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

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: Fixed presubmit errors. 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;
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 array = new Uint8Array(16);
51 window.crypto.getRandomValues(array);
52 array[6] = 0x40 | (array[6] & 0x0f);
53 array[8] = 0x80 | (array[8] & 0x3f);
54
55 var UUID = "";
56 for (var i = 0; i < 16; i++) {
57 var temp = array[i].toString(16);
58 if (temp.length < 2)
59 temp = "0" + temp;
60 UUID += temp;
61 if (i == 3 || i == 5 || i == 7 || i == 9)
62 UUID += "-";
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 78 matching lines...) Expand 10 before | Expand all | Expand 10 after
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.
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;
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 }
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 25 matching lines...) Expand all
202 * The inputs to and outputs of the function will be unwrapped and wrapped 305 * The inputs to and outputs of the function will be unwrapped and wrapped
203 * respectively, unless otherwise specified. This wrapping involves converting 306 * respectively, unless otherwise specified. This wrapping involves converting
204 * between cached object reference IDs and actual JS objects. The cache will 307 * between cached object reference IDs and actual JS objects. The cache will
205 * automatically be pruned each call to remove stale references. 308 * automatically be pruned each call to remove stale references.
206 * 309 *
207 * @param {Array<string>} shadowHostIds The host ids of the nested shadow 310 * @param {Array<string>} shadowHostIds The host ids of the nested shadow
208 * DOMs the function should be executed in the context of. 311 * DOMs the function should be executed in the context of.
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.
315 * @param {boolean} w3c Whether to return a W3C compliant element reference.
212 * @param {boolean=} opt_unwrappedReturn Whether the function's return value 316 * @param {boolean=} opt_unwrappedReturn Whether the function's return value
213 * should be left unwrapped. 317 * should be left unwrapped.
214 * @return {*} An object containing a status and value property, where status 318 * @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 319 * 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 320 * unwrapped return was specified, this will be the function's pure return
217 * value. 321 * value.
218 */ 322 */
219 function callFunction(shadowHostIds, func, args, opt_unwrappedReturn) { 323 function callFunction(shadowHostIds, func, args, w3c, opt_unwrappedReturn) {
220 var cache = getPageCache(); 324 if (w3c) {
325 w3cEnabled = true;
326 ELEMENT_KEY = 'element-6066-11e4-a52e-4f735466cecf';
327
328 }
329 var cache = getPageCache(null, w3cEnabled);
221 cache.clearStale(); 330 cache.clearStale();
222 if (shadowHostIds && SHADOW_DOM_ENABLED) { 331 if (shadowHostIds && SHADOW_DOM_ENABLED) {
223 for (var i = 0; i < shadowHostIds.length; i++) { 332 for (var i = 0; i < shadowHostIds.length; i++) {
224 var host = cache.retrieveItem(shadowHostIds[i]); 333 var host = cache.retrieveItem(shadowHostIds[i]);
225 // TODO(zachconrad): Use the olderShadowRoot API when available to check 334 // TODO(zachconrad): Use the olderShadowRoot API when available to check
226 // all of the shadow roots. 335 // all of the shadow roots.
227 cache = getPageCache(host.webkitShadowRoot); 336 cache = getPageCache(host.webkitShadowRoot, w3cEnabled);
228 cache.clearStale(); 337 cache.clearStale();
229 } 338 }
230 } 339 }
231 340
232 if (opt_unwrappedReturn) 341 if (opt_unwrappedReturn)
233 return func.apply(null, unwrap(args, cache)); 342 return func.apply(null, unwrap(args, cache));
234 343
235 var status = 0; 344 var status = 0;
236 try { 345 try {
237 var returnValue = wrap(func.apply(null, unwrap(args, cache))); 346 var returnValue = wrap(func.apply(null, unwrap(args, cache)));
238 } catch (error) { 347 } catch (error) {
239 status = error.code || StatusCode.UNKNOWN_ERROR; 348 status = error.code || StatusCode.UNKNOWN_ERROR;
240 var returnValue = error.message; 349 var returnValue = error.message;
241 } 350 }
242 return { 351 return {
243 status: status, 352 status: status,
244 value: returnValue 353 value: returnValue
245 } 354 }
246 } 355 }
OLDNEW
« no previous file with comments | « chrome/test/chromedriver/element_util.cc ('k') | chrome/test/chromedriver/js/call_function_test.html » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698