| // Licensed to the Software Freedom Conservancy (SFC) under one |
| // or more contributor license agreements. See the NOTICE file |
| // distributed with this work for additional information |
| // regarding copyright ownership. The SFC licenses this file |
| // to you under the Apache License, Version 2.0 (the |
| // "License"); you may not use this file except in compliance |
| // with the License. You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, |
| // software distributed under the License is distributed on an |
| // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| // KIND, either express or implied. See the License for the |
| // specific language governing permissions and limitations |
| // under the License. |
| |
| goog.require('bot.ErrorCode'); |
| goog.require('goog.Promise'); |
| goog.require('goog.Uri'); |
| goog.require('goog.testing.MockControl'); |
| goog.require('goog.testing.jsunit'); |
| goog.require('goog.userAgent'); |
| goog.require('webdriver.Command'); |
| goog.require('webdriver.http.Client'); |
| goog.require('webdriver.http.Executor'); |
| goog.require('webdriver.test.testutil'); |
| |
| // Alias for readability. |
| var callbackHelper = webdriver.test.testutil.callbackHelper; |
| |
| var control = new goog.testing.MockControl(); |
| var mockClient, executor, onCallback, onErrback; |
| |
| function shouldRunTests() { |
| return !goog.userAgent.IE || goog.userAgent.isVersionOrHigher(10); |
| } |
| |
| function setUp() { |
| mockClient = control.createStrictMock(webdriver.http.Client); |
| |
| executor = new webdriver.http.Executor(mockClient); |
| } |
| |
| function tearDown() { |
| control.$tearDown(); |
| } |
| |
| function assertSuccess() { |
| onErrback.assertNotCalled('Did not expect errback'); |
| onCallback.assertCalled('Expected callback'); |
| } |
| |
| function assertFailure() { |
| onCallback.assertNotCalled('Did not expect callback'); |
| onErrback.assertCalled('Expected errback'); |
| } |
| |
| function headersToString(headers) { |
| var str = []; |
| for (var key in headers) { |
| str.push(key + ': ' + headers[key]); |
| } |
| return str.join('\n'); |
| } |
| |
| function expectRequest(method, path, data, headers) { |
| var description = method + ' ' + path + '\n' + headersToString(headers) + |
| '\n' + JSON.stringify(data); |
| |
| return mockClient.send(new goog.testing.mockmatchers.ArgumentMatcher( |
| function(request) { |
| assertEquals('wrong method', method, request.method); |
| assertEquals('wrong path', path + '', request.path); |
| webdriver.test.testutil.assertObjectEquals(data, request.data); |
| assertNull( |
| 'Wrong headers for request:\n' + description + |
| '\n Actual headers were:\n' + headersToString(request.headers), |
| goog.testing.asserts.findDifferences(headers, request.headers)); |
| return true; |
| }, description)); |
| } |
| |
| function response(status, headers, body) { |
| return new webdriver.http.Response(status, headers, body); |
| } |
| |
| function respondsWith(error, opt_response) { |
| return function() { |
| if (error) { |
| return goog.Promise.reject(error); |
| } else { |
| return goog.Promise.resolve(opt_response); |
| } |
| }; |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // |
| // Tests |
| // |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| function testBuildPath() { |
| var parameters = {'sessionId':'foo', 'url':'http://www.google.com'}; |
| var finalPath = webdriver.http.Executor.buildPath_( |
| '/session/:sessionId/url', parameters); |
| assertEquals('/session/foo/url', finalPath); |
| webdriver.test.testutil.assertObjectEquals({'url':'http://www.google.com'}, |
| parameters); |
| } |
| |
| function testBuildPath_withWebElement() { |
| var parameters = {'sessionId':'foo', 'id': {}}; |
| parameters['id']['ELEMENT'] = 'bar'; |
| |
| var finalPath = webdriver.http.Executor.buildPath_( |
| '/session/:sessionId/element/:id/click', parameters); |
| assertEquals('/session/foo/element/bar/click', finalPath); |
| webdriver.test.testutil.assertObjectEquals({}, parameters); |
| } |
| |
| function testBuildPath_throwsIfMissingParameter() { |
| assertThrows(goog.partial(webdriver.http.Executor.buildPath_, |
| '/session/:sessionId', {})); |
| |
| assertThrows(goog.partial(webdriver.http.Executor.buildPath_, |
| '/session/:sessionId/element/:id', {'sessionId': 'foo'})); |
| } |
| |
| function testBuildPath_doesNotMatchOnSegmentsThatDoNotStartWithColon() { |
| assertEquals('/session/foo:bar/baz', |
| webdriver.http.Executor.buildPath_('/session/foo:bar/baz', {})); |
| } |
| |
| function testExecute_rejectsUnrecognisedCommands() { |
| assertThrows(goog.bind(executor.execute, executor, |
| new webdriver.Command('fake-command-name'))); |
| } |
| |
| /** |
| * @param {!webdriver.Command} command The command to send. |
| * @param {!Function=} opt_onSuccess The function to check the response with. |
| */ |
| function assertSendsSuccessfully(command, opt_onSuccess) { |
| return executor.execute(command) |
| .then(function(response) { |
| control.$verifyAll(); |
| if (opt_onSuccess) { |
| opt_onSuccess(response); |
| } |
| }); |
| } |
| |
| /** |
| * @param {!webdriver.Command} command The command to send. |
| * @param {!Function=} opt_onError The function to check the error with. |
| */ |
| function assertFailsToSend(command, opt_onError) { |
| return executor.execute(command) |
| .then(fail, function(e) { |
| control.$verifyAll(); |
| if (opt_onError) { |
| opt_onError(e); |
| } |
| }); |
| } |
| |
| function testExecute_clientFailsToSendRequest() { |
| var error = new Error('boom'); |
| expectRequest('POST', '/session', {}, { |
| 'Accept': 'application/json; charset=utf-8' |
| }). |
| $does(respondsWith(error)); |
| control.$replayAll(); |
| |
| return assertFailsToSend( |
| new webdriver.Command(webdriver.CommandName.NEW_SESSION), |
| function(e) { |
| assertEquals(error, e); |
| }); |
| } |
| |
| function testExecute_commandWithNoUrlParameters() { |
| expectRequest('POST', '/session', {}, { |
| 'Accept': 'application/json; charset=utf-8' |
| }). |
| $does(respondsWith(null, response(200, {}, ''))); |
| control.$replayAll(); |
| |
| return assertSendsSuccessfully( |
| new webdriver.Command(webdriver.CommandName.NEW_SESSION)); |
| } |
| |
| function testExecute_rejectsCommandsMissingUrlParameters() { |
| var command = |
| new webdriver.Command(webdriver.CommandName.FIND_CHILD_ELEMENT). |
| setParameter('sessionId', 's123'). |
| // Let this be missing: setParameter('id', {'ELEMENT': 'e456'}). |
| setParameter('using', 'id'). |
| setParameter('value', 'foo'); |
| |
| control.$replayAll(); |
| assertThrows(goog.bind(executor.execute, executor, command)); |
| control.$verifyAll(); |
| } |
| |
| function testExecute_replacesUrlParametersWithCommandParameters() { |
| var command = |
| new webdriver.Command(webdriver.CommandName.GET). |
| setParameter('sessionId', 's123'). |
| setParameter('url', 'http://www.google.com'); |
| |
| expectRequest('POST', '/session/s123/url', |
| {'url': 'http://www.google.com'}, |
| {'Accept': 'application/json; charset=utf-8'}). |
| $does(respondsWith(null, response(200, {}, ''))); |
| control.$replayAll(); |
| |
| return assertSendsSuccessfully(command); |
| } |
| |
| function testExecute_returnsParsedJsonResponse() { |
| var responseObj = { |
| 'status': bot.ErrorCode.SUCCESS, |
| 'value': 'http://www.google.com' |
| }; |
| var command = new webdriver.Command(webdriver.CommandName.GET_CURRENT_URL). |
| setParameter('sessionId', 's123'); |
| |
| expectRequest('GET', '/session/s123/url', {}, { |
| 'Accept': 'application/json; charset=utf-8' |
| }).$does(respondsWith(null, |
| response(200, {'Content-Type': 'application/json'}, |
| JSON.stringify(responseObj)))); |
| control.$replayAll(); |
| |
| return assertSendsSuccessfully(command, function(response) { |
| webdriver.test.testutil.assertObjectEquals(responseObj, response); |
| }); |
| } |
| |
| function testExecute_returnsSuccessFor2xxWithBodyAsValueWhenNotJson() { |
| var command = new webdriver.Command(webdriver.CommandName.GET_CURRENT_URL). |
| setParameter('sessionId', 's123'); |
| |
| expectRequest('GET', '/session/s123/url', {}, { |
| 'Accept': 'application/json; charset=utf-8' |
| }).$does(respondsWith(null, |
| response(200, {}, 'hello, world\r\ngoodbye, world!'))); |
| control.$replayAll(); |
| |
| return assertSendsSuccessfully(command, function(response) { |
| webdriver.test.testutil.assertObjectEquals({ |
| 'status': bot.ErrorCode.SUCCESS, |
| 'value': 'hello, world\ngoodbye, world!' |
| }, response); |
| }); |
| } |
| |
| function testExecute_returnsSuccessFor2xxInvalidJsonBody() { |
| var invalidJson = '['; |
| expectRequest('POST', '/session', {}, { |
| 'Accept': 'application/json; charset=utf-8' |
| }). |
| $does(respondsWith(null, response(200, { |
| 'Content-Type': 'application/json' |
| }, invalidJson))); |
| control.$replayAll(); |
| |
| return assertSendsSuccessfully( |
| new webdriver.Command(webdriver.CommandName.NEW_SESSION), |
| function(response) { |
| webdriver.test.testutil.assertObjectEquals({ |
| 'status': bot.ErrorCode.SUCCESS, |
| 'value': invalidJson |
| }, response); |
| }); |
| } |
| |
| function testExecute_returnsUnknownCommandFor404WithBodyAsValueWhenNotJson() { |
| var command = new webdriver.Command(webdriver.CommandName.GET_CURRENT_URL). |
| setParameter('sessionId', 's123'); |
| |
| expectRequest('GET', '/session/s123/url', {}, { |
| 'Accept': 'application/json; charset=utf-8' |
| }).$does(respondsWith(null, |
| response(404, {}, 'hello, world\r\ngoodbye, world!'))); |
| control.$replayAll(); |
| |
| return assertSendsSuccessfully(command, function(response) { |
| webdriver.test.testutil.assertObjectEquals({ |
| 'status': bot.ErrorCode.UNKNOWN_COMMAND, |
| 'value': 'hello, world\ngoodbye, world!' |
| }, response); |
| }); |
| } |
| |
| function testExecute_returnsUnknownErrorForGenericErrorCodeWithBodyAsValueWhenNotJson() { |
| var command = new webdriver.Command(webdriver.CommandName.GET_CURRENT_URL). |
| setParameter('sessionId', 's123'); |
| |
| expectRequest('GET', '/session/s123/url', {}, { |
| 'Accept': 'application/json; charset=utf-8' |
| }).$does(respondsWith(null, |
| response(500, {}, 'hello, world\r\ngoodbye, world!'))); |
| control.$replayAll(); |
| |
| return assertSendsSuccessfully(command, function(response) { |
| webdriver.test.testutil.assertObjectEquals({ |
| 'status': bot.ErrorCode.UNKNOWN_ERROR, |
| 'value': 'hello, world\ngoodbye, world!' |
| }, response); |
| }); |
| } |
| |
| function testExecute_attemptsToParseBodyWhenNoContentTypeSpecified() { |
| var responseObj = { |
| 'status': bot.ErrorCode.SUCCESS, |
| 'value': 'http://www.google.com' |
| }; |
| var command = new webdriver.Command(webdriver.CommandName.GET_CURRENT_URL). |
| setParameter('sessionId', 's123'); |
| |
| expectRequest('GET', '/session/s123/url', {}, { |
| 'Accept': 'application/json; charset=utf-8' |
| }).$does(respondsWith(null, |
| response(200, {}, JSON.stringify(responseObj)))); |
| control.$replayAll(); |
| |
| return assertSendsSuccessfully(command, function(response) { |
| webdriver.test.testutil.assertObjectEquals(responseObj, response); |
| }); |
| } |
| |
| function testCanDefineNewCommands() { |
| executor.defineCommand('greet', 'GET', '/person/:name'); |
| |
| var command = new webdriver.Command('greet'). |
| setParameter('name', 'Bob'); |
| |
| expectRequest('GET', '/person/Bob', {}, |
| {'Accept': 'application/json; charset=utf-8'}). |
| $does(respondsWith(null, response(200, {}, ''))); |
| control.$replayAll(); |
| |
| return assertSendsSuccessfully(command); |
| } |
| |
| function testCanRedefineStandardCommands() { |
| executor.defineCommand(webdriver.CommandName.GO_BACK, |
| 'POST', '/custom/back'); |
| |
| var command = new webdriver.Command(webdriver.CommandName.GO_BACK). |
| setParameter('times', 3); |
| |
| expectRequest('POST', '/custom/back', |
| {'times': 3}, |
| {'Accept': 'application/json; charset=utf-8'}). |
| $does(respondsWith(null, response(200, {}, ''))); |
| control.$replayAll(); |
| |
| return assertSendsSuccessfully(command); |
| } |
| |
| function FakeXmlHttpRequest(headers, status, responseText) { |
| return { |
| getAllResponseHeaders: function() { return headers; }, |
| status: status, |
| responseText: responseText |
| }; |
| } |
| |
| function testXmlHttpRequestToHttpResponse_parseHeaders_windows() { |
| var response = webdriver.http.Response.fromXmlHttpRequest( |
| FakeXmlHttpRequest([ |
| 'a:b', |
| 'c: d', |
| 'e :f', |
| 'g : h' |
| ].join('\r\n'), 200, '')); |
| assertEquals(200, response.status); |
| assertEquals('', response.body); |
| |
| webdriver.test.testutil.assertObjectEquals({ |
| 'a': 'b', |
| 'c': 'd', |
| 'e': 'f', |
| 'g': 'h' |
| }, response.headers); |
| } |
| |
| function testXmlHttpRequestToHttpResponse_parseHeaders_unix() { |
| var response = webdriver.http.Response.fromXmlHttpRequest( |
| FakeXmlHttpRequest([ |
| 'a:b', |
| 'c: d', |
| 'e :f', |
| 'g : h' |
| ].join('\n'), 200, '')); |
| assertEquals(200, response.status); |
| assertEquals('', response.body); |
| |
| webdriver.test.testutil.assertObjectEquals({ |
| 'a': 'b', |
| 'c': 'd', |
| 'e': 'f', |
| 'g': 'h' |
| }, response.headers); |
| } |
| |
| function testXmlHttpRequestToHttpResponse_noHeaders() { |
| var response = webdriver.http.Response.fromXmlHttpRequest( |
| FakeXmlHttpRequest('', 200, '')); |
| assertEquals(200, response.status); |
| assertEquals('', response.body); |
| webdriver.test.testutil.assertObjectEquals({}, response.headers); |
| } |
| |
| function testXmlHttpRequestToHttpResponse_stripsNullCharactersFromBody() { |
| var response = webdriver.http.Response.fromXmlHttpRequest( |
| FakeXmlHttpRequest('', 200, '\x00\0foo\x00\x00bar\x00\0')); |
| assertEquals(200, response.status); |
| assertEquals('foobar', response.body); |
| webdriver.test.testutil.assertObjectEquals({}, response.headers); |
| } |