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

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

Issue 14230010: [chromedriver] Fix issue of cache id in JS. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Address comment Created 7 years, 8 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 | Annotate | Revision Log
« no previous file with comments | « no previous file | chrome/test/chromedriver/js/call_function_test.html » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 17 matching lines...) Expand all
28 var ELEMENT_KEY = 'ELEMENT'; 28 var ELEMENT_KEY = 'ELEMENT';
29 29
30 /** 30 /**
31 * A cache which maps IDs <-> cached objects for the purpose of identifying 31 * A cache which maps IDs <-> cached objects for the purpose of identifying
32 * a script object remotely. 32 * a script object remotely.
33 * @constructor 33 * @constructor
34 */ 34 */
35 function Cache() { 35 function Cache() {
36 this.cache_ = {}; 36 this.cache_ = {};
37 this.nextId_ = 1; 37 this.nextId_ = 1;
38 this.idPrefix_ = Math.random().toString();
38 } 39 }
39 40
40 Cache.prototype = { 41 Cache.prototype = {
41 42
42 /** 43 /**
43 * Stores a given item in the cache and returns a unique ID. 44 * Stores a given item in the cache and returns a unique ID.
44 * 45 *
45 * @param {!Object} item The item to store in the cache. 46 * @param {!Object} item The item to store in the cache.
46 * @return {number} The ID for the cached item. 47 * @return {number} The ID for the cached item.
47 */ 48 */
48 storeItem_: function(item) { 49 storeItem: function(item) {
49 for (var i in this.cache_) { 50 for (var i in this.cache_) {
50 if (item == this.cache_[i]) 51 if (item == this.cache_[i])
51 return i; 52 return i;
52 } 53 }
53 var id = this.nextId_.toString(); 54 var id = this.idPrefix_ + ':' + this.nextId_;
54 this.cache_[id] = item; 55 this.cache_[id] = item;
55 this.nextId_++; 56 this.nextId_++;
56 return id; 57 return id;
57 }, 58 },
58 59
59 /** 60 /**
60 * Retrieves the cached object for the given ID. 61 * Retrieves the cached object for the given ID.
61 * 62 *
62 * @param {number} id The ID for the cached item to retrieve. 63 * @param {number} id The ID for the cached item to retrieve.
63 * @return {!Object} The retrieved item. 64 * @return {!Object} The retrieved item.
64 */ 65 */
65 retrieveItem_: function(id) { 66 retrieveItem: function(id) {
66 var item = this.cache_[id]; 67 var item = this.cache_[id];
67 if (item) 68 if (item)
68 return item; 69 return item;
69 var error = new Error('not in cache'); 70 var error = new Error('not in cache');
70 error.code = StatusCode.STALE_ELEMENT_REFERENCE; 71 error.code = StatusCode.STALE_ELEMENT_REFERENCE;
71 error.message = 'element is not attached to the page document'; 72 error.message = 'element is not attached to the page document';
72 throw error; 73 throw error;
73 }, 74 },
74 75
75 /** 76 /**
76 * Clears stale items from the cache. 77 * Clears stale items from the cache.
77 */ 78 */
78 clearStale: function() { 79 clearStale: function() {
79 for (var id in this.cache_) { 80 for (var id in this.cache_) {
80 var node = this.cache_[id]; 81 var node = this.cache_[id];
81 while (node) { 82 while (node) {
82 if (node == document) 83 if (node == document)
83 break; 84 break;
84 node = node.parentNode; 85 node = node.parentNode;
85 } 86 }
86 if (!node) 87 if (!node)
87 delete this.cache_[id]; 88 delete this.cache_[id];
88 } 89 }
89 },
90
91 /**
92 * Wraps the given value to be transmitted remotely by converting
93 * appropriate objects to cached object IDs.
94 *
95 * @param {*} value The value to wrap.
96 * @return {*} The wrapped value.
97 */
98 wrap: function(value) {
99 if (typeof(value) == 'object' && value != null) {
100 var nodeType = value['nodeType'];
101 if (nodeType == NodeType.ELEMENT || nodeType == NodeType.DOCUMENT) {
102 var wrapped = {};
103 wrapped[ELEMENT_KEY] = this.storeItem_(value);
104 return wrapped;
105 }
106
107 var obj = (typeof(value.length) == 'number') ? [] : {};
108 for (var prop in value)
109 obj[prop] = this.wrap(value[prop]);
110 return obj;
111 }
112 return value;
113 },
114
115 /**
116 * Unwraps the given value by converting from object IDs to the cached
117 * objects.
118 *
119 * @param {*} value The value to unwrap.
120 * @return {*} The unwrapped value.
121 */
122 unwrap: function(value) {
123 if (typeof(value) == 'object' && value != null) {
124 if (ELEMENT_KEY in value)
125 return this.retrieveItem_(value[ELEMENT_KEY]);
126
127 var obj = (typeof(value.length) == 'number') ? [] : {};
128 for (var prop in value)
129 obj[prop] = this.unwrap(value[prop]);
130 return obj;
131 }
132 return value;
133 } 90 }
134 }; 91 };
135 92
136 /** 93 /**
137 * Returns the global object cache for the page. 94 * Returns the global object cache for the page.
95 * @param {Document=} opt_doc The document whose cache to retrieve. Defaults to
96 * the current document.
138 * @return {!Cache} The page's object cache. 97 * @return {!Cache} The page's object cache.
139 */ 98 */
140 function getPageCache() { 99 function getPageCache(opt_doc) {
100 var doc = opt_doc || document;
141 // We use the same key as selenium's javascript/atoms/inject.js. 101 // We use the same key as selenium's javascript/atoms/inject.js.
142 var key = '$wdc_'; 102 var key = '$wdc_';
143 if (!(key in document)) 103 if (!(key in doc))
144 document[key] = new Cache(); 104 doc[key] = new Cache();
145 return document[key]; 105 return doc[key];
146 } 106 }
147 107
148 /** 108 /**
109 * Wraps the given value to be transmitted remotely by converting
110 * appropriate objects to cached object IDs.
111 *
112 * @param {*} value The value to wrap.
113 * @return {*} The wrapped value.
114 */
115 function wrap(value) {
116 if (typeof(value) == 'object' && value != null) {
117 var nodeType = value['nodeType'];
118 if (nodeType == NodeType.ELEMENT || nodeType == NodeType.DOCUMENT) {
119 var wrapped = {};
120 wrapped[ELEMENT_KEY] = getPageCache(value.ownerDocument).storeItem(value);
121 return wrapped;
122 }
123
124 var obj = (typeof(value.length) == 'number') ? [] : {};
125 for (var prop in value)
126 obj[prop] = wrap(value[prop]);
127 return obj;
128 }
129 return value;
130 }
131
132 /**
133 * Unwraps the given value by converting from object IDs to the cached
134 * objects.
135 *
136 * @param {*} value The value to unwrap.
137 * @param {Cache} cache The cache to retrieve wrapped elements from.
138 * @return {*} The unwrapped value.
139 */
140 function unwrap(value, cache) {
141 if (typeof(value) == 'object' && value != null) {
142 if (ELEMENT_KEY in value)
143 return cache.retrieveItem(value[ELEMENT_KEY]);
144
145 var obj = (typeof(value.length) == 'number') ? [] : {};
146 for (var prop in value)
147 obj[prop] = unwrap(value[prop], cache);
148 return obj;
149 }
150 return value;
151 }
152
153 /**
149 * Calls a given function and returns its value. 154 * Calls a given function and returns its value.
150 * 155 *
151 * The inputs to and outputs of the function will be unwrapped and wrapped 156 * The inputs to and outputs of the function will be unwrapped and wrapped
152 * respectively, unless otherwise specified. This wrapping involves converting 157 * respectively, unless otherwise specified. This wrapping involves converting
153 * between cached object reference IDs and actual JS objects. The cache will 158 * between cached object reference IDs and actual JS objects. The cache will
154 * automatically be pruned each call to remove stale references. 159 * automatically be pruned each call to remove stale references.
155 * 160 *
156 * @param {function(...[*]) : *} func The function to invoke. 161 * @param {function(...[*]) : *} func The function to invoke.
157 * @param {!Array.<*>} args The array of arguments to supply to the function, 162 * @param {!Array.<*>} args The array of arguments to supply to the function,
158 * which will be unwrapped before invoking the function. 163 * which will be unwrapped before invoking the function.
159 * @param {boolean=} opt_unwrappedReturn Whether the function's return value 164 * @param {boolean=} opt_unwrappedReturn Whether the function's return value
160 * should be left unwrapped. 165 * should be left unwrapped.
161 * @return {*} An object containing a status and value property, where status 166 * @return {*} An object containing a status and value property, where status
162 * is a WebDriver status code and value is the wrapped value. If an 167 * is a WebDriver status code and value is the wrapped value. If an
163 * unwrapped return was specified, this will be the function's pure return 168 * unwrapped return was specified, this will be the function's pure return
164 * value. 169 * value.
165 */ 170 */
166 function callFunction(func, args, opt_unwrappedReturn) { 171 function callFunction(func, args, opt_unwrappedReturn) {
167 var cache = getPageCache(); 172 var cache = getPageCache();
168 cache.clearStale(); 173 cache.clearStale();
169 174
170 if (opt_unwrappedReturn) 175 if (opt_unwrappedReturn)
171 return func.apply(null, cache.unwrap(args)); 176 return func.apply(null, unwrap(args, cache));
172 177
173 var status = 0; 178 var status = 0;
174 try { 179 try {
175 var returnValue = cache.wrap(func.apply(null, cache.unwrap(args))); 180 var returnValue = wrap(func.apply(null, unwrap(args, cache)));
176 } catch (error) { 181 } catch (error) {
177 status = error.code || StatusCode.UNKNOWN_ERROR; 182 status = error.code || StatusCode.UNKNOWN_ERROR;
178 var returnValue = error.message; 183 var returnValue = error.message;
179 } 184 }
180 return { 185 return {
181 status: status, 186 status: status,
182 value: returnValue 187 value: returnValue
183 } 188 }
184 } 189 }
OLDNEW
« no previous file with comments | « no previous file | chrome/test/chromedriver/js/call_function_test.html » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698