codeceptjs
Version:
Modern Era Acceptance Testing Framework for NodeJS
234 lines (209 loc) • 6.74 kB
JavaScript
const container = require('../container');
const mainConfig = require('../config');
const recorder = require('../recorder');
const event = require('../event');
const output = require('../output');
const debug = require('debug')('codeceptjs:plugin:wdio');
const defaultConfig = {
services: [],
capabilities: {},
};
let restartsSession;
/**
* Webdriverio services runner.
*
* This plugin allows to run webdriverio services like:
*
* * selenium-standalone
* * sauce
* * testingbot
* * browserstack
* * appium
*
* A complete list of all available services can be found on [webdriverio website](https://webdriver.io).
*
* ###### Setup
*
* 1. Install a webdriverio service
* 2. Enable `wdio` plugin in config
* 3. Add service name to `services` array inside wdio plugin config.
*
* See examples below:
*
* ###### Selenium Standalone Service
*
* Install ` @wdio/selenium-standalone-service` package, as [described here](https://webdriver.io/docs/selenium-standalone-service.html).
* It is important to make sure it is compatible with current webdriverio version.
*
* Enable `wdio` plugin in plugins list and add `selenium-standalone` service:
*
* ```js
* plugins: {
* wdio: {
* enabled: true,
* services: ['selenium-standalone']
* // additional config for service can be passed here
* }
* }
* ```
*
* Please note, this service can be used with Protractor helper as well!
*
* ##### Sauce Service
*
* Install `@wdio/sauce-service` package, as [described here](https://webdriver.io/docs/sauce-service.html).
* It is important to make sure it is compatible with current webdriverio version.
*
* Enable `wdio` plugin in plugins list and add `sauce` service:
*
* ```js
* plugins: {
* wdio: {
* enabled: true,
* services: ['sauce'],
* user: ... ,// saucelabs username
* key: ... // saucelabs api key
* // additional config, from sauce service
* }
* }
* ```
*
* ---
*
* In the same manner additional services from webdriverio can be installed, enabled, and configured.
*
* #### Configuration
*
* * `services` - list of enabled services
* * ... - additional configuration passed into services.
*
*/
module.exports = (config) => {
const webDriver = container.helpers('WebDriver');
if (webDriver) {
config = Object.assign(webDriver.options, config);
restartsSession = !!config.restart;
}
config = Object.assign(defaultConfig, config);
const services = [];
const launchers = [];
for (const name of config.services) {
// webdriverio v5 style
const Service = safeRequire(`@wdio/${name.toLowerCase()}-service`);
if (Service) {
if (Service.launcher && typeof Service.launcher === 'function') {
const Launcher = Service.launcher;
launchers.push(new Launcher(config));
}
if (typeof Service === 'function') {
services.push(new Service(config, config.capabilities));
}
continue;
}
throw new Error(`Couldn't initialize service ${name} from wdio plugin config.\nIt should be available either in '@wdio/${name.toLowerCase()}-service' package`);
}
debug(`services ${services}, launchers ${launchers}`);
recorder.startUnlessRunning();
for (const launcher of launchers) {
registerLauncher(launcher);
}
for (const service of services) {
registerService(service);
}
function registerService(service) {
const name = service.constructor.name;
if (service.beforeSession) {
event.dispatcher.on(event.all.before, () => {
recorder.add(`service ${name} all.before`, async () => {
await service.beforeSession(config, config.capabilities);
});
});
}
if (service.afterSession) {
event.dispatcher.on(event.all.result, (result) => {
recorder.add(`service ${name} all.after`, async () => {
await service.afterSession(result);
});
});
}
if (service.beforeSuite) {
event.dispatcher.on(event.suite.before, (suite) => {
debug(`suite started: ${suite.title}`);
recorder.add(`service ${name} suite.before`, () => service.beforeSuite(suite));
});
}
if (service.afterSuite) {
event.dispatcher.on(event.suite.after, (suite) => {
debug(`suite finished: ${suite.title}`);
recorder.add(`service ${name} suite.after`, () => service.afterSuite(suite));
});
}
if (service.beforeTest) {
event.dispatcher.on(event.test.started, async (test) => {
if (test.parent) {
test.parent.toString = () => test.parent.title;
}
// test.parent = test.parent ? test.parent.title : null;
debug(`test started: ${test.title}`);
if (webDriver) {
global.browser = webDriver.browser;
global.browser.config = Object.assign(mainConfig.get(), global.browser.config);
}
await service.beforeTest(test);
});
}
if (service.afterTest) {
event.dispatcher.on(event.test.finished, async (test) => {
debug(`test finished: ${test.title}`);
await service.afterTest(test);
});
}
if (restartsSession && service.before) {
event.dispatcher.on(event.test.started, test => service.before());
}
if (restartsSession && service.after) {
event.dispatcher.on(event.test.finished, test => service.after());
}
if (!restartsSession && service.before) {
let initializedBrowser = false;
event.dispatcher.on(event.test.started, async (test) => {
if (!initializedBrowser) {
await service.before();
initializedBrowser = true;
}
});
}
if (!restartsSession && service.after) {
event.dispatcher.on(event.all.result, result => service.after(result));
}
}
function registerLauncher(launcher) {
const name = launcher.constructor.name;
if (launcher.onPrepare) {
event.dispatcher.on(event.all.before, () => {
recorder.add(`launcher ${name} start`, async () => {
await launcher.onPrepare(config, config.capabilities);
output.debug(`Started ${name}`);
});
});
}
if (launcher.onComplete) {
event.dispatcher.on(event.all.after, () => {
recorder.add(`launcher ${name} start`, async () => {
await launcher.onComplete(process.exitCode, config, config.capabilities);
output.debug(`Stopped ${name}`);
});
});
}
}
};
function safeRequire(name) {
try {
return require(name);
} catch (e) {
if (!e.message.match(`Cannot find module '${name}'`)) {
throw new Error(`Couldn't initialise "${name}".\n${e.stack}`);
}
return null;
}
}