Skip to content

Commit 0ca584d

Browse files
committed
[js] Use the W3C set timeouts format. If this fails, fallback to the legacy
format. This commit also updates the API to expose getTimeouts() and setTimeouts() methods off of the Options class. The current Timeouts class is deprecated in favor of setTimeouts(), which allows setting multiple timeouts at once. For #3607
1 parent 4e4d599 commit 0ca584d

File tree

5 files changed

+228
-11
lines changed

5 files changed

+228
-11
lines changed

javascript/node/selenium-webdriver/CHANGES.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,12 @@
1+
## v.next
2+
3+
* Added `Options#getTimeouts()` for retrieving the currently configured session
4+
timeouts (i.e. implicit wait). This method will only work with W3C compatible
5+
WebDriver implementations.
6+
* Deprecated the `Timeouts` class in favor of `Options#setTimeouts()`, which
7+
supports setting multiple timeouts at once.
8+
9+
110
## v3.3.0
211

312
* Added warning log messages when the user creates new managed promises, or

javascript/node/selenium-webdriver/lib/command.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,8 @@ const Name = {
150150
TAKE_ELEMENT_SCREENSHOT: 'takeElementScreenshot',
151151
IMPLICITLY_WAIT: 'implicitlyWait',
152152
SET_SCRIPT_TIMEOUT: 'setScriptTimeout',
153+
154+
GET_TIMEOUT: 'getTimeout',
153155
SET_TIMEOUT: 'setTimeout',
154156

155157
ACCEPT_ALERT: 'acceptAlert',

javascript/node/selenium-webdriver/lib/http.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,7 @@ const COMMAND_MAP = new Map([
225225
[cmd.Name.EXECUTE_SCRIPT, post('/session/:sessionId/execute')],
226226
[cmd.Name.EXECUTE_ASYNC_SCRIPT, post('/session/:sessionId/execute_async')],
227227
[cmd.Name.SCREENSHOT, get('/session/:sessionId/screenshot')],
228+
[cmd.Name.GET_TIMEOUT, get('/session/:sessionId/timeouts')],
228229
[cmd.Name.SET_TIMEOUT, post('/session/:sessionId/timeouts')],
229230
[cmd.Name.MOVE_TO, post('/session/:sessionId/moveto')],
230231
[cmd.Name.CLICK, post('/session/:sessionId/click')],

javascript/node/selenium-webdriver/lib/webdriver.js

Lines changed: 114 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1326,6 +1326,91 @@ class Options {
13261326
});
13271327
}
13281328

1329+
/**
1330+
* Schedules a command to fetch the timeouts currently configured for the
1331+
* current session.
1332+
*
1333+
* @return {!promise.Thenable<{script: number,
1334+
* pageLoad: number,
1335+
* implicit: number}>} A promise that will be
1336+
* resolved with the timeouts currently configured for the current
1337+
* session.
1338+
* @see #setTimeouts()
1339+
*/
1340+
getTimeouts() {
1341+
return this.driver_.schedule(
1342+
new command.Command(command.Name.GET_TIMEOUT),
1343+
`WebDriver.manage().getTimeouts()`)
1344+
}
1345+
1346+
/**
1347+
* Schedules a command to set timeout durations associated with the current
1348+
* session.
1349+
*
1350+
* The following timeouts are supported (all timeouts are specified in
1351+
* milliseconds):
1352+
*
1353+
* - `implicit` specifies the maximum amount of time to wait for an element
1354+
* locator to succeed when {@linkplain WebDriver#findElement locating}
1355+
* {@linkplain WebDriver#findElements elements} on the page.
1356+
* Defaults to 0 milliseconds.
1357+
*
1358+
* - `pageLoad` specifies the maximum amount of time to wait for a page to
1359+
* finishing loading. Defaults to 300000 milliseconds.
1360+
*
1361+
* - `script` specifies the maximum amount of time to wait for an
1362+
* {@linkplain WebDriver#executeScript evaluated script} to run. If set to
1363+
* `null`, the script timeout will be indefinite.
1364+
* Defaults to 30000 milliseconds.
1365+
*
1366+
* @param {{script: (number|null|undefined),
1367+
* pageLoad: (number|null|undefined),
1368+
* implicit: (number|null|undefined)}} conf
1369+
* The desired timeout configuration.
1370+
* @return {!promise.Thenable<void>} A promise that will be resolved when the
1371+
* timeouts have been set.
1372+
* @throws {!TypeError} if an invalid options object is provided.
1373+
* @see #getTimeouts()
1374+
* @see <https://w3c.github.io/webdriver/webdriver-spec.html#dfn-set-timeouts>
1375+
*/
1376+
setTimeouts({script, pageLoad, implicit} = {}) {
1377+
let cmd = new command.Command(command.Name.SET_TIMEOUT);
1378+
1379+
let valid = false;
1380+
function setParam(key, value) {
1381+
if (value === null || typeof value === 'number') {
1382+
valid = true;
1383+
cmd.setParameter(key, value);
1384+
} else if (typeof value !== 'undefined') {
1385+
throw TypeError(
1386+
'invalid timeouts configuration:'
1387+
+ ` expected "${key}" to be a number, got ${typeof value}`);
1388+
}
1389+
}
1390+
setParam('implicit', implicit);
1391+
setParam('pageLoad', pageLoad);
1392+
setParam('script', script);
1393+
1394+
if (valid) {
1395+
return this.driver_.schedule(cmd, `WebDriver.manage().setTimeouts()`)
1396+
.catch(() => {
1397+
// Fallback to the legacy method.
1398+
let cmds = [];
1399+
if (typeof script === 'number') {
1400+
cmds.push(legacyTimeout(this.driver_, 'script', script));
1401+
}
1402+
if (typeof implicit === 'number') {
1403+
cmds.push(legacyTimeout(this.driver_, 'implicit', implicit));
1404+
}
1405+
if (typeof pageLoad === 'number') {
1406+
cmds.push(legacyTimeout(this.driver_, 'page load', pageLoad));
1407+
}
1408+
return Promise.all(cmds);
1409+
});
1410+
}
1411+
throw TypeError('no timeouts specified');
1412+
}
1413+
13291414
/**
13301415
* @return {!Logs} The interface for managing driver
13311416
* logs.
@@ -1336,6 +1421,7 @@ class Options {
13361421

13371422
/**
13381423
* @return {!Timeouts} The interface for managing driver timeouts.
1424+
* @deprecated Use {@link #setTimeouts()} instead.
13391425
*/
13401426
timeouts() {
13411427
return new Timeouts(this.driver_);
@@ -1350,6 +1436,22 @@ class Options {
13501436
}
13511437

13521438

1439+
/**
1440+
* @param {!WebDriver} driver
1441+
* @param {string} type
1442+
* @param {number} ms
1443+
* @return {!promise.Thenable<void>}
1444+
*/
1445+
function legacyTimeout(driver, type, ms) {
1446+
return driver.schedule(
1447+
new command.Command(command.Name.SET_TIMEOUT)
1448+
.setParameter('type', type)
1449+
.setParameter('ms', ms),
1450+
`WebDriver.manage().setTimeouts({${type}: ${ms}})`);
1451+
}
1452+
1453+
1454+
13531455
/**
13541456
* A record object describing a browser cookie.
13551457
*
@@ -1432,6 +1534,9 @@ Options.Cookie.prototype.expiry;
14321534
*
14331535
* webdriver.manage().timeouts()
14341536
*
1537+
* @deprecated This has been deprecated in favor of
1538+
* {@link Options#setTimeouts()}, which supports setting multiple timeouts
1539+
* at once.
14351540
* @see WebDriver#manage()
14361541
* @see Options#timeouts()
14371542
*/
@@ -1465,9 +1570,11 @@ class Timeouts {
14651570
* @param {number} ms The amount of time to wait, in milliseconds.
14661571
* @return {!promise.Thenable<void>} A promise that will be resolved
14671572
* when the implicit wait timeout has been set.
1573+
* @deprecated Use {@link Options#setTimeouts()
1574+
* driver.manage().setTimeouts({implicit: ms})}.
14681575
*/
14691576
implicitlyWait(ms) {
1470-
return this._scheduleCommand(ms, 'implicit', 'implicitlyWait');
1577+
return this.driver_.manage().setTimeouts({implicit: ms});
14711578
}
14721579

14731580
/**
@@ -1478,9 +1585,11 @@ class Timeouts {
14781585
* @param {number} ms The amount of time to wait, in milliseconds.
14791586
* @return {!promise.Thenable<void>} A promise that will be resolved
14801587
* when the script timeout has been set.
1588+
* @deprecated Use {@link Options#setTimeouts()
1589+
* driver.manage().setTimeouts({script: ms})}.
14811590
*/
14821591
setScriptTimeout(ms) {
1483-
return this._scheduleCommand(ms, 'script', 'setScriptTimeout');
1592+
return this.driver_.manage().setTimeouts({script: ms});
14841593
}
14851594

14861595
/**
@@ -1491,17 +1600,11 @@ class Timeouts {
14911600
* @param {number} ms The amount of time to wait, in milliseconds.
14921601
* @return {!promise.Thenable<void>} A promise that will be resolved
14931602
* when the timeout has been set.
1603+
* @deprecated Use {@link Options#setTimeouts()
1604+
* driver.manage().setTimeouts({pageLoad: ms})}.
14941605
*/
14951606
pageLoadTimeout(ms) {
1496-
return this._scheduleCommand(ms, 'page load', 'pageLoadTimeout');
1497-
}
1498-
1499-
_scheduleCommand(ms, timeoutIdentifier, timeoutName) {
1500-
return this.driver_.schedule(
1501-
new command.Command(command.Name.SET_TIMEOUT).
1502-
setParameter('type', timeoutIdentifier).
1503-
setParameter('ms', ms),
1504-
`WebDriver.manage().timeouts().${timeoutName}(${ms})`);
1607+
return this.driver_.manage().setTimeouts({pageLoad: ms});
15051608
}
15061609
}
15071610

javascript/node/selenium-webdriver/test/lib/webdriver_test.js

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1952,6 +1952,108 @@ describe('WebDriver', function() {
19521952
});
19531953
});
19541954

1955+
describe('manage()', function() {
1956+
describe('setTimeouts()', function() {
1957+
describe('throws if no timeouts are specified', function() {
1958+
let driver;
1959+
before(() => driver = new FakeExecutor().createDriver());
1960+
1961+
it('; no arguments', function() {
1962+
assert.throws(() => driver.manage().setTimeouts(), TypeError);
1963+
});
1964+
1965+
it('; ignores unrecognized timeout keys', function() {
1966+
assert.throws(
1967+
() => driver.manage().setTimeouts({foo: 123}), TypeError);
1968+
});
1969+
1970+
it('; ignores positional arguments', function() {
1971+
assert.throws(
1972+
() => driver.manage().setTimeouts(1234, 56), TypeError);
1973+
});
1974+
});
1975+
1976+
describe('throws timeout is not a number, null, or undefined', () => {
1977+
let driver;
1978+
before(() => driver = new FakeExecutor().createDriver());
1979+
1980+
function checkError(e) {
1981+
return e instanceof TypeError
1982+
&& /expected "(script|pageLoad|implicit)" to be a number/.test(
1983+
e.message);
1984+
}
1985+
1986+
it('script', function() {
1987+
assert.throws(
1988+
() => driver.manage().setTimeouts({script: 'abc'}),
1989+
checkError);
1990+
});
1991+
1992+
it('pageLoad', function() {
1993+
assert.throws(
1994+
() => driver.manage().setTimeouts({pageLoad: 'abc'}),
1995+
checkError);
1996+
});
1997+
1998+
it('implicit', function() {
1999+
assert.throws(
2000+
() => driver.manage().setTimeouts({implicit: 'abc'}),
2001+
checkError);
2002+
});
2003+
});
2004+
2005+
it('can set multiple timeouts', function() {
2006+
let executor = new FakeExecutor()
2007+
.expect(CName.SET_TIMEOUT, {script:1, pageLoad: 2, implicit: 3})
2008+
.andReturnSuccess()
2009+
.end();
2010+
let driver = executor.createDriver();
2011+
return driver.manage()
2012+
.setTimeouts({script: 1, pageLoad: 2, implicit: 3});
2013+
});
2014+
2015+
it('falls back to legacy wire format if W3C version fails', () => {
2016+
let executor = new FakeExecutor()
2017+
.expect(CName.SET_TIMEOUT, {implicit: 3})
2018+
.andReturnError(Error('oops'))
2019+
.expect(CName.SET_TIMEOUT, {type: 'implicit', ms: 3})
2020+
.andReturnSuccess()
2021+
.end();
2022+
let driver = executor.createDriver();
2023+
return driver.manage().setTimeouts({implicit: 3});
2024+
});
2025+
2026+
describe('deprecated API calls setTimeouts()', function() {
2027+
it('implicitlyWait()', function() {
2028+
let executor = new FakeExecutor()
2029+
.expect(CName.SET_TIMEOUT, {implicit: 3})
2030+
.andReturnSuccess()
2031+
.end();
2032+
let driver = executor.createDriver();
2033+
return driver.manage().timeouts().implicitlyWait(3);
2034+
});
2035+
2036+
it('setScriptTimeout()', function() {
2037+
let executor = new FakeExecutor()
2038+
.expect(CName.SET_TIMEOUT, {script: 3})
2039+
.andReturnSuccess()
2040+
.end();
2041+
let driver = executor.createDriver();
2042+
return driver.manage().timeouts().setScriptTimeout(3);
2043+
});
2044+
2045+
it('pageLoadTimeout()', function() {
2046+
let executor = new FakeExecutor()
2047+
.expect(CName.SET_TIMEOUT, {pageLoad: 3})
2048+
.andReturnSuccess()
2049+
.end();
2050+
let driver = executor.createDriver();
2051+
return driver.manage().timeouts().pageLoadTimeout(3);
2052+
});
2053+
});
2054+
});
2055+
});
2056+
19552057
describe('generator support', function() {
19562058
var driver;
19572059

0 commit comments

Comments
 (0)