Files
appium/test/protocol/protocol-e2e-specs.js
T

1085 lines
34 KiB
JavaScript

// transpile:mocha
import {
server, routeConfiguringFunction, errors, JWProxy, BaseDriver
} from '../..';
import { FakeDriver } from './fake-driver';
import _ from 'lodash';
import axios from 'axios';
import chai from 'chai';
import chaiAsPromised from 'chai-as-promised';
import sinon from 'sinon';
import { StatusCodes as HTTPStatusCodes } from 'http-status-codes';
import { createProxyServer } from './helpers';
import {
MJSONWP_ELEMENT_KEY, W3C_ELEMENT_KEY
} from '../../lib/constants';
import qs from 'querystring';
let should = chai.should();
chai.use(chaiAsPromised);
const serverPort = 8181;
const baseUrl = `http://localhost:${serverPort}/wd/hub`;
describe('Protocol', function () {
//TODO: more tests!:
// Unknown commands should return 404
describe('direct to driver', function () {
let d = new FakeDriver();
it('should return response values directly from the driver', async function () {
(await d.setUrl('http://google.com')).should.contain('google');
});
});
describe('via express router', function () {
let mjsonwpServer;
let driver;
before(async function () {
driver = new FakeDriver();
driver.sessionId = 'foo';
mjsonwpServer = await server({
routeConfiguringFunction: routeConfiguringFunction(driver),
port: serverPort,
});
});
after(async function () {
await mjsonwpServer.close();
});
it('should proxy to driver and return valid jsonwp response', async function () {
const {data} = await axios({
url: `${baseUrl}/session/foo/url`,
method: 'POST',
data: {url: 'http://google.com'}
});
data.should.eql({
status: 0,
value: 'Navigated to: http://google.com',
sessionId: 'foo'
});
});
it('should assume requests without a Content-Type are json requests', async function () {
const {data} = await axios({
url: `${baseUrl}/session/foo/url`,
method: 'POST',
data: {url: 'http://google.com'},
});
data.should.eql({
status: 0,
value: 'Navigated to: http://google.com',
sessionId: 'foo'
});
});
it('should respond to x-www-form-urlencoded as well as json requests', async function () {
const {data} = await axios({
url: `${baseUrl}/session/foo/url`,
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
method: 'POST',
data: qs.stringify({
url: 'http://google.com',
}),
});
data.should.eql({
status: 0,
value: 'Navigated to: http://google.com',
sessionId: 'foo'
});
});
it('should include url request parameters for methods to use - sessionid', async function () {
const {data} = await axios({
url: `${baseUrl}/session/foo/back`,
method: 'POST',
data: {},
});
data.should.eql({
status: 0,
value: 'foo',
sessionId: 'foo'
});
});
it('should include url request parameters for methods to use - elementid', async function () {
const {data} = await axios({
url: `${baseUrl}/session/foo/element/bar/click`,
method: 'POST',
data: {},
});
data.status.should.equal(0);
data.value.should.eql(['bar', 'foo']);
});
it('should include url req params in the order: custom, element, session', async function () {
const {data} = await axios({
url: `${baseUrl}/session/foo/element/bar/attribute/baz`,
});
data.status.should.equal(0);
data.value.should.eql(['baz', 'bar', 'foo']);
});
it('should respond with 400 Bad Request if parameters missing', async function () {
const {data, status} = await axios({
url: `${baseUrl}/session/foo/url`,
method: 'POST',
data: {},
validateStatus: null,
});
status.should.equal(400);
JSON.stringify(data).should.contain('url');
});
it('should reject requests with a badly formatted body and not crash', async function () {
await axios({
url: `${baseUrl}/session/foo/url`,
method: 'POST',
data: 'oh hello'
}).should.eventually.be.rejected;
const {data} = await axios({
url: `${baseUrl}/session/foo/url`,
method: 'POST',
data: {url: 'http://google.com'}
});
data.should.eql({
status: 0,
value: 'Navigated to: http://google.com',
sessionId: 'foo'
});
});
it('should get 404 for bad routes', async function () {
await axios({
url: `${baseUrl}/blargimarg`,
}).should.eventually.be.rejectedWith(/404/);
});
it('4xx responses should have content-type of application/json', async function () {
const {headers} = await axios({
url: `${baseUrl}/blargimargarita`,
validateStatus: null,
});
headers['content-type'].should.include('application/json');
});
it('should throw not yet implemented for unfilledout commands', async function () {
const {status, data} = await axios({
url: `${baseUrl}/session/foo/element/bar/location`,
validateStatus: null,
});
status.should.equal(501);
data.should.eql({
status: 405,
value: {
message: 'Method has not yet been implemented'
},
sessionId: 'foo'
});
});
it('should throw not implemented for ignored commands', async function () {
const {status, data} = await axios({
url: `${baseUrl}/session/foo/buttonup`,
method: 'POST',
validateStatus: null,
data: {},
});
status.should.equal(501);
data.should.eql({
status: 405,
value: {
message: 'Method has not yet been implemented'
},
sessionId: 'foo'
});
});
it('should get 400 for bad parameters', async function () {
await axios({
url: `${baseUrl}/session/foo/url`,
method: 'POST',
data: {}
}).should.eventually.be.rejectedWith(/400/);
});
it('should ignore special extra payload params in the right contexts', async function () {
await axios({
url: `${baseUrl}/session/foo/element/bar/value`,
method: 'POST',
data: {id: 'baz', sessionId: 'lol', value: ['a']}
});
await axios({
url: `${baseUrl}/session/foo/element/bar/value`,
method: 'POST',
data: {id: 'baz'}
}).should.eventually.be.rejectedWith(/400/);
// make sure adding the optional 'id' doesn't clobber a route where we
// have an actual required 'id'
await axios({
url: `${baseUrl}/session/foo/frame`,
method: 'POST',
data: {id: 'baz'}
});
});
it('should return the correct error even if driver does not throw', async function () {
const {status, data} = await axios({
url: `${baseUrl}/session/foo/appium/receive_async_response`,
method: 'POST',
data: {response: 'baz'},
validateStatus: null,
});
status.should.equal(500);
data.should.eql({
status: 13,
value: {
message: 'An unknown server-side error occurred while processing ' +
'the command. Original error: Mishandled Driver Error'
},
sessionId: 'foo'
});
});
describe('w3c sendkeys migration', function () {
it('should accept value for sendkeys', async function () {
const {data} = await axios({
url: `${baseUrl}/session/foo/element/bar/value`,
method: 'POST',
data: {value: 'text to type'}
});
data.status.should.equal(0);
data.value.should.eql(['text to type', 'bar']);
});
it('should accept text for sendkeys', async function () {
const {data} = await axios({
url: `${baseUrl}/session/foo/element/bar/value`,
method: 'POST',
data: {text: 'text to type'}
});
data.status.should.equal(0);
data.value.should.eql(['text to type', 'bar']);
});
it('should accept value and text for sendkeys, and use value', async function () {
const {data} = await axios({
url: `${baseUrl}/session/foo/element/bar/value`,
method: 'POST',
data: {value: 'text to type', text: 'text to ignore'}
});
data.status.should.equal(0);
data.value.should.eql(['text to type', 'bar']);
});
});
describe('multiple sets of arguments', function () {
describe('optional', function () {
it('should allow moveto with element', async function () {
const {data} = await axios({
url: `${baseUrl}/session/foo/moveto`,
method: 'POST',
data: {element: '3'}
});
data.status.should.equal(0);
data.value.should.eql(['3', null, null]);
});
it('should allow moveto with xoffset/yoffset', async function () {
const {data} = await axios({
url: `${baseUrl}/session/foo/moveto`,
method: 'POST',
data: {xoffset: 42, yoffset: 17}
});
data.status.should.equal(0);
data.value.should.eql([null, 42, 17]);
});
});
describe('required', function () {
it('should allow removeApp with appId', async function () {
const {data} = await axios({
url: `${baseUrl}/session/foo/appium/device/remove_app`,
method: 'POST',
data: {appId: 42}
});
data.status.should.equal(0);
data.value.should.eql(42);
});
it('should allow removeApp with bundleId', async function () {
const {data} = await axios({
url: `${baseUrl}/session/foo/appium/device/remove_app`,
method: 'POST',
data: {bundleId: 42}
});
data.status.should.equal(0);
data.value.should.eql(42);
});
});
});
describe('default param wrap', function () {
it('should wrap', async function () {
const {data} = await axios({
url: `${baseUrl}/session/foo/touch/perform`,
method: 'POST',
data: [{'action': 'tap', 'options': {'element': '3'}}]
});
data.value.should.deep.equal([[{'action': 'tap', 'options': {'element': '3'}}], 'foo']);
});
it('should not wrap twice', async function () {
const {data} = await axios({
url: `${baseUrl}/session/foo/touch/perform`,
method: 'POST',
data: {actions: [{'action': 'tap', 'options': {'element': '3'}}]}
});
data.value.should.deep.equal([[{'action': 'tap', 'options': {'element': '3'}}], 'foo']);
});
});
describe('create sessions via HTTP endpoint', function () {
let desiredCapabilities = {a: 'b'};
let requiredCapabilities = {c: 'd'};
let capabilities = {e: 'f'};
let sessionId;
beforeEach(function () {
sessionId = null;
});
afterEach(async function () {
if (sessionId) {
await axios.delete(`${baseUrl}/session/${sessionId}`);
}
});
it('should allow create session with desired caps (MJSONWP)', async function () {
const {data} = await axios({
url: `${baseUrl}/session`,
method: 'POST',
data: {desiredCapabilities}
});
sessionId = data.sessionId;
data.status.should.equal(0);
data.value.should.eql(desiredCapabilities);
});
it('should allow create session with desired and required caps', async function () {
const {data} = await axios({
url: `${baseUrl}/session`,
method: 'POST',
data: {
desiredCapabilities,
requiredCapabilities
}
});
sessionId = data.sessionId;
data.status.should.equal(0);
data.value.should.eql(_.extend({}, desiredCapabilities, requiredCapabilities));
});
it('should fail to create session without capabilities or desiredCapabilities', async function () {
await axios({
url: `${baseUrl}/session`,
method: 'POST',
data: {},
}).should.eventually.be.rejectedWith(/400/);
});
it('should allow create session with capabilities (W3C)', async function () {
const {data} = await axios({
url: `${baseUrl}/session`,
method: 'POST',
data: {
capabilities,
}
});
sessionId = data.sessionId;
should.not.exist(data.status);
should.not.exist(data.sessionId);
data.value.capabilities.should.eql(capabilities);
data.value.sessionId.should.exist;
});
it('should fall back to MJSONWP if driver does not support W3C yet', async function () {
const createSessionStub = sinon.stub(driver, 'createSession').callsFake(function (capabilities) {
driver.sessionId = null;
return BaseDriver.prototype.createSession.call(driver, capabilities);
});
try {
let caps = {
...desiredCapabilities,
platformName: 'Fake',
deviceName: 'Fake',
};
// let {status, value, sessionId} = await request({
const {data} = await axios({
url: `${baseUrl}/session`,
method: 'POST',
data: {
desiredCapabilities: caps,
capabilities: {
alwaysMatch: caps,
firstMatch: [{}],
},
}
});
sessionId = data.sessionId;
should.exist(data.status);
should.exist(data.sessionId);
data.value.should.eql(caps);
} finally {
createSessionStub.restore();
}
});
describe('w3c endpoints', function () {
let w3cCaps = {
alwaysMatch: {
platformName: 'Fake',
deviceName: 'Commodore 64',
},
firstMatch: [{}],
};
let sessionUrl;
beforeEach(async function () {
// Start a W3C session
const {value} = (await axios({
url: `${baseUrl}/session`,
method: 'POST',
data: {
capabilities: w3cCaps,
},
})).data;
sessionId = value.sessionId;
sessionUrl = `${baseUrl}/session/${sessionId}`;
});
it(`should throw 400 Bad Parameters exception if the parameters are bad`, async function () {
const {status, data} = await axios({
url: `${sessionUrl}/actions`,
method: 'POST',
validateStatus: null,
data: {
bad: 'params',
}
});
status.should.equal(400);
const {error: w3cError, message, stacktrace} = data.value;
message.should.match(/Parameters were incorrect/);
stacktrace.should.match(/protocol.js/);
w3cError.should.be.a.string;
w3cError.should.equal(errors.InvalidArgumentError.error());
});
it(`should throw 405 exception if the command hasn't been implemented yet`, async function () {
const {status, data} = await axios({
url: `${sessionUrl}/actions`,
method: 'POST',
validateStatus: null,
data: {
actions: [],
},
});
status.should.equal(405);
const {error: w3cError, message, stacktrace} = data.value;
message.should.match(/Method has not yet been implemented/);
stacktrace.should.match(/protocol.js/);
w3cError.should.be.a.string;
w3cError.should.equal(errors.NotYetImplementedError.error());
message.should.match(/Method has not yet been implemented/);
});
it(`should throw 500 Unknown Error if the command throws an unexpected exception`, async function () {
driver.performActions = () => { throw new Error(`Didn't work`); };
const {status, data} = await axios({
url: `${sessionUrl}/actions`,
method: 'POST',
validateStatus: null,
data: {
actions: [],
}
});
status.should.equal(500);
const {error: w3cError, message, stacktrace} = data.value;
stacktrace.should.match(/protocol.js/);
w3cError.should.be.a.string;
w3cError.should.equal(errors.UnknownError.error());
message.should.match(/Didn't work/);
delete driver.performActions;
});
it(`should translate element format from MJSONWP to W3C`, async function () {
const retValue = [
{
something: {
[MJSONWP_ELEMENT_KEY]: 'fooo',
other: 'bar'
}
}, {
[MJSONWP_ELEMENT_KEY]: 'bar'
},
'ignore',
];
const expectedValue = [
{
something: {
[MJSONWP_ELEMENT_KEY]: 'fooo',
[W3C_ELEMENT_KEY]: 'fooo',
other: 'bar'
}
}, {
[MJSONWP_ELEMENT_KEY]: 'bar',
[W3C_ELEMENT_KEY]: 'bar'
},
'ignore',
];
const findElementsBackup = driver.findElements;
driver.findElements = () => retValue;
const {data} = await axios.post(`${sessionUrl}/elements`, {
using: 'whatever',
value: 'whatever',
});
data.value.should.eql(expectedValue);
driver.findElements = findElementsBackup;
});
it(`should fail with a 408 error if it throws a TimeoutError exception`, async function () {
let setUrlStub = sinon.stub(driver, 'setUrl').callsFake(function () {
throw new errors.TimeoutError;
});
const {status, data} = await axios({
url: `${sessionUrl}/url`,
method: 'POST',
validateStatus: null,
data: {
url: 'https://example.com/',
}
});
status.should.equal(408);
const {error: w3cError, message, stacktrace} = data.value;
stacktrace.should.match(/protocol.js/);
w3cError.should.be.a.string;
w3cError.should.equal(errors.TimeoutError.error());
message.should.match(/An operation did not complete before its timeout expired/);
setUrlStub.restore();
});
it(`should pass with 200 HTTP status code if the command returns a value`, async function () {
driver.performActions = (actions) => 'It works ' + actions.join('');
const {status, value, sessionId} = (await axios.post(`${sessionUrl}/actions`, {
actions: ['a', 'b', 'c'],
})).data;
should.not.exist(sessionId);
should.not.exist(status);
value.should.equal('It works abc');
delete driver.performActions;
});
describe('jwproxy', function () {
const port = 56562;
let server, jwproxy, app;
beforeEach(function () {
const res = createProxyServer(sessionId, port);
server = res.server;
app = res.app;
jwproxy = new JWProxy({host: 'localhost', port});
jwproxy.sessionId = sessionId;
driver.performActions = async (actions) => await jwproxy.command('/perform-actions', 'POST', actions);
});
afterEach(async function () {
delete driver.performActions;
await server.close();
});
it('should work if a proxied request returns a response with status 200', async function () {
app.post('/wd/hub/session/:sessionId/perform-actions', (req, res) => {
res.json({
sessionId: req.params.sessionId,
value: req.body,
status: 0,
});
});
const {status, value, sessionId} = (await axios.post(`${sessionUrl}/actions`, {
actions: [1, 2, 3],
})).data;
value.should.eql([1, 2, 3]);
should.not.exist(status);
should.not.exist(sessionId);
});
it('should return error if a proxied request returns a MJSONWP error response', async function () {
app.post('/wd/hub/session/:sessionId/perform-actions', (req, res) => {
res.status(500).json({
sessionId,
status: 6,
value: 'A problem occurred',
});
});
const {status, data} = await axios({
url: `${sessionUrl}/actions`,
method: 'POST',
validateStatus: null,
data: {
actions: [1, 2, 3],
}
});
status.should.equal(HTTPStatusCodes.NOT_FOUND);
JSON.stringify(data).should.match(/A problem occurred/);
});
it('should return W3C error if a proxied request returns a W3C error response', async function () {
const error = new Error(`Some error occurred`);
error.w3cStatus = 414;
const executeCommandStub = sinon.stub(driver, 'executeCommand').returns({
protocol: 'W3C',
error,
});
const {status, data} = await axios({
url: `${sessionUrl}/actions`,
method: 'POST',
validateStatus: null,
data: {actions: [1, 2, 3]},
});
status.should.equal(414);
const {error: w3cError, message: errMessage, stacktrace} = data.value;
w3cError.should.equal('unknown error');
stacktrace.should.match(/Some error occurred/);
errMessage.should.equal('Some error occurred');
executeCommandStub.restore();
});
it('should return error if a proxied request returns a MJSONWP error response but HTTP status code is 200', async function () {
app.post('/wd/hub/session/:sessionId/perform-actions', (req, res) => {
res.status(200).json({
sessionId: 'Fake Session Id',
status: 7,
value: 'A problem occurred',
});
});
const {status, data} = await axios({
url: `${sessionUrl}/actions`,
method: 'POST',
validateStatus: null,
data: {
actions: [1, 2, 3],
}
});
status.should.equal(HTTPStatusCodes.NOT_FOUND);
const {error: w3cError, message: errMessage, stacktrace} = data.value;
w3cError.should.equal('no such element');
errMessage.should.match(/A problem occurred/);
stacktrace.should.exist;
});
it('should return error if a proxied request returns a W3C error response', async function () {
app.post('/wd/hub/session/:sessionId/perform-actions', (req, res) => {
res.status(404).json({
value: {
error: 'no such element',
message: 'does not make a difference',
stacktrace: 'arbitrary stacktrace',
},
});
});
const {status, data} = await axios({
url: `${sessionUrl}/actions`,
method: 'POST',
validateStatus: null,
data: {
actions: [1, 2, 3],
}
});
status.should.equal(HTTPStatusCodes.NOT_FOUND);
const {error: w3cError, stacktrace} = data.value;
w3cError.should.equal('no such element');
stacktrace.should.match(/arbitrary stacktrace/);
});
it('should return an error if a proxied request returns a W3C error response', async function () {
app.post('/wd/hub/session/:sessionId/perform-actions', (req, res) => {
res.set('Connection', 'close');
res.status(444).json({
value: {
error: 'bogus error code',
message: 'does not make a difference',
stacktrace: 'arbitrary stacktrace',
},
});
});
const {status, data} = await axios({
url: `${sessionUrl}/actions`,
method: 'POST',
validateStatus: null,
data: {
actions: [1, 2, 3],
}
});
status.should.equal(HTTPStatusCodes.INTERNAL_SERVER_ERROR);
const {error: w3cError, stacktrace} = data.value;
w3cError.should.equal('unknown error');
stacktrace.should.match(/arbitrary stacktrace/);
});
});
});
});
it('should handle commands with no response values', async function () {
const {data} = await axios({
url: `${baseUrl}/session/foo/forward`,
method: 'POST',
});
data.should.eql({
status: 0,
value: null,
sessionId: 'foo'
});
});
it('should allow empty string response values', async function () {
const {data} = await axios({
url: `${baseUrl}/session/foo/element/bar/text`,
});
data.should.eql({
status: 0,
value: '',
sessionId: 'foo'
});
});
it('should send 500 response and an Unknown object for rejected commands', async function () {
const {status, data} = await axios({
url: `${baseUrl}/session/foo/refresh`,
method: 'POST',
validateStatus: null,
});
status.should.equal(500);
data.should.eql({
status: 13,
value: {
message: 'An unknown server-side error occurred while processing ' +
'the command. Original error: Too Fresh!'
},
sessionId: 'foo'
});
});
it('should not throw UnknownError when known', async function () {
const {status, data} = await axios({
url: `${baseUrl}/session/foo`,
validateStatus: null,
});
status.should.equal(404);
data.should.eql({
status: 6,
value: {
message: 'A session is either terminated or not started'
},
sessionId: 'foo'
});
});
});
describe('session Ids', function () {
let driver = new FakeDriver();
let mjsonwpServer;
before(async function () {
mjsonwpServer = await server({
routeConfiguringFunction: routeConfiguringFunction(driver),
port: serverPort,
});
});
after(async function () {
await mjsonwpServer.close();
});
afterEach(function () {
driver.sessionId = null;
});
it('should return null SessionId for commands without sessionIds', async function () {
const {data} = await axios({
url: `${baseUrl}/status`,
});
should.equal(data.sessionId, null);
});
it('responds with the same session ID in the request', async function () {
let sessionId = 'Vader Sessions';
driver.sessionId = sessionId;
const {data} = await axios({
url: `${baseUrl}/session/${sessionId}/url`,
method: 'POST',
data: {url: 'http://google.com'}
});
should.exist(data.sessionId);
data.sessionId.should.eql(sessionId);
});
it('yells if no session exists', async function () {
let sessionId = 'Vader Sessions';
const {data, status} = await axios({
url: `${baseUrl}/session/${sessionId}/url`,
method: 'POST',
validateStatus: null,
data: {url: 'http://google.com'},
});
status.should.equal(404);
data.status.should.equal(6);
data.value.message.should.contain('session');
});
it('yells if invalid session is sent', async function () {
let sessionId = 'Vader Sessions';
driver.sessionId = 'recession';
const {data, status} = await axios({
url: `${baseUrl}/session/${sessionId}/url`,
method: 'POST',
validateStatus: null,
data: {url: 'http://google.com'},
});
status.should.equal(404);
data.status.should.equal(6);
data.value.message.should.contain('session');
});
it('should have session IDs in error responses', async function () {
let sessionId = 'Vader Sessions';
driver.sessionId = sessionId;
const {data, status} = await axios({
url: `${baseUrl}/session/${sessionId}/refresh`,
method: 'POST',
validateStatus: null,
});
status.should.equal(500);
data.should.eql({
status: 13,
value: {
message: 'An unknown server-side error occurred while processing ' +
'the command. Original error: Too Fresh!'
},
sessionId
});
});
it('should return a new session ID on create', async function () {
const {data} = await axios({
url: `${baseUrl}/session`,
method: 'POST',
data: {desiredCapabilities: {greeting: 'hello'}, requiredCapabilities: {valediction: 'bye'}}
});
should.exist(data.sessionId);
data.sessionId.indexOf('fakeSession_').should.equal(0);
data.value.should.eql({greeting: 'hello', valediction: 'bye'});
});
});
describe('via drivers jsonwp proxy', function () {
let driver;
let sessionId = 'foo';
let mjsonwpServer;
beforeEach(async function () {
driver = new FakeDriver();
driver.sessionId = sessionId;
driver.proxyActive = () => true;
driver.canProxy = () => true;
mjsonwpServer = await server({
routeConfiguringFunction: routeConfiguringFunction(driver),
port: serverPort,
});
});
afterEach(async function () {
await mjsonwpServer.close();
});
it('should give a nice error if proxying is set but no proxy function exists', async function () {
driver.canProxy = () => false;
const {status, data} = await axios({
url: `${baseUrl}/session/${sessionId}/url`,
method: 'POST',
validateStatus: null,
data: {url: 'http://google.com'},
});
status.should.equal(500);
data.should.eql({
status: 13,
value: {
message: 'An unknown server-side error occurred while processing ' +
'the command. Original error: Trying to proxy to a JSONWP ' +
'server but driver is unable to proxy'
},
sessionId
});
});
it('should pass on any errors in proxying', async function () {
driver.proxyReqRes = async function () { // eslint-disable-line require-await
throw new Error('foo');
};
const {status, data} = await axios({
url: `${baseUrl}/session/${sessionId}/url`,
method: 'POST',
validateStatus: null,
data: {url: 'http://google.com'},
});
status.should.equal(500);
data.should.eql({
status: 13,
value: {
message: 'An unknown server-side error occurred while processing ' +
'the command. Original error: Could not proxy. Proxy ' +
'error: foo'
},
sessionId
});
});
it('should able to throw ProxyRequestError in proxying', async function () {
driver.proxyReqRes = async function () { // eslint-disable-line require-await
let jsonwp = {status: 35, value: 'No such context found.', sessionId: 'foo'};
throw new errors.ProxyRequestError(`Could not proxy command to remote server. `, jsonwp);
};
const {status, data} = await axios({
url: `${baseUrl}/session/${sessionId}/url`,
method: 'POST',
validateStatus: null,
data: {url: 'http://google.com'},
});
status.should.equal(500);
data.should.eql({
status: 35,
value: {
message: 'No such context found.'
},
sessionId: 'foo'
});
});
it('should let the proxy handle req/res', async function () {
driver.proxyReqRes = async function (req, res) { // eslint-disable-line require-await
res.status(200).json({custom: 'data'});
};
const {status, data} = await axios({
url: `${baseUrl}/session/${sessionId}/url`,
method: 'POST',
data: {url: 'http://google.com'}
});
status.should.equal(200);
data.should.eql({custom: 'data'});
});
it('should avoid jsonwp proxying when path matches avoidance list', async function () {
driver.getProxyAvoidList = () => [['POST', new RegExp('^/session/[^/]+/url$')]];
const {status, data} = await axios({
url: `${baseUrl}/session/${sessionId}/url`,
method: 'POST',
data: {url: 'http://google.com'},
});
status.should.equal(200);
data.should.eql({
status: 0,
value: 'Navigated to: http://google.com',
sessionId
});
});
it('should fail if avoid proxy list is malformed in some way', async function () {
async function badProxyAvoidanceList (list) {
driver.getProxyAvoidList = () => list;
const {status, data} = await axios({
url: `${baseUrl}/session/${sessionId}/url`,
method: 'POST',
validateStatus: null,
data: {url: 'http://google.com'},
});
status.should.equal(500);
data.status.should.equal(13);
data.value.message.should.contain('roxy');
}
const lists = [
'foo',
[['foo']],
[['BAR', /lol/]],
[['GET', 'foo']]
];
for (let list of lists) {
await badProxyAvoidanceList(list);
}
});
it('should avoid proxying non-session commands even if not in the list', async function () {
driver.getProxyAvoidList = () => [['POST', new RegExp('')]];
const {status, data} = await axios({
url: `${baseUrl}/status`,
});
status.should.equal(200);
data.should.eql({
status: 0,
value: "I'm fine",
sessionId: null
});
});
it('should avoid proxying deleteSession commands', async function () {
driver.getProxyAvoidList = () => [['POST', new RegExp('')]];
driver.sessionId.should.equal(sessionId);
const {status} = await axios.delete(`${baseUrl}/session/${sessionId}`);
status.should.equal(200);
should.not.exist(driver.sessionId);
driver.jwpProxyActive.should.be.false;
});
});
});