webdriver_test.js 73 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311
  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. const testutil = require('./testutil');
  19. const By = require('../../lib/by').By;
  20. const Capabilities = require('../../lib/capabilities').Capabilities;
  21. const Executor = require('../../lib/command').Executor;
  22. const CName = require('../../lib/command').Name;
  23. const error = require('../../lib/error');
  24. const Button = require('../../lib/input').Button;
  25. const Key = require('../../lib/input').Key;
  26. const logging = require('../../lib/logging');
  27. const Session = require('../../lib/session').Session;
  28. const promise = require('../../lib/promise');
  29. const {enablePromiseManager, promiseManagerSuite} = require('../../lib/test/promise');
  30. const until = require('../../lib/until');
  31. const Alert = require('../../lib/webdriver').Alert;
  32. const AlertPromise = require('../../lib/webdriver').AlertPromise;
  33. const UnhandledAlertError = require('../../lib/webdriver').UnhandledAlertError;
  34. const WebDriver = require('../../lib/webdriver').WebDriver;
  35. const WebElement = require('../../lib/webdriver').WebElement;
  36. const WebElementPromise = require('../../lib/webdriver').WebElementPromise;
  37. const assert = require('assert');
  38. const sinon = require('sinon');
  39. const SESSION_ID = 'test_session_id';
  40. // Aliases for readability.
  41. const NativePromise = Promise;
  42. const StubError = testutil.StubError;
  43. const assertIsInstance = testutil.assertIsInstance;
  44. const assertIsStubError = testutil.assertIsStubError;
  45. const throwStubError = testutil.throwStubError;
  46. const fail = (msg) => assert.fail(msg);
  47. describe('WebDriver', function() {
  48. const LOG = logging.getLogger('webdriver.test');
  49. // before(function() {
  50. // logging.getLogger('webdriver').setLevel(logging.Level.ALL);
  51. // logging.installConsoleHandler();
  52. // });
  53. // after(function() {
  54. // logging.getLogger('webdriver').setLevel(null);
  55. // logging.removeConsoleHandler();
  56. // });
  57. var driver;
  58. var flow;
  59. var uncaughtExceptions;
  60. beforeEach(function setUp() {
  61. flow = promise.controlFlow();
  62. uncaughtExceptions = [];
  63. flow.on('uncaughtException', onUncaughtException);
  64. });
  65. afterEach(function tearDown() {
  66. if (!promise.USE_PROMISE_MANAGER) {
  67. return;
  68. }
  69. return waitForIdle(flow).then(function() {
  70. assert.deepEqual([], uncaughtExceptions);
  71. flow.reset();
  72. });
  73. });
  74. function onUncaughtException(e) {
  75. uncaughtExceptions.push(e);
  76. }
  77. function defer() {
  78. let d = {};
  79. let promise = new Promise((resolve, reject) => {
  80. Object.assign(d, {resolve, reject});
  81. });
  82. d.promise = promise;
  83. return d;
  84. }
  85. function waitForIdle(opt_flow) {
  86. if (!promise.USE_PROMISE_MANAGER) {
  87. return Promise.resolve();
  88. }
  89. var theFlow = opt_flow || flow;
  90. return new Promise(function(fulfill, reject) {
  91. if (theFlow.isIdle()) {
  92. fulfill();
  93. return;
  94. }
  95. theFlow.once('idle', fulfill);
  96. theFlow.once('uncaughtException', reject);
  97. });
  98. }
  99. function waitForAbort(opt_flow, opt_n) {
  100. var n = opt_n || 1;
  101. var theFlow = opt_flow || flow;
  102. theFlow.removeAllListeners(
  103. promise.ControlFlow.EventType.UNCAUGHT_EXCEPTION);
  104. return new Promise(function(fulfill, reject) {
  105. theFlow.once('idle', function() {
  106. reject(Error('expected flow to report an unhandled error'));
  107. });
  108. var errors = [];
  109. theFlow.on('uncaughtException', onError);
  110. function onError(e) {
  111. errors.push(e);
  112. if (errors.length === n) {
  113. theFlow.removeListener('uncaughtException', onError);
  114. fulfill(n === 1 ? errors[0] : errors);
  115. }
  116. }
  117. });
  118. }
  119. function expectedError(ctor, message) {
  120. return function(e) {
  121. assertIsInstance(ctor, e);
  122. assert.equal(message, e.message);
  123. };
  124. }
  125. class Expectation {
  126. constructor(executor, name, opt_parameters) {
  127. this.executor_ = executor;
  128. this.name_ = name;
  129. this.times_ = 1;
  130. this.sessionId_ = SESSION_ID;
  131. this.check_ = null;
  132. this.toDo_ = null;
  133. this.withParameters(opt_parameters || {});
  134. }
  135. anyTimes() {
  136. this.times_ = Infinity;
  137. return this;
  138. }
  139. times(n) {
  140. this.times_ = n;
  141. return this;
  142. }
  143. withParameters(parameters) {
  144. this.parameters_ = parameters;
  145. if (this.name_ !== CName.NEW_SESSION) {
  146. this.parameters_['sessionId'] = this.sessionId_;
  147. }
  148. return this;
  149. }
  150. andReturn(code, opt_value) {
  151. this.toDo_ = function(command) {
  152. LOG.info('executing ' + command.getName() + '; returning ' + code);
  153. return Promise.resolve(opt_value !== void(0) ? opt_value : null);
  154. };
  155. return this;
  156. }
  157. andReturnSuccess(opt_value) {
  158. this.toDo_ = function(command) {
  159. LOG.info('executing ' + command.getName() + '; returning success');
  160. return Promise.resolve(opt_value !== void(0) ? opt_value : null);
  161. };
  162. return this;
  163. }
  164. andReturnError(error) {
  165. if (typeof error === 'number') {
  166. throw Error('need error type');
  167. }
  168. this.toDo_ = function(command) {
  169. LOG.info('executing ' + command.getName() + '; returning failure');
  170. return Promise.reject(error);
  171. };
  172. return this;
  173. }
  174. expect(name, opt_parameters) {
  175. this.end();
  176. return this.executor_.expect(name, opt_parameters);
  177. }
  178. end() {
  179. if (!this.toDo_) {
  180. this.andReturnSuccess(null);
  181. }
  182. return this.executor_;
  183. }
  184. execute(command) {
  185. assert.deepEqual(this.parameters_, command.getParameters());
  186. return this.toDo_(command);
  187. }
  188. }
  189. class FakeExecutor {
  190. constructor() {
  191. this.commands_ = new Map;
  192. }
  193. execute(command) {
  194. let expectations = this.commands_.get(command.getName());
  195. if (!expectations || !expectations.length) {
  196. assert.fail('unexpected command: ' + command.getName());
  197. return;
  198. }
  199. let next = expectations[0];
  200. let result = next.execute(command);
  201. if (next.times_ != Infinity) {
  202. next.times_ -= 1;
  203. if (!next.times_) {
  204. expectations.shift();
  205. }
  206. }
  207. return result;
  208. }
  209. expect(commandName, opt_parameters) {
  210. if (!this.commands_.has(commandName)) {
  211. this.commands_.set(commandName, []);
  212. }
  213. let e = new Expectation(this, commandName, opt_parameters);
  214. this.commands_.get(commandName).push(e);
  215. return e;
  216. }
  217. createDriver(opt_session) {
  218. let session = opt_session || new Session(SESSION_ID, {});
  219. return new WebDriver(session, this);
  220. }
  221. }
  222. /////////////////////////////////////////////////////////////////////////////
  223. //
  224. // Tests
  225. //
  226. /////////////////////////////////////////////////////////////////////////////
  227. describe('testAttachToSession', function() {
  228. it('sessionIsAvailable', function() {
  229. let aSession = new Session(SESSION_ID, {'browserName': 'firefox'});
  230. let executor = new FakeExecutor().
  231. expect(CName.DESCRIBE_SESSION).
  232. withParameters({'sessionId': SESSION_ID}).
  233. andReturnSuccess(aSession).
  234. end();
  235. let driver = WebDriver.attachToSession(executor, SESSION_ID);
  236. return driver.getSession().then(v => assert.strictEqual(v, aSession));
  237. });
  238. it('failsToGetSessionInfo', function() {
  239. let e = new Error('boom');
  240. let executor = new FakeExecutor().
  241. expect(CName.DESCRIBE_SESSION).
  242. withParameters({'sessionId': SESSION_ID}).
  243. andReturnError(e).
  244. end();
  245. let driver = WebDriver.attachToSession(executor, SESSION_ID);
  246. return driver.getSession()
  247. .then(() => assert.fail('should have failed!'),
  248. (actual) => assert.strictEqual(actual, e));
  249. });
  250. it('remote end does not recognize DESCRIBE_SESSION command', function() {
  251. let e = new error.UnknownCommandError;
  252. let executor = new FakeExecutor().
  253. expect(CName.DESCRIBE_SESSION).
  254. withParameters({'sessionId': SESSION_ID}).
  255. andReturnError(e).
  256. end();
  257. let driver = WebDriver.attachToSession(executor, SESSION_ID);
  258. return driver.getSession().then(session => {
  259. assert.ok(session instanceof Session);
  260. assert.strictEqual(session.getId(), SESSION_ID);
  261. assert.equal(session.getCapabilities().size, 0);
  262. });
  263. });
  264. it('usesActiveFlowByDefault', function() {
  265. let executor = new FakeExecutor().
  266. expect(CName.DESCRIBE_SESSION).
  267. withParameters({'sessionId': SESSION_ID}).
  268. andReturnSuccess({}).
  269. end();
  270. var driver = WebDriver.attachToSession(executor, SESSION_ID);
  271. assert.equal(driver.controlFlow(), promise.controlFlow());
  272. return waitForIdle(driver.controlFlow());
  273. });
  274. enablePromiseManager(() => {
  275. it('canAttachInCustomFlow', function() {
  276. let executor = new FakeExecutor().
  277. expect(CName.DESCRIBE_SESSION).
  278. withParameters({'sessionId': SESSION_ID}).
  279. andReturnSuccess({}).
  280. end();
  281. var otherFlow = new promise.ControlFlow();
  282. var driver = WebDriver.attachToSession(executor, SESSION_ID, otherFlow);
  283. assert.equal(otherFlow, driver.controlFlow());
  284. assert.notEqual(otherFlow, promise.controlFlow());
  285. return waitForIdle(otherFlow);
  286. });
  287. });
  288. });
  289. describe('testCreateSession', function() {
  290. it('happyPathWithCapabilitiesHashObject', function() {
  291. let aSession = new Session(SESSION_ID, {'browserName': 'firefox'});
  292. let executor = new FakeExecutor().
  293. expect(CName.NEW_SESSION).
  294. withParameters({
  295. 'desiredCapabilities': {'browserName': 'firefox'}
  296. }).
  297. andReturnSuccess(aSession).
  298. end();
  299. var driver = WebDriver.createSession(executor, {
  300. 'browserName': 'firefox'
  301. });
  302. return driver.getSession().then(v => assert.strictEqual(v, aSession));
  303. });
  304. it('happyPathWithCapabilitiesInstance', function() {
  305. let aSession = new Session(SESSION_ID, {'browserName': 'firefox'});
  306. let executor = new FakeExecutor().
  307. expect(CName.NEW_SESSION).
  308. withParameters({'desiredCapabilities': {'browserName': 'firefox'}}).
  309. andReturnSuccess(aSession).
  310. end();
  311. var driver = WebDriver.createSession(executor, Capabilities.firefox());
  312. return driver.getSession().then(v => assert.strictEqual(v, aSession));
  313. });
  314. it('handles desired and required capabilities', function() {
  315. let aSession = new Session(SESSION_ID, {'browserName': 'firefox'});
  316. let executor = new FakeExecutor().
  317. expect(CName.NEW_SESSION).
  318. withParameters({
  319. 'desiredCapabilities': {'foo': 'bar'},
  320. 'requiredCapabilities': {'bim': 'baz'}
  321. }).
  322. andReturnSuccess(aSession).
  323. end();
  324. let desired = new Capabilities().set('foo', 'bar');
  325. let required = new Capabilities().set('bim', 'baz');
  326. var driver = WebDriver.createSession(executor, {desired, required});
  327. return driver.getSession().then(v => assert.strictEqual(v, aSession));
  328. });
  329. it('failsToCreateSession', function() {
  330. let executor = new FakeExecutor().
  331. expect(CName.NEW_SESSION).
  332. withParameters({'desiredCapabilities': {'browserName': 'firefox'}}).
  333. andReturnError(new StubError()).
  334. end();
  335. var driver =
  336. WebDriver.createSession(executor, {'browserName': 'firefox'});
  337. return driver.getSession().then(fail, assertIsStubError);
  338. });
  339. it('invokes quit callback if it fails to create a session', function() {
  340. let called = false;
  341. let executor = new FakeExecutor()
  342. .expect(CName.NEW_SESSION)
  343. .withParameters({'desiredCapabilities': {'browserName': 'firefox'}})
  344. .andReturnError(new StubError())
  345. .end();
  346. var driver =
  347. WebDriver.createSession(executor, {'browserName': 'firefox'},
  348. null, () => called = true);
  349. return driver.getSession().then(fail, err => {
  350. assert.ok(called);
  351. assertIsStubError(err);
  352. });
  353. });
  354. it('usesActiveFlowByDefault', function() {
  355. let executor = new FakeExecutor().
  356. expect(CName.NEW_SESSION).
  357. withParameters({'desiredCapabilities': {}}).
  358. andReturnSuccess(new Session(SESSION_ID)).
  359. end();
  360. var driver = WebDriver.createSession(executor, {});
  361. assert.equal(promise.controlFlow(), driver.controlFlow());
  362. return waitForIdle(driver.controlFlow());
  363. });
  364. enablePromiseManager(() => {
  365. it('canCreateInCustomFlow', function() {
  366. let executor = new FakeExecutor().
  367. expect(CName.NEW_SESSION).
  368. withParameters({'desiredCapabilities': {}}).
  369. andReturnSuccess({}).
  370. end();
  371. var otherFlow = new promise.ControlFlow();
  372. var driver = WebDriver.createSession(executor, {}, otherFlow);
  373. assert.equal(otherFlow, driver.controlFlow());
  374. assert.notEqual(otherFlow, promise.controlFlow());
  375. return waitForIdle(otherFlow);
  376. });
  377. describe('creation failures bubble up in control flow', function() {
  378. function runTest(...args) {
  379. let executor = new FakeExecutor()
  380. .expect(CName.NEW_SESSION)
  381. .withParameters({'desiredCapabilities': {'browserName': 'firefox'}})
  382. .andReturnError(new StubError())
  383. .end();
  384. WebDriver.createSession(
  385. executor, {'browserName': 'firefox'}, ...args);
  386. return waitForAbort().then(assertIsStubError);
  387. }
  388. it('no onQuit callback', () => runTest());
  389. it('has onQuit callback', () => runTest(null, null, function() {}));
  390. it('onQuit callback failure suppress creation failure', function() {
  391. let e = new Error('hi!');
  392. let executor = new FakeExecutor()
  393. .expect(CName.NEW_SESSION)
  394. .withParameters({'desiredCapabilities': {'browserName': 'firefox'}})
  395. .andReturnError(new StubError())
  396. .end();
  397. WebDriver.createSession(
  398. executor, {'browserName': 'firefox'}, null, () => {throw e});
  399. return waitForAbort().then(err => assert.strictEqual(err, e));
  400. });
  401. });
  402. });
  403. });
  404. it('testDoesNotExecuteCommandIfSessionDoesNotResolve', function() {
  405. var session = Promise.reject(new StubError);
  406. return new FakeExecutor().createDriver(session)
  407. .getTitle()
  408. .then(_ => assert.fail('should have failed'), assertIsStubError);
  409. });
  410. it('testCommandReturnValuesArePassedToFirstCallback', function() {
  411. let executor = new FakeExecutor().
  412. expect(CName.GET_TITLE).andReturnSuccess('Google Search').
  413. end();
  414. var driver = executor.createDriver();
  415. return driver.getTitle()
  416. .then(title => assert.equal('Google Search', title));
  417. });
  418. it('testStopsCommandExecutionWhenAnErrorOccurs', function() {
  419. let e = new error.NoSuchWindowError('window not found');
  420. let executor = new FakeExecutor().
  421. expect(CName.SWITCH_TO_WINDOW).
  422. withParameters({
  423. 'name': 'foo',
  424. 'handle': 'foo'
  425. }).
  426. andReturnError(e).
  427. end();
  428. let driver = executor.createDriver();
  429. return driver.switchTo().window('foo')
  430. .then(
  431. _ => driver.getTitle(), // mock should blow if this gets executed
  432. v => assert.strictEqual(v, e));
  433. });
  434. it('testCanSuppressCommandFailures', function() {
  435. let e = new error.NoSuchWindowError('window not found');
  436. let executor = new FakeExecutor().
  437. expect(CName.SWITCH_TO_WINDOW).
  438. withParameters({
  439. 'name': 'foo',
  440. 'handle': 'foo'
  441. }).
  442. andReturnError(e).
  443. expect(CName.GET_TITLE).
  444. andReturnSuccess('Google Search').
  445. end();
  446. var driver = executor.createDriver();
  447. driver.switchTo().window('foo')
  448. .catch(v => assert.strictEqual(v, e));
  449. driver.getTitle();
  450. return waitForIdle();
  451. });
  452. it('testErrorsPropagateUpToTheRunningApplication', function() {
  453. let e = new error.NoSuchWindowError('window not found');
  454. let executor = new FakeExecutor().
  455. expect(CName.SWITCH_TO_WINDOW).
  456. withParameters({
  457. 'name': 'foo',
  458. 'handle': 'foo'
  459. }).
  460. andReturnError(e).
  461. end();
  462. return executor.createDriver()
  463. .switchTo().window('foo')
  464. .then(_ => assert.fail(), v => assert.strictEqual(v, e));
  465. });
  466. it('testErrbacksThatReturnErrorsStillSwitchToCallbackChain', function() {
  467. let executor = new FakeExecutor().
  468. expect(CName.SWITCH_TO_WINDOW).
  469. withParameters({
  470. 'name': 'foo',
  471. 'handle': 'foo'
  472. }).
  473. andReturnError(new error.NoSuchWindowError('window not found')).
  474. end();
  475. var driver = executor.createDriver();
  476. return driver.switchTo().window('foo').
  477. catch(function() { return new StubError; });
  478. then(assertIsStubError, () => assert.fail());
  479. });
  480. it('testErrbacksThrownCanOverrideOriginalError', function() {
  481. let executor = new FakeExecutor().
  482. expect(CName.SWITCH_TO_WINDOW, {
  483. 'name': 'foo',
  484. 'handle': 'foo'
  485. }).
  486. andReturnError(new error.NoSuchWindowError('window not found')).
  487. end();
  488. var driver = executor.createDriver();
  489. return driver.switchTo().window('foo')
  490. .catch(throwStubError)
  491. .then(assert.fail, assertIsStubError);
  492. });
  493. it('testReportsErrorWhenExecutingCommandsAfterExecutingAQuit', function() {
  494. let executor = new FakeExecutor().
  495. expect(CName.QUIT).
  496. end();
  497. let verifyError = expectedError(
  498. error.NoSuchSessionError,
  499. 'This driver instance does not have a valid session ID ' +
  500. '(did you call WebDriver.quit()?) and may no longer be used.');
  501. let driver = executor.createDriver();
  502. return driver.quit()
  503. .then(_ => driver.get('http://www.google.com'))
  504. .then(assert.fail, verifyError);
  505. });
  506. it('testCallbackCommandsExecuteBeforeNextCommand', function() {
  507. let executor = new FakeExecutor().
  508. expect(CName.GET_CURRENT_URL).
  509. expect(CName.GET, {'url': 'http://www.google.com'}).
  510. expect(CName.CLOSE).
  511. expect(CName.GET_TITLE).
  512. end();
  513. var driver = executor.createDriver();
  514. driver.getCurrentUrl().then(function() {
  515. driver.get('http://www.google.com').then(function() {
  516. driver.close();
  517. });
  518. });
  519. driver.getTitle();
  520. return waitForIdle();
  521. });
  522. enablePromiseManager(() => {
  523. it('testEachCallbackFrameRunsToCompletionBeforeTheNext', function() {
  524. let executor = new FakeExecutor().
  525. expect(CName.GET_TITLE).
  526. expect(CName.GET_CURRENT_URL).
  527. expect(CName.GET_CURRENT_WINDOW_HANDLE).
  528. expect(CName.CLOSE).
  529. expect(CName.QUIT).
  530. end();
  531. var driver = executor.createDriver();
  532. driver.getTitle().
  533. // Everything in this callback...
  534. then(function() {
  535. driver.getCurrentUrl();
  536. driver.getWindowHandle();
  537. }).
  538. // ...should execute before everything in this callback.
  539. then(function() {
  540. driver.close();
  541. });
  542. // This should execute after everything above
  543. driver.quit();
  544. return waitForIdle();
  545. });
  546. });
  547. describe('returningAPromise', function() {
  548. it('fromACallback', function() {
  549. let executor = new FakeExecutor().
  550. expect(CName.GET_TITLE).
  551. expect(CName.GET_CURRENT_URL).
  552. andReturnSuccess('http://www.google.com').
  553. end();
  554. var driver = executor.createDriver();
  555. return driver.getTitle().
  556. then(function() {
  557. return driver.getCurrentUrl();
  558. }).
  559. then(function(value) {
  560. assert.equal('http://www.google.com', value);
  561. });
  562. });
  563. it('fromAnErrbackSuppressesTheError', function() {
  564. let executor = new FakeExecutor().
  565. expect(CName.SWITCH_TO_WINDOW, {
  566. 'name': 'foo',
  567. 'handle': 'foo'
  568. }).
  569. andReturnError(new StubError()).
  570. expect(CName.GET_CURRENT_URL).
  571. andReturnSuccess('http://www.google.com').
  572. end();
  573. var driver = executor.createDriver();
  574. return driver.switchTo().window('foo').
  575. catch(function(e) {
  576. assertIsStubError(e);
  577. return driver.getCurrentUrl();
  578. }).
  579. then(url => assert.equal('http://www.google.com', url));
  580. });
  581. });
  582. describe('customFunctions', function() {
  583. it('returnsANonPromiseValue', function() {
  584. var driver = new FakeExecutor().createDriver();
  585. return driver.call(() => 'abc123').then(function(value) {
  586. assert.equal('abc123', value);
  587. });
  588. });
  589. enablePromiseManager(() => {
  590. it('executionOrderWithCustomFunctions', function() {
  591. var msg = [];
  592. let executor = new FakeExecutor().
  593. expect(CName.GET_TITLE).andReturnSuccess('cheese ').
  594. expect(CName.GET_CURRENT_URL).andReturnSuccess('tasty').
  595. end();
  596. var driver = executor.createDriver();
  597. var pushMsg = msg.push.bind(msg);
  598. driver.getTitle().then(pushMsg);
  599. driver.call(() => 'is ').then(pushMsg);
  600. driver.getCurrentUrl().then(pushMsg);
  601. driver.call(() => '!').then(pushMsg);
  602. return waitForIdle().then(function() {
  603. assert.equal('cheese is tasty!', msg.join(''));
  604. });
  605. });
  606. });
  607. it('passingArgumentsToACustomFunction', function() {
  608. var add = function(a, b) {
  609. return a + b;
  610. };
  611. var driver = new FakeExecutor().createDriver();
  612. return driver.call(add, null, 1, 2).then(function(value) {
  613. assert.equal(3, value);
  614. });
  615. });
  616. it('passingPromisedArgumentsToACustomFunction', function() {
  617. var promisedArg = Promise.resolve(2);
  618. var add = function(a, b) {
  619. return a + b;
  620. };
  621. var driver = new FakeExecutor().createDriver();
  622. return driver.call(add, null, 1, promisedArg).then(function(value) {
  623. assert.equal(3, value);
  624. });
  625. });
  626. it('passingArgumentsAndScopeToACustomFunction', function() {
  627. function Foo(name) {
  628. this.name = name;
  629. }
  630. Foo.prototype.getName = function() {
  631. return this.name;
  632. };
  633. var foo = new Foo('foo');
  634. var driver = new FakeExecutor().createDriver();
  635. return driver.call(foo.getName, foo).then(function(value) {
  636. assert.equal('foo', value);
  637. });
  638. });
  639. it('customFunctionThrowsAnError', function() {
  640. var driver = new FakeExecutor().createDriver();
  641. return driver.call(throwStubError).then(fail, assertIsStubError);
  642. });
  643. it('customFunctionSchedulesCommands', function() {
  644. let executor = new FakeExecutor().
  645. expect(CName.GET_TITLE).
  646. expect(CName.CLOSE).
  647. expect(CName.QUIT).
  648. end();
  649. var driver = executor.createDriver();
  650. driver.call(function() {
  651. driver.getTitle();
  652. driver.close();
  653. });
  654. driver.quit();
  655. return waitForIdle();
  656. });
  657. it('returnsATaskResultAfterSchedulingAnother', function() {
  658. let executor = new FakeExecutor().
  659. expect(CName.GET_TITLE).
  660. andReturnSuccess('Google Search').
  661. expect(CName.CLOSE).
  662. end();
  663. var driver = executor.createDriver();
  664. return driver.call(function() {
  665. var title = driver.getTitle();
  666. driver.close();
  667. return title;
  668. }).then(function(title) {
  669. assert.equal('Google Search', title);
  670. });
  671. });
  672. it('hasANestedCommandThatFails', function() {
  673. let executor = new FakeExecutor().
  674. expect(CName.SWITCH_TO_WINDOW, {
  675. 'name': 'foo',
  676. 'handle': 'foo'
  677. }).
  678. andReturnError(new StubError()).
  679. end();
  680. var driver = executor.createDriver();
  681. return driver.call(function() {
  682. return driver.switchTo().window('foo');
  683. }).then(fail, assertIsStubError);
  684. });
  685. enablePromiseManager(() => {
  686. it('doesNotCompleteUntilReturnedPromiseIsResolved', function() {
  687. var order = [];
  688. var driver = new FakeExecutor().createDriver();
  689. var d = promise.defer();
  690. d.promise.then(function() {
  691. order.push('b');
  692. });
  693. driver.call(function() {
  694. order.push('a');
  695. return d.promise;
  696. });
  697. driver.call(function() {
  698. order.push('c');
  699. });
  700. // timeout to ensure the first function starts its execution before we
  701. // trigger d's callbacks.
  702. return new Promise(f => setTimeout(f, 0)).then(function() {
  703. assert.deepEqual(['a'], order);
  704. d.fulfill();
  705. return waitForIdle().then(function() {
  706. assert.deepEqual(['a', 'b', 'c'], order);
  707. });
  708. });
  709. });
  710. });
  711. it('returnsADeferredAction', function() {
  712. let executor = new FakeExecutor().
  713. expect(CName.GET_TITLE).andReturnSuccess('Google').
  714. end();
  715. var driver = executor.createDriver();
  716. driver.call(function() {
  717. return driver.getTitle();
  718. }).then(function(title) {
  719. assert.equal('Google', title);
  720. });
  721. return waitForIdle();
  722. });
  723. });
  724. describe('nestedCommands', function() {
  725. enablePromiseManager(() => {
  726. it('commandExecutionOrder', function() {
  727. var msg = [];
  728. var driver = new FakeExecutor().createDriver();
  729. driver.call(msg.push, msg, 'a');
  730. driver.call(function() {
  731. driver.call(msg.push, msg, 'c');
  732. driver.call(function() {
  733. driver.call(msg.push, msg, 'e');
  734. driver.call(msg.push, msg, 'f');
  735. });
  736. driver.call(msg.push, msg, 'd');
  737. });
  738. driver.call(msg.push, msg, 'b');
  739. return waitForIdle().then(function() {
  740. assert.equal('acefdb', msg.join(''));
  741. });
  742. });
  743. it('basicUsage', function() {
  744. var msg = [];
  745. var driver = new FakeExecutor().createDriver();
  746. var pushMsg = msg.push.bind(msg);
  747. driver.call(() => 'cheese ').then(pushMsg);
  748. driver.call(function() {
  749. driver.call(() => 'is ').then(pushMsg);
  750. driver.call(() => 'tasty').then(pushMsg);
  751. });
  752. driver.call(() => '!').then(pushMsg);
  753. return waitForIdle().then(function() {
  754. assert.equal('cheese is tasty!', msg.join(''));
  755. });
  756. });
  757. it('normalCommandAfterNestedCommandThatReturnsAnAction', function() {
  758. var msg = [];
  759. let executor = new FakeExecutor().
  760. expect(CName.CLOSE).
  761. end();
  762. var driver = executor.createDriver();
  763. driver.call(function() {
  764. return driver.call(function() {
  765. msg.push('a');
  766. return driver.call(() => 'foobar');
  767. });
  768. });
  769. driver.close().then(function() {
  770. msg.push('b');
  771. });
  772. return waitForIdle().then(function() {
  773. assert.equal('ab', msg.join(''));
  774. });
  775. });
  776. });
  777. it('canReturnValueFromNestedFunction', function() {
  778. var driver = new FakeExecutor().createDriver();
  779. return driver.call(function() {
  780. return driver.call(function() {
  781. return driver.call(() => 'foobar');
  782. });
  783. }).then(function(value) {
  784. assert.equal('foobar', value);
  785. });
  786. });
  787. it('errorsBubbleUp_caught', function() {
  788. var driver = new FakeExecutor().createDriver();
  789. var result = driver.call(function() {
  790. return driver.call(function() {
  791. return driver.call(throwStubError);
  792. });
  793. }).then(fail, assertIsStubError);
  794. return Promise.all([waitForIdle(), result]);
  795. });
  796. it('errorsBubbleUp_uncaught', function() {
  797. var driver = new FakeExecutor().createDriver();
  798. return driver.call(function() {
  799. return driver.call(function() {
  800. return driver.call(throwStubError);
  801. });
  802. })
  803. .then(_ => assert.fail('should have failed'), assertIsStubError);
  804. });
  805. it('canScheduleCommands', function() {
  806. let executor = new FakeExecutor().
  807. expect(CName.GET_TITLE).
  808. expect(CName.CLOSE).
  809. end();
  810. var driver = executor.createDriver();
  811. driver.call(function() {
  812. driver.call(function() {
  813. driver.getTitle();
  814. });
  815. driver.close();
  816. });
  817. return waitForIdle();
  818. });
  819. });
  820. describe('WebElementPromise', function() {
  821. let driver = new FakeExecutor().createDriver();
  822. it('resolvesWhenUnderlyingElementDoes', function() {
  823. let el = new WebElement(driver, {'ELEMENT': 'foo'});
  824. return new WebElementPromise(driver, Promise.resolve(el))
  825. .then(e => assert.strictEqual(e, el));
  826. });
  827. it('resolvesBeforeCallbacksOnWireValueTrigger', function() {
  828. var el = defer();
  829. var element = new WebElementPromise(driver, el.promise);
  830. var messages = [];
  831. let steps = [
  832. element.then(_ => messages.push('element resolved')),
  833. element.getId().then(_ => messages.push('wire value resolved'))
  834. ];
  835. el.resolve(new WebElement(driver, {'ELEMENT': 'foo'}));
  836. return Promise.all(steps).then(function() {
  837. assert.deepEqual([
  838. 'element resolved',
  839. 'wire value resolved'
  840. ], messages);
  841. });
  842. });
  843. it('isRejectedIfUnderlyingIdIsRejected', function() {
  844. let element =
  845. new WebElementPromise(driver, Promise.reject(new StubError));
  846. return element.then(fail, assertIsStubError);
  847. });
  848. });
  849. describe('executeScript', function() {
  850. it('nullReturnValue', function() {
  851. let executor = new FakeExecutor().
  852. expect(CName.EXECUTE_SCRIPT).
  853. withParameters({
  854. 'script': 'return document.body;',
  855. 'args': []
  856. }).
  857. andReturnSuccess(null).
  858. end();
  859. var driver = executor.createDriver();
  860. return driver.executeScript('return document.body;')
  861. .then((result) => assert.equal(null, result));
  862. });
  863. it('primitiveReturnValue', function() {
  864. let executor = new FakeExecutor().
  865. expect(CName.EXECUTE_SCRIPT).
  866. withParameters({
  867. 'script': 'return document.body;',
  868. 'args': []
  869. }).
  870. andReturnSuccess(123).
  871. end();
  872. var driver = executor.createDriver();
  873. return driver.executeScript('return document.body;')
  874. .then((result) => assert.equal(123, result));
  875. });
  876. it('webElementReturnValue', function() {
  877. var json = WebElement.buildId('foo');
  878. let executor = new FakeExecutor().
  879. expect(CName.EXECUTE_SCRIPT).
  880. withParameters({
  881. 'script': 'return document.body;',
  882. 'args': []
  883. }).
  884. andReturnSuccess(json).
  885. end();
  886. var driver = executor.createDriver();
  887. return driver.executeScript('return document.body;')
  888. .then((element) => element.getId())
  889. .then((id) => assert.equal(id, 'foo'));
  890. });
  891. it('arrayReturnValue', function() {
  892. var json = [WebElement.buildId('foo')];
  893. let executor = new FakeExecutor().
  894. expect(CName.EXECUTE_SCRIPT).
  895. withParameters({
  896. 'script': 'return document.body;',
  897. 'args': []
  898. }).
  899. andReturnSuccess(json).
  900. end();
  901. var driver = executor.createDriver();
  902. return driver.executeScript('return document.body;')
  903. .then(function(array) {
  904. assert.equal(1, array.length);
  905. return array[0].getId();
  906. })
  907. .then((id) => assert.equal('foo', id));
  908. });
  909. it('objectReturnValue', function() {
  910. var json = {'foo': WebElement.buildId('foo')};
  911. let executor = new FakeExecutor().
  912. expect(CName.EXECUTE_SCRIPT).
  913. withParameters({
  914. 'script': 'return document.body;',
  915. 'args': []
  916. }).
  917. andReturnSuccess(json).
  918. end();
  919. var driver = executor.createDriver();
  920. var callback;
  921. return driver.executeScript('return document.body;')
  922. .then((obj) => obj['foo'].getId())
  923. .then((id) => assert.equal(id, 'foo'));
  924. });
  925. it('scriptAsFunction', function() {
  926. let executor = new FakeExecutor().
  927. expect(CName.EXECUTE_SCRIPT).
  928. withParameters({
  929. 'script': 'return (' + function() {} +
  930. ').apply(null, arguments);',
  931. 'args': []
  932. }).
  933. andReturnSuccess(null).
  934. end();
  935. var driver = executor.createDriver();
  936. return driver.executeScript(function() {});
  937. });
  938. it('simpleArgumentConversion', function() {
  939. let executor = new FakeExecutor().
  940. expect(CName.EXECUTE_SCRIPT).
  941. withParameters({
  942. 'script': 'return 1;',
  943. 'args': ['abc', 123, true, [123, {'foo': 'bar'}]]
  944. }).
  945. andReturnSuccess(null).
  946. end();
  947. var driver = executor.createDriver();
  948. return driver.executeScript(
  949. 'return 1;', 'abc', 123, true, [123, {'foo': 'bar'}]);
  950. });
  951. it('webElementArgumentConversion', function() {
  952. var elementJson = WebElement.buildId('fefifofum');
  953. let executor = new FakeExecutor().
  954. expect(CName.EXECUTE_SCRIPT).
  955. withParameters({
  956. 'script': 'return 1;',
  957. 'args': [elementJson]
  958. }).
  959. andReturnSuccess(null).
  960. end();
  961. var driver = executor.createDriver();
  962. return driver.executeScript('return 1;',
  963. new WebElement(driver, 'fefifofum'));
  964. });
  965. it('webElementPromiseArgumentConversion', function() {
  966. var elementJson = WebElement.buildId('bar');
  967. let executor = new FakeExecutor().
  968. expect(CName.FIND_ELEMENT,
  969. {'using': 'css selector', 'value': '*[id="foo"]'}).
  970. andReturnSuccess(elementJson).
  971. expect(CName.EXECUTE_SCRIPT).
  972. withParameters({
  973. 'script': 'return 1;',
  974. 'args': [elementJson]
  975. }).
  976. andReturnSuccess(null).
  977. end();
  978. var driver = executor.createDriver();
  979. var element = driver.findElement(By.id('foo'));
  980. return driver.executeScript('return 1;', element);
  981. });
  982. it('argumentConversion', function() {
  983. var elementJson = WebElement.buildId('fefifofum');
  984. let executor = new FakeExecutor().
  985. expect(CName.EXECUTE_SCRIPT).
  986. withParameters({
  987. 'script': 'return 1;',
  988. 'args': ['abc', 123, true, elementJson, [123, {'foo': 'bar'}]]
  989. }).
  990. andReturnSuccess(null).
  991. end();
  992. var driver = executor.createDriver();
  993. var element = new WebElement(driver, 'fefifofum');
  994. return driver.executeScript('return 1;',
  995. 'abc', 123, true, element, [123, {'foo': 'bar'}]);
  996. });
  997. it('scriptReturnsAnError', function() {
  998. let executor = new FakeExecutor().
  999. expect(CName.EXECUTE_SCRIPT).
  1000. withParameters({
  1001. 'script': 'throw Error(arguments[0]);',
  1002. 'args': ['bam']
  1003. }).
  1004. andReturnError(new StubError).
  1005. end();
  1006. var driver = executor.createDriver();
  1007. return driver.executeScript('throw Error(arguments[0]);', 'bam').
  1008. then(fail, assertIsStubError);
  1009. });
  1010. it('failsIfArgumentIsARejectedPromise', function() {
  1011. let executor = new FakeExecutor();
  1012. var arg = Promise.reject(new StubError);
  1013. arg.catch(function() {}); // Suppress default handler.
  1014. var driver = executor.createDriver();
  1015. return driver.executeScript(function() {}, arg).
  1016. then(fail, assertIsStubError);
  1017. });
  1018. });
  1019. describe('executeAsyncScript', function() {
  1020. it('failsIfArgumentIsARejectedPromise', function() {
  1021. var arg = Promise.reject(new StubError);
  1022. arg.catch(function() {}); // Suppress default handler.
  1023. var driver = new FakeExecutor().createDriver();
  1024. return driver.executeAsyncScript(function() {}, arg).
  1025. then(fail, assertIsStubError);
  1026. });
  1027. });
  1028. describe('findElement', function() {
  1029. it('elementNotFound', function() {
  1030. let executor = new FakeExecutor().
  1031. expect(CName.FIND_ELEMENT,
  1032. {using: 'css selector', value: '*[id="foo"]'}).
  1033. andReturnError(new StubError).
  1034. end();
  1035. var driver = executor.createDriver();
  1036. return driver.findElement(By.id('foo'))
  1037. .then(assert.fail, assertIsStubError);
  1038. });
  1039. it('elementNotFoundInACallback', function() {
  1040. let executor = new FakeExecutor().
  1041. expect(CName.FIND_ELEMENT,
  1042. {using: 'css selector', value: '*[id="foo"]'}).
  1043. andReturnError(new StubError).
  1044. end();
  1045. var driver = executor.createDriver();
  1046. return Promise.resolve()
  1047. .then(_ => driver.findElement(By.id('foo')))
  1048. .then(assert.fail, assertIsStubError);
  1049. });
  1050. it('elementFound', function() {
  1051. let executor = new FakeExecutor().
  1052. expect(CName.FIND_ELEMENT,
  1053. {using: 'css selector', value: '*[id="foo"]'}).
  1054. andReturnSuccess(WebElement.buildId('bar')).
  1055. expect(CName.CLICK_ELEMENT, {'id': WebElement.buildId('bar')}).
  1056. andReturnSuccess().
  1057. end();
  1058. var driver = executor.createDriver();
  1059. var element = driver.findElement(By.id('foo'));
  1060. element.click();
  1061. return waitForIdle();
  1062. });
  1063. it('canUseElementInCallback', function() {
  1064. let executor = new FakeExecutor().
  1065. expect(CName.FIND_ELEMENT,
  1066. {using: 'css selector', value: '*[id="foo"]'}).
  1067. andReturnSuccess(WebElement.buildId('bar')).
  1068. expect(CName.CLICK_ELEMENT, {'id': WebElement.buildId('bar')}).
  1069. andReturnSuccess().
  1070. end();
  1071. var driver = executor.createDriver();
  1072. driver.findElement(By.id('foo')).then(function(element) {
  1073. element.click();
  1074. });
  1075. return waitForIdle();
  1076. });
  1077. it('byJs', function() {
  1078. let executor = new FakeExecutor().
  1079. expect(CName.EXECUTE_SCRIPT, {
  1080. 'script': 'return document.body',
  1081. 'args': []
  1082. }).
  1083. andReturnSuccess(WebElement.buildId('bar')).
  1084. expect(CName.CLICK_ELEMENT, {'id': WebElement.buildId('bar')}).
  1085. end();
  1086. var driver = executor.createDriver();
  1087. var element = driver.findElement(By.js('return document.body'));
  1088. element.click(); // just to make sure
  1089. return waitForIdle();
  1090. });
  1091. it('byJs_returnsNonWebElementValue', function() {
  1092. let executor = new FakeExecutor().
  1093. expect(CName.EXECUTE_SCRIPT, {'script': 'return 123', 'args': []}).
  1094. andReturnSuccess(123).
  1095. end();
  1096. var driver = executor.createDriver();
  1097. return driver.findElement(By.js('return 123'))
  1098. .then(assert.fail, function(e) {
  1099. assertIsInstance(TypeError, e);
  1100. assert.equal(
  1101. 'Custom locator did not return a WebElement', e.message);
  1102. });
  1103. });
  1104. it('byJs_canPassArguments', function() {
  1105. var script = 'return document.getElementsByTagName(arguments[0]);';
  1106. let executor = new FakeExecutor().
  1107. expect(CName.EXECUTE_SCRIPT, {
  1108. 'script': script,
  1109. 'args': ['div']
  1110. }).
  1111. andReturnSuccess(WebElement.buildId('one')).
  1112. end();
  1113. var driver = executor.createDriver();
  1114. driver.findElement(By.js(script, 'div'));
  1115. return waitForIdle();
  1116. });
  1117. it('customLocator', function() {
  1118. let executor = new FakeExecutor().
  1119. expect(CName.FIND_ELEMENTS, {'using': 'css selector', 'value': 'a'}).
  1120. andReturnSuccess([
  1121. WebElement.buildId('foo'),
  1122. WebElement.buildId('bar')]).
  1123. expect(CName.CLICK_ELEMENT, {'id': WebElement.buildId('foo')}).
  1124. andReturnSuccess().
  1125. end();
  1126. var driver = executor.createDriver();
  1127. var element = driver.findElement(function(d) {
  1128. assert.equal(driver, d);
  1129. return d.findElements(By.tagName('a'));
  1130. });
  1131. return element.click();
  1132. });
  1133. it('customLocatorThrowsIfresultIsNotAWebElement', function() {
  1134. var driver = new FakeExecutor().createDriver();
  1135. return driver.findElement(_ => 1)
  1136. .then(assert.fail, function(e) {
  1137. assertIsInstance(TypeError, e);
  1138. assert.equal(
  1139. 'Custom locator did not return a WebElement', e.message);
  1140. });
  1141. });
  1142. });
  1143. describe('findElements', function() {
  1144. it('returnsMultipleElements', function() {
  1145. var ids = ['foo', 'bar', 'baz'];
  1146. let executor = new FakeExecutor().
  1147. expect(CName.FIND_ELEMENTS, {'using':'css selector', 'value':'a'}).
  1148. andReturnSuccess(ids.map(WebElement.buildId)).
  1149. end();
  1150. var driver = executor.createDriver();
  1151. return driver.findElements(By.tagName('a'))
  1152. .then(function(elements) {
  1153. return promise.all(elements.map(function(e) {
  1154. assert.ok(e instanceof WebElement);
  1155. return e.getId();
  1156. }));
  1157. })
  1158. .then((actual) => assert.deepEqual(ids, actual));
  1159. });
  1160. it('byJs', function() {
  1161. var ids = ['foo', 'bar', 'baz'];
  1162. let executor = new FakeExecutor().
  1163. expect(CName.EXECUTE_SCRIPT, {
  1164. 'script': 'return document.getElementsByTagName("div");',
  1165. 'args': []
  1166. }).
  1167. andReturnSuccess(ids.map(WebElement.buildId)).
  1168. end();
  1169. var driver = executor.createDriver();
  1170. return driver.
  1171. findElements(By.js('return document.getElementsByTagName("div");')).
  1172. then(function(elements) {
  1173. return promise.all(elements.map(function(e) {
  1174. assert.ok(e instanceof WebElement);
  1175. return e.getId();
  1176. }));
  1177. }).
  1178. then((actual) => assert.deepEqual(ids, actual));
  1179. });
  1180. it('byJs_filtersOutNonWebElementResponses', function() {
  1181. var ids = ['foo', 'bar', 'baz'];
  1182. var json = [
  1183. WebElement.buildId(ids[0]),
  1184. 123,
  1185. 'a',
  1186. false,
  1187. WebElement.buildId(ids[1]),
  1188. {'not a web element': 1},
  1189. WebElement.buildId(ids[2])
  1190. ];
  1191. let executor = new FakeExecutor().
  1192. expect(CName.EXECUTE_SCRIPT, {
  1193. 'script': 'return document.getElementsByTagName("div");',
  1194. 'args': []
  1195. }).
  1196. andReturnSuccess(json).
  1197. end();
  1198. var driver = executor.createDriver();
  1199. driver.findElements(By.js('return document.getElementsByTagName("div");')).
  1200. then(function(elements) {
  1201. return promise.all(elements.map(function(e) {
  1202. assert.ok(e instanceof WebElement);
  1203. return e.getId();
  1204. }));
  1205. }).
  1206. then((actual) => assert.deepEqual(ids, actual));
  1207. return waitForIdle();
  1208. });
  1209. it('byJs_convertsSingleWebElementResponseToArray', function() {
  1210. let executor = new FakeExecutor().
  1211. expect(CName.EXECUTE_SCRIPT, {
  1212. 'script': 'return document.getElementsByTagName("div");',
  1213. 'args': []
  1214. }).
  1215. andReturnSuccess(WebElement.buildId('foo')).
  1216. end();
  1217. var driver = executor.createDriver();
  1218. return driver.
  1219. findElements(By.js('return document.getElementsByTagName("div");')).
  1220. then(function(elements) {
  1221. return promise.all(elements.map(function(e) {
  1222. assert.ok(e instanceof WebElement);
  1223. return e.getId();
  1224. }));
  1225. }).
  1226. then((actual) => assert.deepEqual(['foo'], actual));
  1227. });
  1228. it('byJs_canPassScriptArguments', function() {
  1229. var script = 'return document.getElementsByTagName(arguments[0]);';
  1230. let executor = new FakeExecutor().
  1231. expect(CName.EXECUTE_SCRIPT, {
  1232. 'script': script,
  1233. 'args': ['div']
  1234. }).
  1235. andReturnSuccess([
  1236. WebElement.buildId('one'),
  1237. WebElement.buildId('two')
  1238. ]).
  1239. end();
  1240. var driver = executor.createDriver();
  1241. return driver.findElements(By.js(script, 'div'))
  1242. then(function(elements) {
  1243. return promise.all(elements.map(function(e) {
  1244. assert.ok(e instanceof WebElement);
  1245. return e.getId();
  1246. }));
  1247. }).
  1248. then((actual) => assert.deepEqual(['one', 'two'], actual));
  1249. });
  1250. });
  1251. describe('sendKeys', function() {
  1252. it('convertsVarArgsIntoStrings_simpleArgs', function() {
  1253. let executor = new FakeExecutor().
  1254. expect(CName.SEND_KEYS_TO_ELEMENT,
  1255. {'id': WebElement.buildId('one'),
  1256. 'text': '12abc3',
  1257. 'value':'12abc3'.split('')}).
  1258. andReturnSuccess().
  1259. end();
  1260. var driver = executor.createDriver();
  1261. var element = new WebElement(driver, 'one');
  1262. element.sendKeys(1, 2, 'abc', 3);
  1263. return waitForIdle();
  1264. });
  1265. it('convertsVarArgsIntoStrings_promisedArgs', function() {
  1266. let executor = new FakeExecutor().
  1267. expect(CName.FIND_ELEMENT,
  1268. {'using':'css selector', 'value':'*[id="foo"]'}).
  1269. andReturnSuccess(WebElement.buildId('one')).
  1270. expect(CName.SEND_KEYS_TO_ELEMENT,
  1271. {'id':WebElement.buildId('one'),
  1272. 'text': 'abc123def',
  1273. 'value':'abc123def'.split('')}).
  1274. andReturnSuccess().
  1275. end();
  1276. var driver = executor.createDriver();
  1277. var element = driver.findElement(By.id('foo'));
  1278. return element.sendKeys(
  1279. Promise.resolve('abc'),
  1280. 123,
  1281. Promise.resolve('def'));
  1282. });
  1283. it('sendKeysWithAFileDetector', function() {
  1284. let executor = new FakeExecutor().
  1285. expect(CName.FIND_ELEMENT,
  1286. {'using':'css selector', 'value':'*[id="foo"]'}).
  1287. andReturnSuccess(WebElement.buildId('one')).
  1288. expect(CName.SEND_KEYS_TO_ELEMENT,
  1289. {'id': WebElement.buildId('one'),
  1290. 'text': 'modified/path',
  1291. 'value':'modified/path'.split('')}).
  1292. andReturnSuccess().
  1293. end();
  1294. let driver = executor.createDriver();
  1295. let handleFile = function(d, path) {
  1296. assert.strictEqual(driver, d);
  1297. assert.equal(path, 'original/path');
  1298. return Promise.resolve('modified/path');
  1299. };
  1300. driver.setFileDetector({handleFile});
  1301. return driver.findElement(By.id('foo')).sendKeys('original/', 'path');
  1302. });
  1303. });
  1304. describe("switchTo()", function() {
  1305. describe("window", function() {
  1306. it('should return a resolved promise when the window is found', function() {
  1307. let executor = new FakeExecutor().
  1308. expect(CName.SWITCH_TO_WINDOW).
  1309. withParameters({
  1310. 'name': 'foo',
  1311. 'handle': 'foo'
  1312. }).
  1313. andReturnSuccess().
  1314. end();
  1315. executor.createDriver().switchTo().window('foo');
  1316. return waitForIdle();
  1317. });
  1318. it('should propagate exceptions', function() {
  1319. let e = new error.NoSuchWindowError('window not found');
  1320. let executor = new FakeExecutor().
  1321. expect(CName.SWITCH_TO_WINDOW).
  1322. withParameters({
  1323. 'name': 'foo',
  1324. 'handle': 'foo'
  1325. }).
  1326. andReturnError(e).
  1327. end();
  1328. return executor.createDriver()
  1329. .switchTo().window('foo')
  1330. .then(assert.fail, v => assert.strictEqual(v, e));
  1331. });
  1332. });
  1333. });
  1334. describe('elementEquality', function() {
  1335. it('isReflexive', function() {
  1336. var a = new WebElement(new FakeExecutor().createDriver(), 'foo');
  1337. return WebElement.equals(a, a).then(assert.ok);
  1338. });
  1339. it('failsIfAnInputElementCouldNotBeFound', function() {
  1340. let id = Promise.reject(new StubError);
  1341. var driver = new FakeExecutor().createDriver();
  1342. var a = new WebElement(driver, 'foo');
  1343. var b = new WebElementPromise(driver, id);
  1344. return WebElement.equals(a, b).then(fail, assertIsStubError);
  1345. });
  1346. });
  1347. describe('waiting', function() {
  1348. describe('supports custom wait functions', function() {
  1349. it('waitSucceeds', function() {
  1350. let executor = new FakeExecutor().
  1351. expect(CName.FIND_ELEMENTS,
  1352. {using: 'css selector', value: '*[id="foo"]'}).
  1353. andReturnSuccess([]).
  1354. times(2).
  1355. expect(CName.FIND_ELEMENTS,
  1356. {using: 'css selector', value: '*[id="foo"]'}).
  1357. andReturnSuccess([WebElement.buildId('bar')]).
  1358. end();
  1359. var driver = executor.createDriver();
  1360. driver.wait(function() {
  1361. return driver.findElements(By.id('foo')).then(els => els.length > 0);
  1362. }, 200);
  1363. return waitForIdle();
  1364. });
  1365. it('waitTimesout_timeoutCaught', function() {
  1366. let executor = new FakeExecutor().
  1367. expect(CName.FIND_ELEMENTS,
  1368. {using: 'css selector', value: '*[id="foo"]'}).
  1369. andReturnSuccess([]).
  1370. anyTimes().
  1371. end();
  1372. var driver = executor.createDriver();
  1373. return driver.wait(function() {
  1374. return driver.findElements(By.id('foo')).then(els => els.length > 0);
  1375. }, 25).then(fail, function(e) {
  1376. assert.equal('Wait timed out after ',
  1377. e.message.substring(0, 'Wait timed out after '.length));
  1378. });
  1379. });
  1380. enablePromiseManager(() => {
  1381. it('waitTimesout_timeoutNotCaught', function() {
  1382. let executor = new FakeExecutor().
  1383. expect(CName.FIND_ELEMENTS,
  1384. {using: 'css selector', value: '*[id="foo"]'}).
  1385. andReturnSuccess([]).
  1386. anyTimes().
  1387. end();
  1388. var driver = executor.createDriver();
  1389. driver.wait(function() {
  1390. return driver.findElements(By.id('foo')).then(els => els.length > 0);
  1391. }, 25);
  1392. return waitForAbort().then(function(e) {
  1393. assert.equal('Wait timed out after ',
  1394. e.message.substring(0, 'Wait timed out after '.length));
  1395. });
  1396. });
  1397. });
  1398. });
  1399. describe('supports condition objects', function() {
  1400. it('wait succeeds', function() {
  1401. let executor = new FakeExecutor()
  1402. .expect(CName.FIND_ELEMENTS,
  1403. {using: 'css selector', value: '*[id="foo"]'})
  1404. .andReturnSuccess([])
  1405. .times(2)
  1406. .expect(CName.FIND_ELEMENTS,
  1407. {using: 'css selector', value: '*[id="foo"]'})
  1408. .andReturnSuccess([WebElement.buildId('bar')])
  1409. .end();
  1410. let driver = executor.createDriver();
  1411. return driver.wait(until.elementLocated(By.id('foo')), 200);
  1412. });
  1413. it('wait times out', function() {
  1414. let executor = new FakeExecutor()
  1415. .expect(CName.FIND_ELEMENTS,
  1416. {using: 'css selector', value: '*[id="foo"]'})
  1417. .andReturnSuccess([])
  1418. .anyTimes()
  1419. .end();
  1420. let driver = executor.createDriver();
  1421. return driver.wait(until.elementLocated(By.id('foo')), 5)
  1422. .then(fail, err => assert.ok(err instanceof error.TimeoutError));
  1423. });
  1424. });
  1425. describe('supports promise objects', function() {
  1426. it('wait succeeds', function() {
  1427. let promise = new Promise(resolve => {
  1428. setTimeout(() => resolve(1), 10);
  1429. });
  1430. let driver = new FakeExecutor().createDriver();
  1431. return driver.wait(promise, 200).then(v => assert.equal(v, 1));
  1432. });
  1433. it('wait times out', function() {
  1434. let promise = new Promise(resolve => {/* never resolves */});
  1435. let driver = new FakeExecutor().createDriver();
  1436. return driver.wait(promise, 5)
  1437. .then(fail, err => assert.ok(err instanceof error.TimeoutError));
  1438. });
  1439. it('wait fails if promise is rejected', function() {
  1440. let err = Error('boom');
  1441. let driver = new FakeExecutor().createDriver();
  1442. return driver.wait(Promise.reject(err), 5)
  1443. .then(fail, e => assert.strictEqual(e, err));
  1444. });
  1445. });
  1446. it('fails if not supported condition type provided', function() {
  1447. let driver = new FakeExecutor().createDriver();
  1448. assert.throws(() => driver.wait({}, 5), TypeError);
  1449. });
  1450. });
  1451. describe('alert handling', function() {
  1452. it('alertResolvesWhenPromisedTextResolves', function() {
  1453. let driver = new FakeExecutor().createDriver();
  1454. let deferredText = defer();
  1455. let alert = new AlertPromise(driver, deferredText.promise);
  1456. deferredText.resolve(new Alert(driver, 'foo'));
  1457. return alert.getText().then(text => assert.equal(text, 'foo'));
  1458. });
  1459. it('cannotSwitchToAlertThatIsNotPresent', function() {
  1460. let e = new error.NoSuchAlertError;
  1461. let executor = new FakeExecutor()
  1462. .expect(CName.GET_ALERT_TEXT)
  1463. .andReturnError(e)
  1464. .end();
  1465. return executor.createDriver()
  1466. .switchTo().alert()
  1467. .then(assert.fail, v => assert.strictEqual(v, e));
  1468. });
  1469. enablePromiseManager(() => {
  1470. it('alertsBelongToSameFlowAsParentDriver', function() {
  1471. let executor = new FakeExecutor()
  1472. .expect(CName.GET_ALERT_TEXT).andReturnSuccess('hello')
  1473. .end();
  1474. var driver = executor.createDriver();
  1475. var otherFlow = new promise.ControlFlow();
  1476. otherFlow.execute(function() {
  1477. driver.switchTo().alert().then(function() {
  1478. assert.strictEqual(
  1479. driver.controlFlow(), promise.controlFlow(),
  1480. 'Alert should belong to the same flow as its parent driver');
  1481. });
  1482. });
  1483. assert.notEqual(otherFlow, driver.controlFlow);
  1484. return Promise.all([
  1485. waitForIdle(otherFlow),
  1486. waitForIdle(driver.controlFlow())
  1487. ]);
  1488. });
  1489. });
  1490. it('commandsFailIfAlertNotPresent', function() {
  1491. let e = new error.NoSuchAlertError;
  1492. let executor = new FakeExecutor()
  1493. .expect(CName.GET_ALERT_TEXT)
  1494. .andReturnError(e)
  1495. .end();
  1496. var driver = executor.createDriver();
  1497. var alert = driver.switchTo().alert();
  1498. var expectError = (v) => assert.strictEqual(v, e);
  1499. return alert.getText()
  1500. .then(fail, expectedError)
  1501. .then(() => alert.accept())
  1502. .then(fail, expectedError)
  1503. .then(() => alert.dismiss())
  1504. .then(fail, expectError)
  1505. .then(() => alert.sendKeys('hi'))
  1506. .then(fail, expectError);
  1507. });
  1508. });
  1509. enablePromiseManager(() => {
  1510. it('testWebElementsBelongToSameFlowAsParentDriver', function() {
  1511. let executor = new FakeExecutor()
  1512. .expect(CName.FIND_ELEMENT,
  1513. {using: 'css selector', value: '*[id="foo"]'})
  1514. .andReturnSuccess(WebElement.buildId('abc123'))
  1515. .end();
  1516. var driver = executor.createDriver();
  1517. var otherFlow = new promise.ControlFlow();
  1518. otherFlow.execute(function() {
  1519. driver.findElement({id: 'foo'}).then(function() {
  1520. assert.equal(driver.controlFlow(), promise.controlFlow());
  1521. });
  1522. });
  1523. assert.notEqual(otherFlow, driver.controlFlow);
  1524. return Promise.all([
  1525. waitForIdle(otherFlow),
  1526. waitForIdle(driver.controlFlow())
  1527. ]);
  1528. });
  1529. });
  1530. it('testFetchingLogs', function() {
  1531. let executor = new FakeExecutor().
  1532. expect(CName.GET_LOG, {'type': 'browser'}).
  1533. andReturnSuccess([
  1534. {'level': 'INFO', 'message': 'hello', 'timestamp': 1234},
  1535. {'level': 'DEBUG', 'message': 'abc123', 'timestamp': 5678}
  1536. ]).
  1537. end();
  1538. var driver = executor.createDriver();
  1539. return driver.manage().logs().get('browser').then(function(entries) {
  1540. assert.equal(2, entries.length);
  1541. assert.ok(entries[0] instanceof logging.Entry);
  1542. assert.equal(logging.Level.INFO.value, entries[0].level.value);
  1543. assert.equal('hello', entries[0].message);
  1544. assert.equal(1234, entries[0].timestamp);
  1545. assert.ok(entries[1] instanceof logging.Entry);
  1546. assert.equal(logging.Level.DEBUG.value, entries[1].level.value);
  1547. assert.equal('abc123', entries[1].message);
  1548. assert.equal(5678, entries[1].timestamp);
  1549. });
  1550. });
  1551. it('testCommandsFailIfInitialSessionCreationFailed', function() {
  1552. var session = Promise.reject(new StubError);
  1553. var driver = new FakeExecutor().createDriver(session);
  1554. var navigateResult = driver.get('some-url').then(fail, assertIsStubError);
  1555. var quitResult = driver.quit().then(fail, assertIsStubError);
  1556. return waitForIdle().then(function() {
  1557. return promise.all(navigateResult, quitResult);
  1558. });
  1559. });
  1560. it('testWebElementCommandsFailIfInitialDriverCreationFailed', function() {
  1561. var session = Promise.reject(new StubError);
  1562. var driver = new FakeExecutor().createDriver(session);
  1563. return driver.findElement(By.id('foo')).click().
  1564. then(fail, assertIsStubError);
  1565. });
  1566. it('testWebElementCommansFailIfElementCouldNotBeFound', function() {
  1567. let e = new error.NoSuchElementError('Unable to find element');
  1568. let executor = new FakeExecutor().
  1569. expect(CName.FIND_ELEMENT,
  1570. {using: 'css selector', value: '*[id="foo"]'}).
  1571. andReturnError(e).
  1572. end();
  1573. var driver = executor.createDriver();
  1574. return driver.findElement(By.id('foo')).click()
  1575. .then(fail, v => assert.strictEqual(v, e));
  1576. });
  1577. it('testCannotFindChildElementsIfParentCouldNotBeFound', function() {
  1578. let e = new error.NoSuchElementError('Unable to find element');
  1579. let executor = new FakeExecutor().
  1580. expect(CName.FIND_ELEMENT,
  1581. {using: 'css selector', value: '*[id="foo"]'}).
  1582. andReturnError(e).
  1583. end();
  1584. var driver = executor.createDriver();
  1585. return driver.findElement(By.id('foo'))
  1586. .findElement(By.id('bar'))
  1587. .findElement(By.id('baz'))
  1588. .then(fail, v => assert.strictEqual(v, e));
  1589. });
  1590. describe('actions()', function() {
  1591. it('failsIfInitialDriverCreationFailed', function() {
  1592. let session = Promise.reject(new StubError('no session for you'));
  1593. let driver = new FakeExecutor().createDriver(session);
  1594. driver.getSession().catch(function() {});
  1595. return driver.
  1596. actions().
  1597. mouseDown().
  1598. mouseUp().
  1599. perform().
  1600. catch(assertIsStubError);
  1601. });
  1602. describe('mouseMove', function() {
  1603. it('noElement', function() {
  1604. let executor = new FakeExecutor()
  1605. .expect(CName.MOVE_TO, {'xoffset': 0, 'yoffset': 125})
  1606. .andReturnSuccess()
  1607. .end();
  1608. return executor.createDriver().
  1609. actions().
  1610. mouseMove({x: 0, y: 125}).
  1611. perform();
  1612. });
  1613. it('element', function() {
  1614. let executor = new FakeExecutor()
  1615. .expect(CName.FIND_ELEMENT,
  1616. {using: 'css selector', value: '*[id="foo"]'})
  1617. .andReturnSuccess(WebElement.buildId('abc123'))
  1618. .expect(CName.MOVE_TO,
  1619. {'element': 'abc123', 'xoffset': 0, 'yoffset': 125})
  1620. .andReturnSuccess()
  1621. .end();
  1622. var driver = executor.createDriver();
  1623. var element = driver.findElement(By.id('foo'));
  1624. return driver.actions()
  1625. .mouseMove(element, {x: 0, y: 125})
  1626. .perform();
  1627. });
  1628. });
  1629. it('supportsMouseDown', function() {
  1630. let executor = new FakeExecutor()
  1631. .expect(CName.MOUSE_DOWN, {'button': Button.LEFT})
  1632. .andReturnSuccess()
  1633. .end();
  1634. return executor.createDriver().
  1635. actions().
  1636. mouseDown().
  1637. perform();
  1638. });
  1639. it('testActionSequence', function() {
  1640. let executor = new FakeExecutor()
  1641. .expect(CName.FIND_ELEMENT,
  1642. {using: 'css selector', value: '*[id="a"]'})
  1643. .andReturnSuccess(WebElement.buildId('id1'))
  1644. .expect(CName.FIND_ELEMENT,
  1645. {using: 'css selector', value: '*[id="b"]'})
  1646. .andReturnSuccess(WebElement.buildId('id2'))
  1647. .expect(CName.SEND_KEYS_TO_ACTIVE_ELEMENT,
  1648. {'value': [Key.SHIFT]})
  1649. .andReturnSuccess()
  1650. .expect(CName.MOVE_TO, {'element': 'id1'})
  1651. .andReturnSuccess()
  1652. .expect(CName.CLICK, {'button': Button.LEFT})
  1653. .andReturnSuccess()
  1654. .expect(CName.MOVE_TO, {'element': 'id2'})
  1655. .andReturnSuccess()
  1656. .expect(CName.CLICK, {'button': Button.LEFT})
  1657. .andReturnSuccess()
  1658. .end();
  1659. var driver = executor.createDriver();
  1660. var element1 = driver.findElement(By.id('a'));
  1661. var element2 = driver.findElement(By.id('b'));
  1662. return driver.actions()
  1663. .keyDown(Key.SHIFT)
  1664. .click(element1)
  1665. .click(element2)
  1666. .perform();
  1667. });
  1668. });
  1669. describe('touchActions()', function() {
  1670. it('failsIfInitialDriverCreationFailed', function() {
  1671. let session = Promise.reject(new StubError);
  1672. let driver = new FakeExecutor().createDriver(session);
  1673. driver.getSession().catch(function() {});
  1674. return driver.
  1675. touchActions().
  1676. scroll({x: 3, y: 4}).
  1677. perform().
  1678. catch(assertIsStubError);
  1679. });
  1680. it('testTouchActionSequence', function() {
  1681. let executor = new FakeExecutor()
  1682. .expect(CName.TOUCH_DOWN, {x: 1, y: 2}).andReturnSuccess()
  1683. .expect(CName.TOUCH_MOVE, {x: 3, y: 4}).andReturnSuccess()
  1684. .expect(CName.TOUCH_UP, {x: 5, y: 6}).andReturnSuccess()
  1685. .end();
  1686. var driver = executor.createDriver();
  1687. return driver.touchActions()
  1688. .tapAndHold({x: 1, y: 2})
  1689. .move({x: 3, y: 4})
  1690. .release({x: 5, y: 6})
  1691. .perform();
  1692. });
  1693. });
  1694. describe('manage()', function() {
  1695. describe('setTimeouts()', function() {
  1696. describe('throws if no timeouts are specified', function() {
  1697. let driver;
  1698. before(() => driver = new FakeExecutor().createDriver());
  1699. it('; no arguments', function() {
  1700. assert.throws(() => driver.manage().setTimeouts(), TypeError);
  1701. });
  1702. it('; ignores unrecognized timeout keys', function() {
  1703. assert.throws(
  1704. () => driver.manage().setTimeouts({foo: 123}), TypeError);
  1705. });
  1706. it('; ignores positional arguments', function() {
  1707. assert.throws(
  1708. () => driver.manage().setTimeouts(1234, 56), TypeError);
  1709. });
  1710. });
  1711. describe('throws timeout is not a number, null, or undefined', () => {
  1712. let driver;
  1713. before(() => driver = new FakeExecutor().createDriver());
  1714. function checkError(e) {
  1715. return e instanceof TypeError
  1716. && /expected "(script|pageLoad|implicit)" to be a number/.test(
  1717. e.message);
  1718. }
  1719. it('script', function() {
  1720. assert.throws(
  1721. () => driver.manage().setTimeouts({script: 'abc'}),
  1722. checkError);
  1723. });
  1724. it('pageLoad', function() {
  1725. assert.throws(
  1726. () => driver.manage().setTimeouts({pageLoad: 'abc'}),
  1727. checkError);
  1728. });
  1729. it('implicit', function() {
  1730. assert.throws(
  1731. () => driver.manage().setTimeouts({implicit: 'abc'}),
  1732. checkError);
  1733. });
  1734. });
  1735. it('can set multiple timeouts', function() {
  1736. let executor = new FakeExecutor()
  1737. .expect(CName.SET_TIMEOUT, {script:1, pageLoad: 2, implicit: 3})
  1738. .andReturnSuccess()
  1739. .end();
  1740. let driver = executor.createDriver();
  1741. return driver.manage()
  1742. .setTimeouts({script: 1, pageLoad: 2, implicit: 3});
  1743. });
  1744. it('falls back to legacy wire format if W3C version fails', () => {
  1745. let executor = new FakeExecutor()
  1746. .expect(CName.SET_TIMEOUT, {implicit: 3})
  1747. .andReturnError(Error('oops'))
  1748. .expect(CName.SET_TIMEOUT, {type: 'implicit', ms: 3})
  1749. .andReturnSuccess()
  1750. .end();
  1751. let driver = executor.createDriver();
  1752. return driver.manage().setTimeouts({implicit: 3});
  1753. });
  1754. describe('deprecated API calls setTimeouts()', function() {
  1755. it('implicitlyWait()', function() {
  1756. let executor = new FakeExecutor()
  1757. .expect(CName.SET_TIMEOUT, {implicit: 3})
  1758. .andReturnSuccess()
  1759. .end();
  1760. let driver = executor.createDriver();
  1761. return driver.manage().timeouts().implicitlyWait(3);
  1762. });
  1763. it('setScriptTimeout()', function() {
  1764. let executor = new FakeExecutor()
  1765. .expect(CName.SET_TIMEOUT, {script: 3})
  1766. .andReturnSuccess()
  1767. .end();
  1768. let driver = executor.createDriver();
  1769. return driver.manage().timeouts().setScriptTimeout(3);
  1770. });
  1771. it('pageLoadTimeout()', function() {
  1772. let executor = new FakeExecutor()
  1773. .expect(CName.SET_TIMEOUT, {pageLoad: 3})
  1774. .andReturnSuccess()
  1775. .end();
  1776. let driver = executor.createDriver();
  1777. return driver.manage().timeouts().pageLoadTimeout(3);
  1778. });
  1779. });
  1780. });
  1781. });
  1782. describe('generator support', function() {
  1783. var driver;
  1784. beforeEach(function() {
  1785. driver = new WebDriver(
  1786. new Session('test-session', {}),
  1787. new ExplodingExecutor());
  1788. });
  1789. it('canUseGeneratorsWithWebDriverCall', function() {
  1790. return driver.call(function* () {
  1791. var x = yield Promise.resolve(1);
  1792. var y = yield Promise.resolve(2);
  1793. return x + y;
  1794. }).then(function(value) {
  1795. assert.deepEqual(3, value);
  1796. });
  1797. });
  1798. it('canDefineScopeOnGeneratorCall', function() {
  1799. return driver.call(function* () {
  1800. var x = yield Promise.resolve(1);
  1801. return this.name + x;
  1802. }, {name: 'Bob'}).then(function(value) {
  1803. assert.deepEqual('Bob1', value);
  1804. });
  1805. });
  1806. it('canSpecifyArgsOnGeneratorCall', function() {
  1807. return driver.call(function* (a, b) {
  1808. var x = yield Promise.resolve(1);
  1809. var y = yield Promise.resolve(2);
  1810. return [x + y, a, b];
  1811. }, null, 'abc', 123).then(function(value) {
  1812. assert.deepEqual([3, 'abc', 123], value);
  1813. });
  1814. });
  1815. it('canUseGeneratorWithWebDriverWait', function() {
  1816. var values = [];
  1817. return driver.wait(function* () {
  1818. yield values.push(1);
  1819. values.push(yield promise.delayed(10).then(function() {
  1820. return 2;
  1821. }));
  1822. yield values.push(3);
  1823. return values.length === 6;
  1824. }, 250).then(function() {
  1825. assert.deepEqual([1, 2, 3, 1, 2, 3], values);
  1826. });
  1827. });
  1828. /**
  1829. * @constructor
  1830. * @implements {CommandExecutor}
  1831. */
  1832. function ExplodingExecutor() {}
  1833. /** @override */
  1834. ExplodingExecutor.prototype.execute = function(command, cb) {
  1835. cb(Error('Unsupported operation'));
  1836. };
  1837. });
  1838. describe('wire format', function() {
  1839. const FAKE_DRIVER = new FakeExecutor().createDriver();
  1840. describe('can serialize', function() {
  1841. function runSerializeTest(input, want) {
  1842. let executor = new FakeExecutor().
  1843. expect(CName.NEW_SESSION).
  1844. withParameters({'desiredCapabilities': want}).
  1845. andReturnSuccess({'browserName': 'firefox'}).
  1846. end();
  1847. return WebDriver.createSession(executor, input)
  1848. .getSession();
  1849. }
  1850. it('function as a string', function() {
  1851. function foo() { return 'foo'; }
  1852. return runSerializeTest(foo, '' + foo);
  1853. });
  1854. it('object with toJSON()', function() {
  1855. return runSerializeTest(
  1856. new Date(605728511546),
  1857. '1989-03-12T17:55:11.546Z');
  1858. });
  1859. it('Session', function() {
  1860. return runSerializeTest(new Session('foo', {}), 'foo');
  1861. });
  1862. it('Capabilities', function() {
  1863. var prefs = new logging.Preferences();
  1864. prefs.setLevel(logging.Type.BROWSER, logging.Level.DEBUG);
  1865. var caps = Capabilities.chrome();
  1866. caps.setLoggingPrefs(prefs);
  1867. return runSerializeTest(
  1868. caps,
  1869. {
  1870. 'browserName': 'chrome',
  1871. 'loggingPrefs': {'browser': 'DEBUG'}
  1872. });
  1873. });
  1874. it('WebElement', function() {
  1875. return runSerializeTest(
  1876. new WebElement(FAKE_DRIVER, 'fefifofum'),
  1877. WebElement.buildId('fefifofum'));
  1878. });
  1879. it('WebElementPromise', function() {
  1880. return runSerializeTest(
  1881. new WebElementPromise(
  1882. FAKE_DRIVER,
  1883. Promise.resolve(new WebElement(FAKE_DRIVER, 'fefifofum'))),
  1884. WebElement.buildId('fefifofum'));
  1885. });
  1886. describe('an array', function() {
  1887. it('with Serializable', function() {
  1888. return runSerializeTest([new Session('foo', {})], ['foo']);
  1889. });
  1890. it('with WebElement', function() {
  1891. return runSerializeTest(
  1892. [new WebElement(FAKE_DRIVER, 'fefifofum')],
  1893. [WebElement.buildId('fefifofum')]);
  1894. });
  1895. it('with WebElementPromise', function() {
  1896. return runSerializeTest(
  1897. [new WebElementPromise(
  1898. FAKE_DRIVER,
  1899. Promise.resolve(new WebElement(FAKE_DRIVER, 'fefifofum')))],
  1900. [WebElement.buildId('fefifofum')]);
  1901. });
  1902. it('complex array', function() {
  1903. var expected = [
  1904. 'abc', 123, true, WebElement.buildId('fefifofum'),
  1905. [123, {'foo': 'bar'}]
  1906. ];
  1907. var element = new WebElement(FAKE_DRIVER, 'fefifofum');
  1908. var input = ['abc', 123, true, element, [123, {'foo': 'bar'}]];
  1909. return runSerializeTest(input, expected);
  1910. });
  1911. it('nested promises', function() {
  1912. return runSerializeTest(
  1913. ['abc', Promise.resolve([123, Promise.resolve(true)])],
  1914. ['abc', [123, true]]);
  1915. });
  1916. });
  1917. describe('an object', function() {
  1918. it('literal', function() {
  1919. var expected = {sessionId: 'foo'};
  1920. return runSerializeTest({sessionId: 'foo'}, expected);
  1921. });
  1922. it('with sub-objects', function() {
  1923. var expected = {sessionId: {value: 'foo'}};
  1924. return runSerializeTest(
  1925. {sessionId: {value: 'foo'}}, expected);
  1926. });
  1927. it('with values that have toJSON', function() {
  1928. return runSerializeTest(
  1929. {a: {b: new Date(605728511546)}},
  1930. {a: {b: '1989-03-12T17:55:11.546Z'}});
  1931. });
  1932. it('with a Session', function() {
  1933. return runSerializeTest(
  1934. {a: new Session('foo', {})},
  1935. {a: 'foo'});
  1936. });
  1937. it('nested', function() {
  1938. var elementJson = WebElement.buildId('fefifofum');
  1939. var expected = {
  1940. 'script': 'return 1',
  1941. 'args': ['abc', 123, true, elementJson, [123, {'foo': 'bar'}]],
  1942. 'sessionId': 'foo'
  1943. };
  1944. var element = new WebElement(FAKE_DRIVER, 'fefifofum');
  1945. var parameters = {
  1946. 'script': 'return 1',
  1947. 'args':['abc', 123, true, element, [123, {'foo': 'bar'}]],
  1948. 'sessionId': new Session('foo', {})
  1949. };
  1950. return runSerializeTest(parameters, expected);
  1951. });
  1952. });
  1953. });
  1954. describe('can deserialize', function() {
  1955. function runDeserializeTest(original, want) {
  1956. let executor = new FakeExecutor()
  1957. .expect(CName.GET_CURRENT_URL)
  1958. .andReturnSuccess(original)
  1959. .end();
  1960. let driver = executor.createDriver();
  1961. return driver.getCurrentUrl().then(function(got) {
  1962. assert.deepEqual(got, want);
  1963. });
  1964. }
  1965. it('primitives', function() {
  1966. return Promise.all([
  1967. runDeserializeTest(1, 1),
  1968. runDeserializeTest('', ''),
  1969. runDeserializeTest(true, true),
  1970. runDeserializeTest(undefined, undefined),
  1971. runDeserializeTest(null, null)
  1972. ]);
  1973. });
  1974. it('simple object', function() {
  1975. return runDeserializeTest(
  1976. {sessionId: 'foo'},
  1977. {sessionId: 'foo'});
  1978. });
  1979. it('nested object', function() {
  1980. return runDeserializeTest(
  1981. {'foo': {'bar': 123}},
  1982. {'foo': {'bar': 123}});
  1983. });
  1984. it('array', function() {
  1985. return runDeserializeTest(
  1986. [{'foo': {'bar': 123}}],
  1987. [{'foo': {'bar': 123}}]);
  1988. });
  1989. it('passes through function properties', function() {
  1990. function bar() {}
  1991. return runDeserializeTest(
  1992. [{foo: {'bar': 123}, func: bar}],
  1993. [{foo: {'bar': 123}, func: bar}]);
  1994. });
  1995. });
  1996. });
  1997. });