mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 01:38:56 -04:00
* Created general driver to accept an argument select the driver to run. * Added environment variable for driver, changed package.json to use custim leadfoot, and made changes to browserdriver to use any driver. * Made changes per PR. * Fixed all nits.
This commit is contained in:
parent
73718c54fd
commit
0da5bacd28
10 changed files with 144 additions and 47 deletions
|
@ -270,6 +270,7 @@
|
|||
"event-stream": "3.3.2",
|
||||
"expect.js": "0.3.1",
|
||||
"faker": "1.1.0",
|
||||
"geckodriver": "1.10.0",
|
||||
"getopts": "2.0.0",
|
||||
"globby": "^8.0.1",
|
||||
"grunt": "1.0.1",
|
||||
|
@ -296,7 +297,7 @@
|
|||
"karma-junit-reporter": "1.2.0",
|
||||
"karma-mocha": "1.3.0",
|
||||
"karma-safari-launcher": "1.0.0",
|
||||
"leadfoot": "1.7.1",
|
||||
"leadfoot": "silne30/leadfoot#validation_for_response_in_ff58",
|
||||
"license-checker": "^16.0.0",
|
||||
"listr": "^0.14.1",
|
||||
"load-grunt-config": "0.19.2",
|
||||
|
|
|
@ -127,6 +127,11 @@ export const schema = Joi.object().keys({
|
|||
url: Joi.string().uri({ scheme: /https?/ }).default('http://localhost:9515')
|
||||
}).default(),
|
||||
|
||||
firefoxdriver: Joi.object().keys({
|
||||
url: Joi.string().uri({ scheme: /https?/ }).default('http://localhost:2828')
|
||||
}).default(),
|
||||
|
||||
|
||||
// definition of apps that work with `common.navigateToApp()`
|
||||
apps: Joi.object().pattern(
|
||||
ID_PATTERN,
|
||||
|
|
|
@ -19,22 +19,22 @@
|
|||
|
||||
import { EventEmitter } from 'events';
|
||||
|
||||
import { createLocalChromedriverApi } from './chromedriver_local_api';
|
||||
import { createRemoteChromedriverApi } from './chromedriver_remote_api';
|
||||
import { createLocalBrowserDriverApi } from './browser_driver_local_api';
|
||||
import { createRemoteBrowserDriverApi } from './browser_driver_remote_api';
|
||||
import { ping } from './ping';
|
||||
|
||||
const noop = () => {};
|
||||
|
||||
/**
|
||||
* Api for interacting with a local or remote instance of Chromedriver
|
||||
* Api for interacting with a local or remote instance of a browser
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
export class ChromedriverApi extends EventEmitter {
|
||||
static async factory(log, url) {
|
||||
export class BrowserDriverApi extends EventEmitter {
|
||||
static async factory(log, url, browserType) {
|
||||
return (await ping(url))
|
||||
? createRemoteChromedriverApi(log, url)
|
||||
: createLocalChromedriverApi(log, url);
|
||||
? createRemoteBrowserDriverApi(log, url)
|
||||
: createLocalBrowserDriverApi(log, url, browserType);
|
||||
}
|
||||
|
||||
constructor(options = {}) {
|
||||
|
@ -44,19 +44,22 @@ export class ChromedriverApi extends EventEmitter {
|
|||
url,
|
||||
start = noop,
|
||||
stop = noop,
|
||||
requiredCapabilities,
|
||||
} = options;
|
||||
|
||||
if (!url) {
|
||||
throw new TypeError('url is a required parameter');
|
||||
}
|
||||
|
||||
this._requiredCapabilities = requiredCapabilities;
|
||||
this._url = url;
|
||||
this._state = undefined;
|
||||
this._callCustomStart = () => start(this);
|
||||
this._callCustomStop = () => stop(this);
|
||||
this._beforeStopFns = [];
|
||||
}
|
||||
|
||||
getRequiredCapabilities() {
|
||||
return this._requiredCapabilities;
|
||||
}
|
||||
getUrl() {
|
||||
return this._url;
|
||||
}
|
||||
|
@ -71,7 +74,7 @@ export class ChromedriverApi extends EventEmitter {
|
|||
|
||||
async start() {
|
||||
if (this._state !== undefined) {
|
||||
throw new Error('Chromedriver can only be started once');
|
||||
throw new Error('Driver can only be started once');
|
||||
}
|
||||
|
||||
this._state = 'started';
|
||||
|
@ -80,7 +83,7 @@ export class ChromedriverApi extends EventEmitter {
|
|||
|
||||
async stop() {
|
||||
if (this._state !== 'started') {
|
||||
throw new Error('Chromedriver can only be stopped after being started');
|
||||
throw new Error('Driver can only be stopped after being started');
|
||||
}
|
||||
|
||||
this._state = 'stopped';
|
|
@ -23,56 +23,67 @@ import { parse as parseUrl } from 'url';
|
|||
import treeKill from 'tree-kill';
|
||||
import { delay, fromNode as fcb } from 'bluebird';
|
||||
import { path as CHROMEDRIVER_EXEC } from 'chromedriver';
|
||||
import { path as FIREFOXDRIVER_EXEC } from 'geckodriver';
|
||||
|
||||
import { ping } from './ping';
|
||||
import { ChromedriverApi } from './chromedriver_api';
|
||||
import { BrowserDriverApi } from './browser_driver_api';
|
||||
const START_TIMEOUT = 15000;
|
||||
const PING_INTERVAL = 500;
|
||||
|
||||
export function createLocalChromedriverApi(log, url) {
|
||||
export function createLocalBrowserDriverApi(log, url, browser) {
|
||||
let runningDriver = null;
|
||||
const driverName = browser + 'driver';
|
||||
switch (browser) {
|
||||
case 'firefox':
|
||||
runningDriver = FIREFOXDRIVER_EXEC;
|
||||
break;
|
||||
default:
|
||||
runningDriver = CHROMEDRIVER_EXEC;
|
||||
}
|
||||
let proc = null;
|
||||
|
||||
return new ChromedriverApi({
|
||||
return new BrowserDriverApi({
|
||||
url,
|
||||
requiredCapabilities: Object.create({ browserType: browser }),
|
||||
|
||||
async start(api) {
|
||||
const { port } = parseUrl(url);
|
||||
log.info('Starting local chromedriver at port %d', port);
|
||||
log.debug('Starting local ' + driverName + ' at port %d', port);
|
||||
|
||||
proc = spawn(CHROMEDRIVER_EXEC, [`--port=${port}`], {
|
||||
proc = spawn(runningDriver, [`--port=${port}`], {
|
||||
stdio: ['ignore', 'pipe', 'pipe'],
|
||||
});
|
||||
|
||||
proc.stdout.on('data', chunk => {
|
||||
log.debug('[chromedriver:stdout]', chunk.toString('utf8').trim());
|
||||
log.debug('[' + driverName + ':stdout]', chunk.toString('utf8').trim());
|
||||
});
|
||||
proc.stderr.on('data', chunk => {
|
||||
log.debug('[chromedriver:stderr]', chunk.toString('utf8').trim());
|
||||
log.debug('[' + driverName + ':stderr]', chunk.toString('utf8').trim());
|
||||
});
|
||||
|
||||
proc.on('exit', (code) => {
|
||||
if (!api.isStopped() || code > 0) {
|
||||
api.emit('error', new Error(`Chromedriver exited with code ${code}`));
|
||||
api.emit('error', new Error(driverName + ` exited with code ${code}`));
|
||||
}
|
||||
});
|
||||
|
||||
const pingsStartedAt = Date.now();
|
||||
while (true) {
|
||||
log.debug('[chromedriver:ping] attempting to reach chromedriver at %j', url);
|
||||
log.debug('[' + driverName + ':ping] attempting to reach at %j', url);
|
||||
if (await ping(url)) {
|
||||
log.debug('[chromedriver:ping] success');
|
||||
log.debug('[' + driverName + ':ping] success');
|
||||
break;
|
||||
} else {
|
||||
log.debug('[chromedriver:ping] failure');
|
||||
log.debug('[' + driverName + ':ping] failure');
|
||||
}
|
||||
|
||||
if ((Date.now() - pingsStartedAt) < START_TIMEOUT) {
|
||||
log.debug('[chromedriver:ping] waiting for %d before next ping', PING_INTERVAL);
|
||||
log.debug('[' + driverName + ':ping] waiting for %d before next ping', PING_INTERVAL);
|
||||
await delay(PING_INTERVAL);
|
||||
continue;
|
||||
}
|
||||
|
||||
throw new Error(`Chromedriver did not start within the ${START_TIMEOUT}ms timeout`);
|
||||
throw new Error(driverName + ` did not start within the ${START_TIMEOUT}ms timeout`);
|
||||
}
|
||||
},
|
||||
|
|
@ -17,10 +17,10 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import { ChromedriverApi } from './chromedriver_api';
|
||||
import { BrowserDriverApi } from './browser_driver_api';
|
||||
|
||||
export function createRemoteChromedriverApi(log, url) {
|
||||
return new ChromedriverApi({
|
||||
export function createRemoteBrowserDriverApi(log, url) {
|
||||
return new BrowserDriverApi({
|
||||
url,
|
||||
|
||||
start() {
|
|
@ -17,4 +17,4 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
export { ChromedriverApi } from './chromedriver_api';
|
||||
export { BrowserDriverApi } from './browser_driver_api';
|
|
@ -27,15 +27,14 @@ const SECOND = 1000;
|
|||
const MINUTE = 60 * SECOND;
|
||||
|
||||
let attemptCounter = 0;
|
||||
async function attemptToCreateCommand(log, server, chromedriverApi) {
|
||||
async function attemptToCreateCommand(log, server, driverApi) {
|
||||
const attemptId = ++attemptCounter;
|
||||
|
||||
log.debug('[leadfoot:command] Creating session');
|
||||
const session = await server.createSession({ browserName: 'chrome' });
|
||||
const session = await server.createSession({}, driverApi.getRequiredCapabilities());
|
||||
if (attemptId !== attemptCounter) return; // abort
|
||||
|
||||
log.debug('[leadfoot:command] Registerying session for teardown');
|
||||
chromedriverApi.beforeStop(async () => session.quit());
|
||||
driverApi.beforeStop(async () => session.quit());
|
||||
if (attemptId !== attemptCounter) return; // abort
|
||||
|
||||
log.debug('[leadfoot:command] Completing session capabilities');
|
||||
|
@ -48,7 +47,7 @@ async function attemptToCreateCommand(log, server, chromedriverApi) {
|
|||
return { command: new Command(session) };
|
||||
}
|
||||
|
||||
export async function initLeadfootCommand({ log, chromedriverApi }) {
|
||||
export async function initLeadfootCommand({ log, browserDriverApi }) {
|
||||
return await Promise.race([
|
||||
(async () => {
|
||||
await delay(2 * MINUTE);
|
||||
|
@ -60,7 +59,7 @@ export async function initLeadfootCommand({ log, chromedriverApi }) {
|
|||
// backend (chromedriver in this case). it helps with session management
|
||||
// and all communication to the remote browser go through it, so we shim
|
||||
// some of it's methods to enable very verbose logging.
|
||||
const server = initVerboseRemoteLogging(log, new Server(chromedriverApi.getUrl()));
|
||||
const server = initVerboseRemoteLogging(log, new Server(browserDriverApi.getUrl()));
|
||||
|
||||
// by default, calling server.createSession() automatically fixes the webdriver
|
||||
// "capabilities" hash so that leadfoot knows the hoops it has to jump through
|
||||
|
@ -78,7 +77,7 @@ export async function initLeadfootCommand({ log, chromedriverApi }) {
|
|||
while (true) {
|
||||
const command = await Promise.race([
|
||||
delay(30 * SECOND),
|
||||
attemptToCreateCommand(log, server, chromedriverApi)
|
||||
attemptToCreateCommand(log, server, browserDriverApi)
|
||||
]);
|
||||
|
||||
if (!command) {
|
||||
|
|
|
@ -19,19 +19,25 @@
|
|||
|
||||
import { initLeadfootCommand } from './leadfoot_command';
|
||||
import { createRemoteInterceptors } from './interceptors';
|
||||
import { ChromedriverApi } from './chromedriver_api';
|
||||
import { BrowserDriverApi } from './browser_driver_api';
|
||||
|
||||
export async function RemoteProvider({ getService }) {
|
||||
const lifecycle = getService('lifecycle');
|
||||
const config = getService('config');
|
||||
const log = getService('log');
|
||||
const possibleBrowsers = ['chrome', 'firefox'];
|
||||
const browserType = process.env.TEST_BROWSER_TYPE || 'chrome';
|
||||
|
||||
const chromedriverApi = await ChromedriverApi.factory(log, config.get('chromedriver.url'));
|
||||
lifecycle.on('cleanup', async () => await chromedriverApi.stop());
|
||||
if (!possibleBrowsers.includes(browserType)) {
|
||||
throw new Error(`Unexpected TEST_BROWSER_TYPE "${browserType}". Valid options are ` + possibleBrowsers.join(','));
|
||||
}
|
||||
|
||||
await chromedriverApi.start();
|
||||
const browserDriverApi = await BrowserDriverApi.factory(log, config.get(browserType + 'driver.url'), browserType);
|
||||
lifecycle.on('cleanup', async () => await browserDriverApi.stop());
|
||||
|
||||
const { command } = await initLeadfootCommand({ log, chromedriverApi });
|
||||
await browserDriverApi.start();
|
||||
|
||||
const { command } = await initLeadfootCommand({ log, browserDriverApi: browserDriverApi });
|
||||
const interceptors = createRemoteInterceptors(command);
|
||||
|
||||
log.info('Remote initialized');
|
||||
|
|
84
yarn.lock
84
yarn.lock
|
@ -507,6 +507,10 @@ add-event-listener@0.0.1:
|
|||
version "0.0.1"
|
||||
resolved "https://registry.yarnpkg.com/add-event-listener/-/add-event-listener-0.0.1.tgz#a76229ebc64c8aefae204a16273a2f255abea2d0"
|
||||
|
||||
adm-zip@0.4.7:
|
||||
version "0.4.7"
|
||||
resolved "https://registry.yarnpkg.com/adm-zip/-/adm-zip-0.4.7.tgz#8606c2cbf1c426ce8c8ec00174447fd49b6eafc1"
|
||||
|
||||
after@0.8.2:
|
||||
version "0.8.2"
|
||||
resolved "https://registry.yarnpkg.com/after/-/after-0.8.2.tgz#fedb394f9f0e02aa9768e702bda23b505fae7e1f"
|
||||
|
@ -1851,6 +1855,10 @@ bluebird@3.1.1:
|
|||
version "3.1.1"
|
||||
resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.1.1.tgz#7e2e4318d62ae72a674f6aea6357bb4def1a6e41"
|
||||
|
||||
bluebird@3.4.6:
|
||||
version "3.4.6"
|
||||
resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.4.6.tgz#01da8d821d87813d158967e743d5fe6c62cf8c0f"
|
||||
|
||||
bluebird@^2.10.0:
|
||||
version "2.11.0"
|
||||
resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-2.11.0.tgz#534b9033c022c9579c56ba3b3e5a5caafbb650e1"
|
||||
|
@ -3038,7 +3046,7 @@ create-ecdh@^4.0.0:
|
|||
bn.js "^4.1.0"
|
||||
elliptic "^6.0.0"
|
||||
|
||||
create-error-class@^3.0.0:
|
||||
create-error-class@^3.0.0, create-error-class@^3.0.1:
|
||||
version "3.0.2"
|
||||
resolved "https://registry.yarnpkg.com/create-error-class/-/create-error-class-3.0.2.tgz#06be7abef947a3f14a30fd610671d401bca8b7b6"
|
||||
dependencies:
|
||||
|
@ -3970,7 +3978,7 @@ dtrace-provider@~0.6:
|
|||
dependencies:
|
||||
nan "^2.0.8"
|
||||
|
||||
duplexer2@~0.1.4:
|
||||
duplexer2@^0.1.4, duplexer2@~0.1.4:
|
||||
version "0.1.4"
|
||||
resolved "https://registry.yarnpkg.com/duplexer2/-/duplexer2-0.1.4.tgz#8b12dab878c0d69e3e7891051662a32fc6bddcc1"
|
||||
dependencies:
|
||||
|
@ -5269,6 +5277,15 @@ gaze@^1.0.0:
|
|||
dependencies:
|
||||
globule "^1.0.0"
|
||||
|
||||
geckodriver@1.10.0:
|
||||
version "1.10.0"
|
||||
resolved "https://registry.yarnpkg.com/geckodriver/-/geckodriver-1.10.0.tgz#73e2f785666521d0d3a9ddc9fd5a0a5e3bf47845"
|
||||
dependencies:
|
||||
adm-zip "0.4.7"
|
||||
bluebird "3.4.6"
|
||||
got "5.6.0"
|
||||
tar "4.0.2"
|
||||
|
||||
generate-function@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/generate-function/-/generate-function-2.0.0.tgz#6858fe7c0969b7d4e9093337647ac79f60dfbe74"
|
||||
|
@ -5582,6 +5599,27 @@ good-squeeze@2.1.0:
|
|||
hoek "2.x.x"
|
||||
json-stringify-safe "5.0.x"
|
||||
|
||||
got@5.6.0:
|
||||
version "5.6.0"
|
||||
resolved "https://registry.yarnpkg.com/got/-/got-5.6.0.tgz#bb1d7ee163b78082bbc8eb836f3f395004ea6fbf"
|
||||
dependencies:
|
||||
create-error-class "^3.0.1"
|
||||
duplexer2 "^0.1.4"
|
||||
is-plain-obj "^1.0.0"
|
||||
is-redirect "^1.0.0"
|
||||
is-retry-allowed "^1.0.0"
|
||||
is-stream "^1.0.0"
|
||||
lowercase-keys "^1.0.0"
|
||||
node-status-codes "^1.0.0"
|
||||
object-assign "^4.0.1"
|
||||
parse-json "^2.1.0"
|
||||
pinkie-promise "^2.0.0"
|
||||
read-all-stream "^3.0.0"
|
||||
readable-stream "^2.0.5"
|
||||
timed-out "^2.0.0"
|
||||
unzip-response "^1.0.0"
|
||||
url-parse-lax "^1.0.0"
|
||||
|
||||
got@^3.2.0:
|
||||
version "3.3.1"
|
||||
resolved "https://registry.yarnpkg.com/got/-/got-3.3.1.tgz#e5d0ed4af55fc3eef4d56007769d98192bcb2eca"
|
||||
|
@ -7801,9 +7839,9 @@ lead@^1.0.0:
|
|||
dependencies:
|
||||
flush-write-stream "^1.0.2"
|
||||
|
||||
leadfoot@1.7.1:
|
||||
version "1.7.1"
|
||||
resolved "https://registry.yarnpkg.com/leadfoot/-/leadfoot-1.7.1.tgz#7dae9961f01c9bec862b621ccece0826c8c64599"
|
||||
leadfoot@silne30/leadfoot#validation_for_response_in_ff58:
|
||||
version "1.7.4"
|
||||
resolved "https://codeload.github.com/silne30/leadfoot/tar.gz/460c8ed67c08177adc9c79243ff045880f4cad09"
|
||||
dependencies:
|
||||
dojo "2.0.0-alpha.7"
|
||||
jszip "2.5.0"
|
||||
|
@ -8715,6 +8753,18 @@ minimost@^1.0.0:
|
|||
dependencies:
|
||||
minimist "^1.2.0"
|
||||
|
||||
minipass@^2.2.1:
|
||||
version "2.2.1"
|
||||
resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.2.1.tgz#5ada97538b1027b4cf7213432428578cb564011f"
|
||||
dependencies:
|
||||
yallist "^3.0.0"
|
||||
|
||||
minizlib@^1.0.4:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-1.1.0.tgz#11e13658ce46bc3a70a267aac58359d1e0c29ceb"
|
||||
dependencies:
|
||||
minipass "^2.2.1"
|
||||
|
||||
mixin-deep@^1.2.0:
|
||||
version "1.3.1"
|
||||
resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.1.tgz#a49e7268dce1a0d9698e45326c5626df3543d0fe"
|
||||
|
@ -9039,6 +9089,10 @@ node-sass@^4.9.0:
|
|||
stdout-stream "^1.4.0"
|
||||
"true-case-path" "^1.0.2"
|
||||
|
||||
node-status-codes@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/node-status-codes/-/node-status-codes-1.0.0.tgz#5ae5541d024645d32a58fcddc9ceecea7ae3ac2f"
|
||||
|
||||
nodemailer@^4.6.4:
|
||||
version "4.6.4"
|
||||
resolved "https://registry.yarnpkg.com/nodemailer/-/nodemailer-4.6.4.tgz#f0d72d0c6a6ec5f4369fa8f4bf5127a31baa2014"
|
||||
|
@ -9527,7 +9581,7 @@ parse-headers@^2.0.0:
|
|||
for-each "^0.3.2"
|
||||
trim "0.0.1"
|
||||
|
||||
parse-json@^2.2.0:
|
||||
parse-json@^2.1.0, parse-json@^2.2.0:
|
||||
version "2.2.0"
|
||||
resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9"
|
||||
dependencies:
|
||||
|
@ -12401,6 +12455,16 @@ tar@2.2.0:
|
|||
fstream "^1.0.2"
|
||||
inherits "2"
|
||||
|
||||
tar@4.0.2:
|
||||
version "4.0.2"
|
||||
resolved "https://registry.yarnpkg.com/tar/-/tar-4.0.2.tgz#e8e22bf3eec330e5c616d415a698395e294e8fad"
|
||||
dependencies:
|
||||
chownr "^1.0.1"
|
||||
minipass "^2.2.1"
|
||||
minizlib "^1.0.4"
|
||||
mkdirp "^0.5.0"
|
||||
yallist "^3.0.2"
|
||||
|
||||
tar@^2.0.0, tar@^2.2.1:
|
||||
version "2.2.1"
|
||||
resolved "https://registry.yarnpkg.com/tar/-/tar-2.2.1.tgz#8e4d2a256c0e2185c6b18ad694aec968b83cb1d1"
|
||||
|
@ -13049,6 +13113,10 @@ unset-value@^1.0.0:
|
|||
has-value "^0.3.1"
|
||||
isobject "^3.0.0"
|
||||
|
||||
unzip-response@^1.0.0:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/unzip-response/-/unzip-response-1.0.2.tgz#b984f0877fc0a89c2c773cc1ef7b5b232b5b06fe"
|
||||
|
||||
unzip-response@^2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/unzip-response/-/unzip-response-2.0.1.tgz#d2f0f737d16b0615e72a6935ed04214572d56f97"
|
||||
|
@ -13966,6 +14034,10 @@ yallist@^2.0.0, yallist@^2.1.2:
|
|||
version "2.1.2"
|
||||
resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52"
|
||||
|
||||
yallist@^3.0.0, yallist@^3.0.2:
|
||||
version "3.0.2"
|
||||
resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.0.2.tgz#8452b4bb7e83c7c188d8041c1a837c773d6d8bb9"
|
||||
|
||||
yargs-parser@^5.0.0:
|
||||
version "5.0.0"
|
||||
resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-5.0.0.tgz#275ecf0d7ffe05c77e64e7c86e4cd94bf0e1228a"
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue