Skip to content

Commit 5234b32

Browse files
committed
[js] Fix new session parsing for geckodriver 0.15.0 (breaks support for older
versions) Fixes #3625
1 parent 0ca584d commit 5234b32

File tree

4 files changed

+66
-46
lines changed

4 files changed

+66
-46
lines changed

javascript/node/selenium-webdriver/CHANGES.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,22 @@
11
## v.next
22

3+
### Notice
4+
5+
This release requires [geckodriver 0.15.0](https://github.com/mozilla/geckodriver/releases/tag/v0.15.0) or newer.
6+
7+
### API Changes
8+
39
* Added `Options#getTimeouts()` for retrieving the currently configured session
410
timeouts (i.e. implicit wait). This method will only work with W3C compatible
511
WebDriver implementations.
612
* Deprecated the `Timeouts` class in favor of `Options#setTimeouts()`, which
713
supports setting multiple timeouts at once.
814

15+
### Changes for W3C WebDriver Spec Compliance
16+
17+
* Fix W3C response parsing, which expects response data to always be a JSON
18+
object with a `value` key.
19+
920

1021
## v3.3.0
1122

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

Lines changed: 42 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -429,34 +429,29 @@ class Executor {
429429
return doSend(this, request).then(response => {
430430
this.log_.finer(() => `>>>\n${request}\n<<<\n${response}`);
431431

432-
let parsed =
433-
parseHttpResponse(
434-
command, /** @type {!Response} */ (response), this.w3c);
432+
let httpResponse = /** @type {!Response} */(response);
433+
let {isW3C, value} = parseHttpResponse(command, httpResponse);
435434

436435
if (command.getName() === cmd.Name.NEW_SESSION
437436
|| command.getName() === cmd.Name.DESCRIBE_SESSION) {
438-
if (!parsed || !parsed['sessionId']) {
437+
if (!value || !value.sessionId) {
439438
throw new error.WebDriverError(
440-
'Unable to parse new session response: ' + response.body);
439+
`Unable to parse new session response: ${response.body}`);
441440
}
442441

443442
// The remote end is a W3C compliant server if there is no `status`
444443
// field in the response. This is not applicable for the DESCRIBE_SESSION
445444
// command, which is not defined in the W3C spec.
446445
if (command.getName() === cmd.Name.NEW_SESSION) {
447-
this.w3c = this.w3c || !('status' in parsed);
446+
this.w3c = this.w3c || isW3C;
448447
}
449448

450-
return new Session(parsed['sessionId'], parsed['value']);
449+
// No implementations use the `capabilities` key yet...
450+
let capabilities = value.capabilities || value.value;
451+
return new Session(value.sessionId, capabilities);
451452
}
452453

453-
if (parsed
454-
&& typeof parsed === 'object'
455-
&& 'value' in parsed) {
456-
let value = parsed['value'];
457-
return typeof value === 'undefined' ? null : value;
458-
}
459-
return parsed;
454+
return typeof value === 'undefined' ? null : value;
460455
});
461456
});
462457
}
@@ -482,40 +477,45 @@ function tryParse(str) {
482477
*
483478
* @param {!cmd.Command} command The command the response is for.
484479
* @param {!Response} httpResponse The HTTP response to parse.
485-
* @param {boolean} w3c Whether the response should be processed using the
486-
* W3C wire protocol.
487-
* @return {?} The parsed response.
480+
* @return {{isW3C: boolean, value: ?}} An object describing the parsed
481+
* response. This object will have two fields: `isW3C` indicates whether
482+
* the response looks like it came from a remote end that conforms with the
483+
* W3C WebDriver spec, and `value`, the actual response value.
488484
* @throws {WebDriverError} If the HTTP response is an error.
489485
*/
490-
function parseHttpResponse(command, httpResponse, w3c) {
491-
let parsed = tryParse(httpResponse.body);
492-
if (parsed !== undefined) {
493-
if (httpResponse.status < 200) {
494-
// This should never happen, but throw the raw response so
495-
// users report it.
496-
throw new error.WebDriverError(
497-
`Unexpected HTTP response:\n${httpResponse}`);
498-
}
486+
function parseHttpResponse(command, httpResponse) {
487+
if (httpResponse.status < 200) {
488+
// This should never happen, but throw the raw response so users report it.
489+
throw new error.WebDriverError(
490+
`Unexpected HTTP response:\n${httpResponse}`);
491+
}
499492

500-
if (w3c) {
501-
if (httpResponse.status > 399) {
502-
error.throwDecodedError(parsed);
493+
let parsed = tryParse(httpResponse.body);
494+
if (parsed && typeof parsed === 'object') {
495+
let value = parsed.value;
496+
let isW3C =
497+
value !== null && typeof value === 'object'
498+
&& typeof parsed.status === 'undefined';
499+
500+
if (!isW3C) {
501+
error.checkLegacyResponse(parsed);
502+
503+
// Adjust legacy new session responses to look like W3C to simplify
504+
// later processing.
505+
if (command.getName() === cmd.Name.NEW_SESSION
506+
|| command.getName() == cmd.Name.DESCRIBE_SESSION) {
507+
value = parsed;
503508
}
504-
return parsed;
505-
}
506509

507-
// If this is a new session command, we need to check for a W3C compliant
508-
// error object. This is necessary since a successful new session command
509-
// is what puts the executor into W3C mode.
510-
if (httpResponse.status > 399
511-
&& (command.getName() == cmd.Name.NEW_SESSION
512-
|| command.getName() === cmd.Name.DESCRIBE_SESSION)
513-
&& error.isErrorResponse(parsed)) {
514-
error.throwDecodedError(parsed);
510+
} else if (httpResponse.status > 399) {
511+
error.throwDecodedError(value);
515512
}
516513

517-
error.checkLegacyResponse(parsed);
518-
return parsed;
514+
return {isW3C, value};
515+
}
516+
517+
if (parsed !== undefined) {
518+
return {isW3C: false, value: parsed};
519519
}
520520

521521
let value = httpResponse.body.replace(/\r\n/g, '\n');
@@ -528,7 +528,7 @@ function parseHttpResponse(command, httpResponse, w3c) {
528528
throw new error.WebDriverError(value);
529529
}
530530

531-
return value || null;
531+
return {isW3C: false, value: value || null};
532532
}
533533

534534

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ var NATIVE_BROWSERS = [
5050
];
5151

5252

53+
var noBuild = /^1|true$/i.test(process.env['SELENIUM_NO_BUILD']);
5354
var serverJar = process.env['SELENIUM_SERVER_JAR'];
5455
var remoteUrl = process.env['SELENIUM_REMOTE_URL'];
5556
var useLoopback = process.env['SELENIUM_USE_LOOP_BACK'] == '1';
@@ -225,7 +226,7 @@ function suite(fn, opt_options) {
225226
try {
226227

227228
before(function() {
228-
if (isDevMode) {
229+
if (isDevMode && !noBuild) {
229230
return build.of(
230231
'//javascript/atoms/fragments:is-displayed',
231232
'//javascript/webdriver/atoms:getAttribute')

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

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -293,7 +293,14 @@ describe('http', function() {
293293
});
294294

295295
it('auto-upgrades on W3C response', function() {
296-
var rawResponse = {sessionId: 's123', value: {name: 'Bob'}};
296+
let rawResponse = {
297+
value: {
298+
sessionId: 's123',
299+
value: {
300+
name: 'Bob'
301+
}
302+
}
303+
};
297304

298305
send.returns(Promise.resolve(
299306
new http.Response(200, {}, JSON.stringify(rawResponse))));
@@ -344,7 +351,8 @@ describe('http', function() {
344351
});
345352

346353
it('handles w3c new session failures', function() {
347-
let rawResponse = {error: 'no such element', message: 'oops'};
354+
let rawResponse =
355+
{value: {error: 'no such element', message: 'oops'}};
348356

349357
send.returns(Promise.resolve(
350358
new http.Response(500, {}, JSON.stringify(rawResponse))));
@@ -429,7 +437,7 @@ describe('http', function() {
429437
});
430438

431439
it('does not auto-upgrade on W3C response', function() {
432-
var rawResponse = {sessionId: 's123', value: {name: 'Bob'}};
440+
var rawResponse = {value: {sessionId: 's123', value: {name: 'Bob'}}};
433441

434442
send.returns(Promise.resolve(
435443
new http.Response(200, {}, JSON.stringify(rawResponse))));

0 commit comments

Comments
 (0)