execute_script_test.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350
  1. // Licensed to the Software Freedom Conservancy (SFC) under one
  2. // or more contributor license agreements. See the NOTICE file
  3. // distributed with this work for additional information
  4. // regarding copyright ownership. The SFC licenses this file
  5. // to you under the Apache License, Version 2.0 (the
  6. // "License"); you may not use this file except in compliance
  7. // with the License. You may obtain a copy of the License at
  8. //
  9. // http://www.apache.org/licenses/LICENSE-2.0
  10. //
  11. // Unless required by applicable law or agreed to in writing,
  12. // software distributed under the License is distributed on an
  13. // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  14. // KIND, either express or implied. See the License for the
  15. // specific language governing permissions and limitations
  16. // under the License.
  17. 'use strict';
  18. var fail = require('assert').fail;
  19. var webdriver = require('..'),
  20. Browser = webdriver.Browser,
  21. By = webdriver.By,
  22. assert = require('../testing/assert'),
  23. test = require('../lib/test');
  24. test.suite(function(env) {
  25. var driver;
  26. test.before(function*() {
  27. driver = yield env.builder().build();
  28. });
  29. test.after(function() {
  30. return driver.quit();
  31. });
  32. test.beforeEach(function() {
  33. return driver.get(test.Pages.echoPage);
  34. });
  35. describe('executeScript;', function() {
  36. var shouldHaveFailed = new Error('Should have failed');
  37. test.it('fails if script throws', function() {
  38. return execute('throw new Error("boom")')
  39. .then(function() { throw shouldHaveFailed; })
  40. .catch(function(e) {
  41. // The java WebDriver server adds a bunch of crap to error messages.
  42. // Error message will just be "JavaScript error" for IE.
  43. assert(e.message).matches(/.*(JavaScript error|boom).*/);
  44. });
  45. });
  46. test.it('fails if script does not parse', function() {
  47. return execute('throw function\\*')
  48. .then(function() { throw shouldHaveFailed; })
  49. .catch(function(e) {
  50. assert(e).notEqualTo(shouldHaveFailed);
  51. });
  52. });
  53. describe('scripts;', function() {
  54. test.it('do not pollute the global scope', function*() {
  55. yield execute('var x = 1;');
  56. yield assert(execute('return typeof x;')).equalTo('undefined');
  57. });
  58. test.it('can set global variables', function*() {
  59. yield execute('window.x = 1234;');
  60. yield assert(execute('return x;')).equalTo(1234);
  61. });
  62. test.it('may be defined as a function expression', function*() {
  63. let result = yield execute(function() {
  64. return 1234 + 'abc';
  65. });
  66. assert(result).equalTo('1234abc');
  67. });
  68. });
  69. describe('return values;', function() {
  70. test.it('returns undefined as null', function() {
  71. return assert(execute('var x; return x;')).isNull();
  72. });
  73. test.it('can return null', function() {
  74. return assert(execute('return null;')).isNull();
  75. });
  76. test.it('can return numbers', function*() {
  77. yield assert(execute('return 1234')).equalTo(1234);
  78. yield assert(execute('return 3.1456')).equalTo(3.1456);
  79. });
  80. test.it('can return strings', function() {
  81. return assert(execute('return "hello"')).equalTo('hello');
  82. });
  83. test.it('can return booleans', function*() {
  84. yield assert(execute('return true')).equalTo(true);
  85. yield assert(execute('return false')).equalTo(false);
  86. });
  87. test.it('can return an array of primitives', function() {
  88. return execute('var x; return [1, false, null, 3.14, x]')
  89. .then(verifyJson([1, false, null, 3.14, null]));
  90. });
  91. test.it('can return nested arrays', function() {
  92. return execute('return [[1, 2, [3]]]').then(verifyJson([[1, 2, [3]]]));
  93. });
  94. test.ignore(env.browsers(Browser.IE)).
  95. it('can return empty object literal', function() {
  96. return execute('return {}').then(verifyJson({}));
  97. });
  98. test.it('can return object literals', function() {
  99. return execute('return {a: 1, b: false, c: null}').then(result => {
  100. verifyJson(['a', 'b', 'c'])(Object.keys(result).sort());
  101. assert(result.a).equalTo(1);
  102. assert(result.b).equalTo(false);
  103. assert(result.c).isNull();
  104. });
  105. });
  106. test.it('can return complex object literals', function() {
  107. return execute('return {a:{b: "hello"}}')
  108. .then(verifyJson({a:{b: 'hello'}}));
  109. });
  110. test.it('can return dom elements as web elements', function*() {
  111. let result =
  112. yield execute('return document.querySelector(".header.host")');
  113. assert(result).instanceOf(webdriver.WebElement);
  114. return assert(result.getText()).startsWith('host: ');
  115. });
  116. test.it('can return array of dom elements', function*() {
  117. let result = yield execute(
  118. 'var nodes = document.querySelectorAll(".request,.host");' +
  119. 'return [nodes[0], nodes[1]];');
  120. assert(result.length).equalTo(2);
  121. assert(result[0]).instanceOf(webdriver.WebElement);
  122. yield assert(result[0].getText()).startsWith('GET ');
  123. assert(result[1]).instanceOf(webdriver.WebElement);
  124. yield assert(result[1].getText()).startsWith('host: ');
  125. });
  126. test.it('can return a NodeList as an array of web elements', function*() {
  127. let result =
  128. yield execute('return document.querySelectorAll(".request,.host");')
  129. assert(result.length).equalTo(2);
  130. assert(result[0]).instanceOf(webdriver.WebElement);
  131. yield assert(result[0].getText()).startsWith('GET ');
  132. assert(result[1]).instanceOf(webdriver.WebElement);
  133. yield assert(result[1].getText()).startsWith('host: ');
  134. });
  135. test.it('can return object literal with element property', function*() {
  136. let result = yield execute('return {a: document.body}');
  137. assert(result.a).instanceOf(webdriver.WebElement);
  138. yield assert(result.a.getTagName()).equalTo('body');
  139. });
  140. });
  141. describe('parameters;', function() {
  142. test.it('can pass numeric arguments', function*() {
  143. yield assert(execute('return arguments[0]', 12)).equalTo(12);
  144. yield assert(execute('return arguments[0]', 3.14)).equalTo(3.14);
  145. });
  146. test.it('can pass boolean arguments', function*() {
  147. yield assert(execute('return arguments[0]', true)).equalTo(true);
  148. yield assert(execute('return arguments[0]', false)).equalTo(false);
  149. });
  150. test.it('can pass string arguments', function*() {
  151. yield assert(execute('return arguments[0]', 'hi')).equalTo('hi');
  152. });
  153. test.it('can pass null arguments', function*() {
  154. yield assert(execute('return arguments[0] === null', null)).equalTo(true);
  155. yield assert(execute('return arguments[0]', null)).equalTo(null);
  156. });
  157. test.it('passes undefined as a null argument', function*() {
  158. var x;
  159. yield assert(execute('return arguments[0] === null', x)).equalTo(true);
  160. yield assert(execute('return arguments[0]', x)).equalTo(null);
  161. });
  162. test.it('can pass multiple arguments', function*() {
  163. yield assert(execute('return arguments.length')).equalTo(0);
  164. yield assert(execute('return arguments.length', 1, 'a', false)).equalTo(3);
  165. });
  166. test.ignore(env.browsers(Browser.FIREFOX, Browser.SAFARI)).
  167. it('can return arguments object as array', function*() {
  168. let val = yield execute('return arguments', 1, 'a', false);
  169. assert(val.length).equalTo(3);
  170. assert(val[0]).equalTo(1);
  171. assert(val[1]).equalTo('a');
  172. assert(val[2]).equalTo(false);
  173. });
  174. test.it('can pass object literal', function*() {
  175. let result = yield execute(
  176. 'return [typeof arguments[0], arguments[0].a]', {a: 'hello'})
  177. assert(result[0]).equalTo('object');
  178. assert(result[1]).equalTo('hello');
  179. });
  180. test.it('WebElement arguments are passed as DOM elements', function*() {
  181. let el = yield driver.findElement(By.tagName('div'));
  182. let result =
  183. yield execute('return arguments[0].tagName.toLowerCase();', el);
  184. assert(result).equalTo('div');
  185. });
  186. test.it('can pass array containing object literals', function*() {
  187. let result = yield execute('return arguments[0]', [{color: "red"}]);
  188. assert(result.length).equalTo(1);
  189. assert(result[0].color).equalTo('red');
  190. });
  191. test.it('does not modify object literal parameters', function() {
  192. var input = {color: 'red'};
  193. return execute('return arguments[0];', input).then(verifyJson(input));
  194. });
  195. });
  196. // See https://code.google.com/p/selenium/issues/detail?id=8223.
  197. describe('issue 8223;', function() {
  198. describe('using for..in loops;', function() {
  199. test.it('can return array built from for-loop index', function() {
  200. return execute(function() {
  201. var ret = [];
  202. for (var i = 0; i < 3; i++) {
  203. ret.push(i);
  204. }
  205. return ret;
  206. }).then(verifyJson[0, 1, 2]);
  207. });
  208. test.it('can copy input array contents', function() {
  209. return execute(function(input) {
  210. var ret = [];
  211. for (var i in input) {
  212. ret.push(input[i]);
  213. }
  214. return ret;
  215. }, ['fa', 'fe', 'fi']).then(verifyJson(['fa', 'fe', 'fi']));
  216. });
  217. test.it('can iterate over input object keys', function() {
  218. return execute(function(thing) {
  219. var ret = [];
  220. for (var w in thing.words) {
  221. ret.push(thing.words[w].word);
  222. }
  223. return ret;
  224. }, {words: [{word: 'fa'}, {word: 'fe'}, {word: 'fi'}]})
  225. .then(verifyJson(['fa', 'fe', 'fi']));
  226. });
  227. describe('recursive functions;', function() {
  228. test.it('can build array from input', function() {
  229. var input = ['fa', 'fe', 'fi'];
  230. return execute(function(thearray) {
  231. var ret = [];
  232. function build_response(thearray, ret) {
  233. ret.push(thearray.shift());
  234. return (!thearray.length && ret
  235. || build_response(thearray, ret));
  236. }
  237. return build_response(thearray, ret);
  238. }, input).then(verifyJson(input));
  239. });
  240. test.it('can build array from elements in object', function() {
  241. var input = {words: [{word: 'fa'}, {word: 'fe'}, {word: 'fi'}]};
  242. return execute(function(thing) {
  243. var ret = [];
  244. function build_response(thing, ret) {
  245. var item = thing.words.shift();
  246. ret.push(item.word);
  247. return (!thing.words.length && ret
  248. || build_response(thing, ret));
  249. }
  250. return build_response(thing, ret);
  251. }, input).then(verifyJson(['fa', 'fe', 'fi']));
  252. });
  253. });
  254. });
  255. });
  256. describe('async timeouts', function() {
  257. var TIMEOUT_IN_MS = 200;
  258. var ACCEPTABLE_WAIT = TIMEOUT_IN_MS / 10;
  259. var TOO_LONG_WAIT = TIMEOUT_IN_MS * 10;
  260. before(function() {
  261. return driver.manage().timeouts().setScriptTimeout(TIMEOUT_IN_MS)
  262. });
  263. test.it('does not fail if script execute in time', function() {
  264. return executeTimeOutScript(ACCEPTABLE_WAIT);
  265. });
  266. test.it('fails if script took too long', function() {
  267. return executeTimeOutScript(TOO_LONG_WAIT)
  268. .then(function() {
  269. fail('it should have timed out');
  270. }).catch(function(e) {
  271. assert(e.name).equalTo('ScriptTimeoutError');
  272. });
  273. });
  274. function executeTimeOutScript(sleepTime) {
  275. return driver.executeAsyncScript(function(sleepTime) {
  276. var callback = arguments[arguments.length - 1];
  277. setTimeout(callback, sleepTime)
  278. }, sleepTime);
  279. }
  280. })
  281. });
  282. function verifyJson(expected) {
  283. return function(actual) {
  284. return assert(JSON.stringify(actual)).equalTo(JSON.stringify(expected));
  285. };
  286. }
  287. function execute() {
  288. return driver.executeScript.apply(driver, arguments);
  289. }
  290. });