Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(31)

Side by Side Diff: chrome/test/chromedriver/js/call_function.js

Issue 2230053002: [chromedriver] Added option to make element references W3C compliant. Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Rebased code with w3c flag change. Created 4 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 /** 5 /**
6 * Enum for WebDriver status codes. 6 * Enum for WebDriver status codes.
7 * @enum {number} 7 * @enum {number}
8 */ 8 */
9 var StatusCode = { 9 var StatusCode = {
10 STALE_ELEMENT_REFERENCE: 10, 10 STALE_ELEMENT_REFERENCE: 10,
(...skipping 10 matching lines...) Expand all
21 }; 21 };
22 22
23 /** 23 /**
24 * Dictionary key to use for holding an element ID. 24 * Dictionary key to use for holding an element ID.
25 * @const 25 * @const
26 * @type {string} 26 * @type {string}
27 */ 27 */
28 var ELEMENT_KEY = 'ELEMENT'; 28 var ELEMENT_KEY = 'ELEMENT';
29 29
30 /** 30 /**
31 * True if using W3C Element references.
32 * @const
33 * @type {boolean}
34 */
35 var w3cEnabled = false;
samuong 2016/08/11 20:45:14 if you're going to have this here, is there a need
36
37 /**
31 * True if shadow dom is enabled. 38 * True if shadow dom is enabled.
32 * @const 39 * @const
33 * @type {boolean} 40 * @type {boolean}
34 */ 41 */
35 var SHADOW_DOM_ENABLED = typeof ShadowRoot === 'function'; 42 var SHADOW_DOM_ENABLED = typeof ShadowRoot === 'function';
36 43
37 /** 44 /**
45 * Generates a unique ID to identify an element.
46 * @void
47 * @return {string} Randomly generated ID.
48 */
49 function generateUUID() {
50 var UUID = "";
51 for (var i = 0; i < 16; i++) {
52 if (i == 6 || i == 12 || i == 14 || i == 15) {
53 UUID += "00";
54 } else if (i == 7 || i == 13) {
55 UUID += "01";
samuong 2016/08/11 20:45:14 If I'm reading https://tools.ietf.org/html/rfc4122
56 } else {
57 var rand = Math.round(Math.random() * 225).toString(16);
samuong 2016/08/11 20:45:14 Let's use window.crypto.getRandomValues() instead
58 UUID += rand;
59 }
60 if (i == 3 || i == 5 || i == 7 || i == 9) {
61 UUID += "-";
62 }
63 }
64 return UUID;
65 };
66
67 /**
68 * A cache which maps IDs <-> cached objects for the purpose of identifying
69 * a script object remotely. Uses UUIDs for identification.
70 * @constructor
71 */
72 function CacheWithUUID() {
73 this.cache_ = {};
74 }
75
76 CacheWithUUID.prototype = {
77 /**
78 * Stores a given item in the cache and returns a unique UUID.
79 *
80 * @param {!Object} item The item to store in the cache.
81 * @return {number} The UUID for the cached item.
82 */
83 storeItem: function(item) {
84 for (var i in this.cache_) {
85 if (item == this.cache_[i])
86 return i;
87 }
88 var id = generateUUID();
89 this.cache_[id] = item;
90 return id;
91 },
92
93 /**
94 * Retrieves the cached object for the given ID.
95 *
96 * @param {number} id The ID for the cached item to retrieve.
97 * @return {!Object} The retrieved item.
98 */
99 retrieveItem: function(id) {
100 var item = this.cache_[id];
101 if (item)
102 return item;
103 var error = new Error('not in cache');
104 error.code = StatusCode.STALE_ELEMENT_REFERENCE;
105 error.message = 'element is not attached to the page document';
106 throw error;
107 },
108
109 /**
110 * Clears stale items from the cache.
111 */
112 clearStale: function() {
113 for (var id in this.cache_) {
114 var node = this.cache_[id];
115 if (!this.isNodeReachable_(node))
116 delete this.cache_[id];
117 }
118 },
119
120 /**
121 * @private
122 * @param {!Node} node The node to check.
123 * @return {boolean} If the nodes is reachable.
124 */
125 isNodeReachable_: function(node) {
126 var nodeRoot = getNodeRootThroughAnyShadows(node);
127 return (nodeRoot == document);
128 }
129
130
131 };
132
133 /**
38 * A cache which maps IDs <-> cached objects for the purpose of identifying 134 * A cache which maps IDs <-> cached objects for the purpose of identifying
39 * a script object remotely. 135 * a script object remotely.
40 * @constructor 136 * @constructor
41 */ 137 */
42 function Cache() { 138 function Cache() {
43 this.cache_ = {}; 139 this.cache_ = {};
44 this.nextId_ = 1; 140 this.nextId_ = 1;
45 this.idPrefix_ = Math.random().toString(); 141 this.idPrefix_ = Math.random().toString();
46 } 142 }
47 143
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after
121 */ 217 */
122 function getNodeRootThroughAnyShadows(node) { 218 function getNodeRootThroughAnyShadows(node) {
123 var root = getNodeRoot(node); 219 var root = getNodeRoot(node);
124 while (SHADOW_DOM_ENABLED && root instanceof ShadowRoot) { 220 while (SHADOW_DOM_ENABLED && root instanceof ShadowRoot) {
125 root = getNodeRoot(root.host); 221 root = getNodeRoot(root.host);
126 } 222 }
127 return root; 223 return root;
128 } 224 }
129 225
130 /** 226 /**
131 * Returns the global object cache for the page. 227 * Returns the global object cache for the page.
samuong 2016/08/11 20:45:14 don't forget to add a comment here for the w3c arg
132 * @param {Document=} opt_doc The document whose cache to retrieve. Defaults to 228 * @param {Document=} opt_doc The document whose cache to retrieve. Defaults to
133 * the current document. 229 * the current document.
134 * @return {!Cache} The page's object cache. 230 * @return {!Cache} The page's object cache.
135 */ 231 */
136 function getPageCache(opt_doc) { 232 function getPageCache(opt_doc, opt_w3c) {
137 var doc = opt_doc || document; 233 var doc = opt_doc || document;
234 var w3c = opt_w3c || false;
samuong 2016/08/11 20:45:14 is there ever a case where we don't pass a value f
roisinmcl 2016/08/13 01:47:26 Done.
138 var key = '$cdc_asdjflasutopfhvcZLmcfl_'; 235 var key = '$cdc_asdjflasutopfhvcZLmcfl_';
139 if (!(key in doc)) 236 if (w3c) {
140 doc[key] = new Cache(); 237 if (!(key in doc))
141 return doc[key]; 238 doc[key] = new CacheWithUUID();
239 return doc[key];
240 } else {
241 if (!(key in doc))
242 doc[key] = new Cache();
243 return doc[key];
244 }
samuong 2016/08/11 20:45:14 if you make the "if (w3c)" check the inner conditi
roisinmcl 2016/08/13 01:47:26 Done.
142 } 245 }
143 246
144 /** 247 /**
145 * Wraps the given value to be transmitted remotely by converting 248 * Wraps the given value to be transmitted remotely by converting
146 * appropriate objects to cached object IDs. 249 * appropriate objects to cached object IDs.
147 * 250 *
148 * @param {*} value The value to wrap. 251 * @param {*} value The value to wrap.
149 * @return {*} The wrapped value. 252 * @return {*} The wrapped value.
150 */ 253 */
151 function wrap(value) { 254 function wrap(value) {
152 // As of crrev.com/1316933002, typeof() for some elements will return 255 // As of crrev.com/1316933002, typeof() for some elements will return
153 // 'function', not 'object'. So we need to check for both non-null objects, as 256 // 'function', not 'object'. So we need to check for both non-null objects, as
154 // well Elements that also happen to be callable functions (e.g. <embed> and 257 // well Elements that also happen to be callable functions (e.g. <embed> and
155 // <object> elements). Note that we can not use |value instanceof Object| here 258 // <object> elements). Note that we can not use |value instanceof Object| here
156 // since this does not work with frames/iframes, for example 259 // since this does not work with frames/iframes, for example
157 // frames[0].document.body instanceof Object == false even though 260 // frames[0].document.body instanceof Object == false even though
158 // typeof(frames[0].document.body) == 'object'. 261 // typeof(frames[0].document.body) == 'object'.
159 if ((typeof(value) == 'object' && value != null) || 262 if ((typeof(value) == 'object' && value != null) ||
160 (typeof(value) == 'function' && value instanceof Element)) { 263 (typeof(value) == 'function' && value instanceof Element)) {
161 var nodeType = value['nodeType']; 264 var nodeType = value['nodeType'];
162 if (nodeType == NodeType.ELEMENT || nodeType == NodeType.DOCUMENT 265 if (nodeType == NodeType.ELEMENT || nodeType == NodeType.DOCUMENT
163 || (SHADOW_DOM_ENABLED && value instanceof ShadowRoot)) { 266 || (SHADOW_DOM_ENABLED && value instanceof ShadowRoot)) {
164 var wrapped = {}; 267 var wrapped = {};
165 var root = getNodeRootThroughAnyShadows(value); 268 var root = getNodeRootThroughAnyShadows(value);
166 wrapped[ELEMENT_KEY] = getPageCache(root).storeItem(value); 269 wrapped[ELEMENT_KEY] = getPageCache(root, w3cEnabled).storeItem(value);
167 return wrapped; 270 return wrapped;
168 } 271 }
169 272
170 var obj = (typeof(value.length) == 'number') ? [] : {}; 273 var obj = (typeof(value.length) == 'number') ? [] : {};
171 for (var prop in value) 274 for (var prop in value)
172 obj[prop] = wrap(value[prop]); 275 obj[prop] = wrap(value[prop]);
173 return obj; 276 return obj;
174 } 277 }
175 return value; 278 return value;
176 } 279 }
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
209 * @param {function(...[*]) : *} func The function to invoke. 312 * @param {function(...[*]) : *} func The function to invoke.
210 * @param {!Array<*>} args The array of arguments to supply to the function, 313 * @param {!Array<*>} args The array of arguments to supply to the function,
211 * which will be unwrapped before invoking the function. 314 * which will be unwrapped before invoking the function.
212 * @param {boolean=} opt_unwrappedReturn Whether the function's return value 315 * @param {boolean=} opt_unwrappedReturn Whether the function's return value
213 * should be left unwrapped. 316 * should be left unwrapped.
214 * @return {*} An object containing a status and value property, where status 317 * @return {*} An object containing a status and value property, where status
215 * is a WebDriver status code and value is the wrapped value. If an 318 * is a WebDriver status code and value is the wrapped value. If an
216 * unwrapped return was specified, this will be the function's pure return 319 * unwrapped return was specified, this will be the function's pure return
217 * value. 320 * value.
218 */ 321 */
219 function callFunction(shadowHostIds, func, args, opt_unwrappedReturn) { 322 function callFunction(shadowHostIds, func, args, w3c, opt_unwrappedReturn) {
220 var cache = getPageCache(); 323 if (w3c) {
324 w3cEnabled = true;
325 ELEMENT_KEY = 'element-6066-11e4-a52e-4f735466cecf';
326
327 }
328 var cache = getPageCache(null, w3cEnabled);
221 cache.clearStale(); 329 cache.clearStale();
222 if (shadowHostIds && SHADOW_DOM_ENABLED) { 330 if (shadowHostIds && SHADOW_DOM_ENABLED) {
223 for (var i = 0; i < shadowHostIds.length; i++) { 331 for (var i = 0; i < shadowHostIds.length; i++) {
224 var host = cache.retrieveItem(shadowHostIds[i]); 332 var host = cache.retrieveItem(shadowHostIds[i]);
225 // TODO(zachconrad): Use the olderShadowRoot API when available to check 333 // TODO(zachconrad): Use the olderShadowRoot API when available to check
226 // all of the shadow roots. 334 // all of the shadow roots.
227 cache = getPageCache(host.webkitShadowRoot); 335 cache = getPageCache(host.webkitShadowRoot, w3cEnabled);
228 cache.clearStale(); 336 cache.clearStale();
229 } 337 }
230 } 338 }
231 339
232 if (opt_unwrappedReturn) 340 if (opt_unwrappedReturn)
233 return func.apply(null, unwrap(args, cache)); 341 return func.apply(null, unwrap(args, cache));
234 342
235 var status = 0; 343 var status = 0;
236 try { 344 try {
237 var returnValue = wrap(func.apply(null, unwrap(args, cache))); 345 var returnValue = wrap(func.apply(null, unwrap(args, cache)));
238 } catch (error) { 346 } catch (error) {
239 status = error.code || StatusCode.UNKNOWN_ERROR; 347 status = error.code || StatusCode.UNKNOWN_ERROR;
240 var returnValue = error.message; 348 var returnValue = error.message;
241 } 349 }
242 return { 350 return {
243 status: status, 351 status: status,
244 value: returnValue 352 value: returnValue
245 } 353 }
246 } 354 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698