kasmir
Version:
Amazing multi-browser automation tool
1,469 lines (1,217 loc) • 43.2 kB
JavaScript
module.exports =
/******/ (function(modules) { // webpackBootstrap
/******/ // The module cache
/******/ var installedModules = {};
/******/
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/
/******/ // Check if module is in cache
/******/ if(installedModules[moduleId])
/******/ return installedModules[moduleId].exports;
/******/
/******/ // Create a new module (and put it into the cache)
/******/ var module = installedModules[moduleId] = {
/******/ i: moduleId,
/******/ l: false,
/******/ exports: {}
/******/ };
/******/
/******/ // Execute the module function
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/
/******/ // Flag the module as loaded
/******/ module.l = true;
/******/
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/
/******/
/******/ // expose the modules object (__webpack_modules__)
/******/ __webpack_require__.m = modules;
/******/
/******/ // expose the module cache
/******/ __webpack_require__.c = installedModules;
/******/
/******/ // identity function for calling harmony imports with the correct context
/******/ __webpack_require__.i = function(value) { return value; };
/******/
/******/ // define getter function for harmony exports
/******/ __webpack_require__.d = function(exports, name, getter) {
/******/ if(!__webpack_require__.o(exports, name)) {
/******/ Object.defineProperty(exports, name, {
/******/ configurable: false,
/******/ enumerable: true,
/******/ get: getter
/******/ });
/******/ }
/******/ };
/******/
/******/ // getDefaultExport function for compatibility with non-harmony modules
/******/ __webpack_require__.n = function(module) {
/******/ var getter = module && module.__esModule ?
/******/ function getDefault() { return module['default']; } :
/******/ function getModuleExports() { return module; };
/******/ __webpack_require__.d(getter, 'a', getter);
/******/ return getter;
/******/ };
/******/
/******/ // Object.prototype.hasOwnProperty.call
/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
/******/
/******/ // __webpack_public_path__
/******/ __webpack_require__.p = "/";
/******/
/******/ // Load entry module and return exports
/******/ return __webpack_require__(__webpack_require__.s = 14);
/******/ })
/************************************************************************/
/******/ ([
/* 0 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.unserialize = exports.serialize = undefined;
var _serializeJavascript = __webpack_require__(2);
var serializer = _interopRequireWildcard(_serializeJavascript);
function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
var serialize = exports.serialize = function serialize(obj) {
return serializer.default(obj);
};
var unserialize = exports.unserialize = function unserialize(obj) {
return eval('(' + obj + ')');
};
/***/ }),
/* 1 */
/***/ (function(module, exports) {
module.exports = require("path");
/***/ }),
/* 2 */
/***/ (function(module, exports) {
module.exports = require("serialize-javascript");
/***/ }),
/* 3 */,
/* 4 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
// Kasmir default configuration file
module.exports = {
// How many browsers to launch
browsers: 1,
// Verbosity level
// 0 - ensure no output
// 1 - only fatal errors
// 2 - output action process and child errors
// 3 - output task progress
// 4 - output selenium logs
// 5 - output everything
verbosity: 1,
// Collect reports
report: true,
// Load action files here
actionsPath: null,
// Download selenium & chromedriver
downloadDrivers: true,
// Output path
downloadPath: '_bin',
// Action definitions
actions: {},
// Runner settings
runner: {
// Colored output
colors: true,
// Runner verbose output
silent: true,
// Live output log
live_output: false,
// Task result settings
result_settings: {
// Embed images in result
images: false
},
// Selenium server settings
selenium_settings: {
// Start process on run
start_process: true,
// Selenium executable path
server_path: "./_bin/selenium.jar",
// Bind port
port: 4444,
// Additional client arguments
cli_args: {
"webdriver.chrome.driver": "./_bin/chromedriver"
}
},
// Test settings per run environment
test_settings: {
// Default run environment settings
"default": {
// Selenium server port
selenium_port: 4444,
// Selenium server host
selenium_host: "localhost",
// Global configuration
globals: {
waitForConditionTimeout: 15000,
abortOnAssertionFailure: false
},
// Enable screenshots
screenshots: {
path: './',
enabled: false,
on_failure: false,
on_error: false
},
// Browser capabilities
desiredCapabilities: {
browserName: "chrome",
javascriptEnabled: true,
acceptSslCerts: true
}
}
},
// Runner timeouts
timeouts: {
// Wait for page to load in ms before fail
pageLoad: 10000,
// Pause after operation in ms (recommended >= 250)
pauseAfter: 250
}
}
};
/***/ }),
/* 5 */,
/* 6 */
/***/ (function(module, exports) {
module.exports = require("child_process");
/***/ }),
/* 7 */
/***/ (function(module, exports) {
module.exports = require("fs");
/***/ }),
/* 8 */,
/* 9 */
/***/ (function(module, exports) {
module.exports = require("nightwatch/lib/runner/selenium");
/***/ }),
/* 10 */
/***/ (function(module, exports) {
module.exports = require("require-dir");
/***/ }),
/* 11 */
/***/ (function(module, exports) {
module.exports = require("selenium-download");
/***/ }),
/* 12 */,
/* 13 */,
/* 14 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
var _selenium = __webpack_require__(9);
var Selenium = _interopRequireWildcard(_selenium);
var _seleniumDownload = __webpack_require__(11);
var SeleniumDownload = _interopRequireWildcard(_seleniumDownload);
var _path = __webpack_require__(1);
var path = _interopRequireWildcard(_path);
var _fs = __webpack_require__(7);
var fs = _interopRequireWildcard(_fs);
var _child_process = __webpack_require__(6);
var _serialize = __webpack_require__(0);
var _requireDir = __webpack_require__(10);
var _requireDir2 = _interopRequireDefault(_requireDir);
var _defaults = __webpack_require__(4);
var _defaults2 = _interopRequireDefault(_defaults);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
var Kasmir = function () {
function Kasmir() {
var config = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
_classCallCheck(this, Kasmir);
this.childCount = 1;
this.readyCount = 0;
this.actionsToRun = [];
this.state = [];
this.reports = [];
this.returns = [];
this.runners = [];
this.stdout = [];
this.func = null;
this.config = config;
this.continuous = false;
this.configure();
this.init();
}
_createClass(Kasmir, [{
key: 'init',
value: function init() {
var _this = this;
// Test environments for each child
this.envs = ['default'];
// Ensure selenium & chromedriver is installed
this.ensureDrivers().then(function () {
// Find child environments
if (typeof _this.config.browsers === 'number') {
_this.childCount = _this.config.browsers;
_this.envs = Array(_this.childCount).fill('default');
} else if (Array.isArray(_this.config.browsers)) {
_this.childCount = _this.config.browsers.length;
_this.envs = _this.config.browsers;
}
// Initialize reports
_this.reports = Array(_this.childCount).fill({
actions: [],
actionSummary: [],
tasks: [],
taskSummary: [],
errors: []
});
// Spawn child nodes to run the instances
for (var inst = 0; inst < _this.childCount; inst++) {
var child = (0, _child_process.spawn)('node', [_this.resolvePath('childrunner.js'), '--id=' + inst, '--settings=' + (0, _serialize.serialize)(_this.config.runner.test_settings[_this.envs[inst]])], {
stdio: ['ignore', 'pipe', 'pipe', 'ipc']
});
// Catch stdout, we trust that child checks config.verbosity
child.stdout.on('data', function (data) {
_this.message(data.toString(), 1, true);
});
// Catch ipc messages
child.on('message', function (data) {
_this.handleRunners(data);
});
// Send serialized config to child node
child.send({ message: 'configure', value: (0, _serialize.serialize)(_this.config) });
_this.runners.push(child);
}
});
// Ensure children are killed when parent exits
// istanbul ignore next
process.on('exit', function () {
_this.killRunners();
});
}
// Returns promise that resolves when init is ready
}, {
key: 'initReady',
value: function initReady() {
var _this2 = this;
return new Promise(function (resolve, reject) {
var readyWait = setInterval(function () {
if (_this2.readyCount === _this2.childCount) {
clearInterval(readyWait);
resolve();
}
}, 100);
});
}
// Ensure selenium is available
}, {
key: 'ensureDrivers',
value: function ensureDrivers() {
var _this3 = this;
return new Promise(function (resolve, reject) {
// istanbul ignore if
if (!_this3.config.downloadDrivers) {
resolve();
}
// Use selenium-download to always download the latest version of drivers
SeleniumDownload.ensure(_this3.config.downloadPath, function (error) {
// istanbul ignore if
if (error) {
_this3.message(error, 1);
} else {
_this3.message('[OK] Selenium & Chromedriver updated to: ' + _this3.config.downloadPath, 5);
}
resolve();
});
});
}
// Creates a new value definition that can be used as dynamic task argument
}, {
key: 'createValue',
value: function createValue(name, value) {
var byChildIndex = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
this.runners.map(function (runner, instance) {
// Value is array and we want to update each child with value by index
if (Array.isArray(value) && byChildIndex === true) {
runner.send({
message: 'createvalue',
value: (0, _serialize.serialize)({
name: name,
value: value[instance] || ''
})
});
} else {
runner.send({
message: 'createvalue',
value: (0, _serialize.serialize)({
name: name, value: value
})
});
}
});
}
// Import actions from a directory
}, {
key: 'getActions',
value: function getActions(pathToActions) {
var actionExports = (0, _requireDir2.default)(path.resolve(pathToActions));
// Map required action exports to global exports
for (var action in actionExports) {
if ({}.hasOwnProperty.call(actionExports, action)) {
for (var actionName in actionExports[action]) {
if ({}.hasOwnProperty.call(actionExports[action], actionName)) {
this.config.actions[actionName] = actionExports[action][actionName];
}
}
}
}
}
// Get report
}, {
key: 'getReport',
value: function getReport(type) {
if (typeof type === 'undefined') {
return this.childCount > 1 ? this.reports : this.reports[0];
}
var states = [];
var _iteratorNormalCompletion = true;
var _didIteratorError = false;
var _iteratorError = undefined;
try {
for (var _iterator = this.reports[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
var report = _step.value;
states.push(report[type]);
}
} catch (err) {
_didIteratorError = true;
_iteratorError = err;
} finally {
try {
if (!_iteratorNormalCompletion && _iterator.return) {
_iterator.return();
}
} finally {
if (_didIteratorError) {
throw _iteratorError;
}
}
}
return this.runners.length > 1 ? states : states[0];
}
// Get current complete state
}, {
key: 'getState',
value: function getState(type) {
var result = [];
var index = 0;
try {
var _iteratorNormalCompletion2 = true;
var _didIteratorError2 = false;
var _iteratorError2 = undefined;
try {
for (var _iterator2 = this.reports[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
var runnerReport = _step2.value;
var state = {};
var _iteratorNormalCompletion3 = true;
var _didIteratorError3 = false;
var _iteratorError3 = undefined;
try {
for (var _iterator3 = runnerReport.tasks[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) {
var taskState = _step3.value;
if (typeof state[taskState.action] === 'undefined') {
state[taskState.action] = [];
} else if (_typeof(state[taskState.action][index]) === 'object' && typeof state[taskState.action][index][taskState.name] !== 'undefined') {
index++;
}
if (_typeof(state[taskState.action][index]) !== 'object') {
state[taskState.action][index] = {};
}
state[taskState.action][index][taskState.name] = taskState;
}
// Collapse arrays if single indice
} catch (err) {
_didIteratorError3 = true;
_iteratorError3 = err;
} finally {
try {
if (!_iteratorNormalCompletion3 && _iterator3.return) {
_iterator3.return();
}
} finally {
if (_didIteratorError3) {
throw _iteratorError3;
}
}
}
for (var actionName in state) {
if ({}.hasOwnProperty.call(state, actionName) && state[actionName].length === 1) {
state[actionName] = state[actionName][0];
}
}
result.push(state);
}
} catch (err) {
_didIteratorError2 = true;
_iteratorError2 = err;
} finally {
try {
if (!_iteratorNormalCompletion2 && _iterator2.return) {
_iterator2.return();
}
} finally {
if (_didIteratorError2) {
throw _iteratorError2;
}
}
}
return result.length > 1 ? result : result[0];
} catch (e) {
// istanbul ignore next
this.message(e.message, 1);
// istanbul ignore next
return null;
}
}
// Get state by action or task
}, {
key: 'getReportsByName',
value: function getReportsByName(name) {
var type = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'actions';
var result = [];
for (var i = 0; i < this.childCount; i++) {
var result2 = [];
var _iteratorNormalCompletion4 = true;
var _didIteratorError4 = false;
var _iteratorError4 = undefined;
try {
for (var _iterator4 = this.reports[i][type][Symbol.iterator](), _step4; !(_iteratorNormalCompletion4 = (_step4 = _iterator4.next()).done); _iteratorNormalCompletion4 = true) {
var report = _step4.value;
if (report.name === name) {
result2.push(report);
}
}
} catch (err) {
_didIteratorError4 = true;
_iteratorError4 = err;
} finally {
try {
if (!_iteratorNormalCompletion4 && _iterator4.return) {
_iterator4.return();
}
} finally {
if (_didIteratorError4) {
throw _iteratorError4;
}
}
}
result.push(result2);
}
return this.childCount > 1 ? result : result[0] || [];
}
// Get state by task
}, {
key: 'getActionReports',
value: function getActionReports(action) {
var reports = this.getReportsByName(action, 'actions');
return reports.length > 1 ? reports : reports[0];
}
// Get task summary
}, {
key: 'getActionReport',
value: function getActionReport() {
return this.getReport('actions');
}
// Get task summary
}, {
key: 'getActionSummary',
value: function getActionSummary() {
return this.getReport('actionSummary');
}
// Get state by task
}, {
key: 'getTaskReports',
value: function getTaskReports(task) {
var reports = this.getReportsByName(task, 'tasks');
return reports.length > 1 ? reports : reports[0];
}
// Get task summary
}, {
key: 'getTaskReport',
value: function getTaskReport() {
return this.getReport('tasks');
}
// Get task summary
}, {
key: 'getTaskSummary',
value: function getTaskSummary() {
return this.getReport('taskSummary');
}
// Get extended summary
}, {
key: 'getErrors',
value: function getErrors() {
return this.getReport('errors');
}
// Pretty print JSON
}, {
key: 'prettyPrint',
value: function prettyPrint(json) {
// istanbul ignore next
console.dir(json, { depth: null, colors: true });
}
// Pretty print report by type
}, {
key: 'report',
value: function report(type) {
// istanbul ignore next
return type ? this.prettyPrint(this.getReport(type)) : this.prettyPrint(this.getReport());
}
// Clear reports
}, {
key: 'clearReports',
value: function clearReports() {
var _this4 = this;
return new Promise(function (resolve, reject) {
_this4.state = [];
_this4.reports = [];
_this4.clearCount = 0;
var _iteratorNormalCompletion5 = true;
var _didIteratorError5 = false;
var _iteratorError5 = undefined;
try {
for (var _iterator5 = _this4.runners[Symbol.iterator](), _step5; !(_iteratorNormalCompletion5 = (_step5 = _iterator5.next()).done); _iteratorNormalCompletion5 = true) {
var runner = _step5.value;
runner.send({ message: 'clear', value: true });
}
// Poll clear count
} catch (err) {
_didIteratorError5 = true;
_iteratorError5 = err;
} finally {
try {
if (!_iteratorNormalCompletion5 && _iterator5.return) {
_iterator5.return();
}
} finally {
if (_didIteratorError5) {
throw _iteratorError5;
}
}
}
var clearWait = setInterval(function () {
if (_this4.clearCount === _this4.runners.length) {
clearInterval(clearWait);
resolve();
}
}, 50);
});
}
// Clone object
}, {
key: 'clone',
value: function clone(obj) {
return JSON.parse(JSON.stringify(obj));
}
// Extend configuration objects
}, {
key: 'extend',
value: function extend() {
var config = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
var userConfig = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
// Clone object
var result = this.clone(config);
// Loop through default config props
for (var prop in config) {
// If known prop found in user config
if (typeof userConfig[prop] !== "undefined") {
// For object props, extended recursively
if (_typeof(result[prop]) === "object" && _typeof(userConfig[prop]) === "object" && Array.isArray(result[prop]) === false && Array.isArray(userConfig[prop]) === false) {
result[prop] = this.extend(config[prop], userConfig[prop]);
}
// Take value from user config
else {
result[prop] = userConfig[prop];
}
}
}
return result;
}
// Parse configuration
}, {
key: 'configure',
value: function configure() {
// Extend default config
var config = this.extend(_defaults2.default, this.config);
config.actions = this.config.actions || {};
this.config = config;
// Import actions from actions path
if (config.actionsPath) {
this.getActions(config.actionsPath);
}
// Resolve download path
if (this.config.downloadPath) {
this.config.downloadPath = path.resolve(this.config.downloadPath);
this.ensurePath(this.config.downloadPath);
}
// Resolve server path
this.config.runner.selenium_settings.server_path = path.resolve(config.runner.selenium_settings.server_path);
// Resolve selenium cli_args
if (this.config.runner.selenium_settings.cli_args) {
for (var arg in this.config.runner.selenium_settings.cli_args) {
// Resolve webdriver bin path
if (arg.match(/\webdriver\..*\.driver$/)) {
this.config.runner.selenium_settings.cli_args[arg] = path.resolve(this.config.runner.selenium_settings.cli_args[arg]);
}
}
}
this.test_settings = config.runner.test_settings;
for (var env in this.test_settings) {
if (config.runner.silent) {
this.test_settings[env].silent = config.runner.silent;
}
if (this.test_settings[env].screenshots.path) {
this.test_settings[env].screenshots.path = path.resolve(this.test_settings[env].screenshots.path);
this.ensurePath(this.test_settings[env].screenshots.path);
}
// If path was not specified, we disable the screenshots option
// otherwise nightwatch will throw an error
else {
this.test_settings[env].screenshots.enabled = false;
this.message('screenshots output path not specified for \'' + env + '\'. screenshots are disabled', 2);
}
// on_failure and on_error are not supported yet
this.test_settings[env].screenshots.on_failure = false;
this.test_settings[env].screenshots.on_error = false;
}
// Full selenium config in standard format
this.seleniumConfig = {
live_output: config.runner.live_output,
output_folder: null,
selenium: config.runner.selenium_settings,
test_settings: this.test_settings
};
}
// Launch the runner
}, {
key: 'run',
value: function run() {
var _this5 = this;
var actionsToRun = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
var continuous = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
this.actionsToRun = actionsToRun;
this.continuous = continuous;
return this.initReady()
// Start sequence before running actions
.then(function () {
return _this5.start();
})
// Launch instances
.then(function () {
return _this5.runRunners(actionsToRun);
})
// Done running actions
.then(function () {
return _this5.end();
});
}
// Before running actions
}, {
key: 'start',
value: function start() {
var _this6 = this;
// Run silent mode; hook stdout to prevent selenium output
// istanbul ignore next
this.hookStdout(function (message) {
_this6.collectStdout(message);
});
return new Promise(function (resolve, reject) {
if (_this6.seleniumRunning === true) {
resolve();
} else {
_this6.runSelenium(resolve, reject);
}
});
}
// When done running actions
}, {
key: 'end',
value: function end() {
// If we are running continuous mode, simply unhook stdout
if (this.continuous === true) {
return this.unhookStdout();
}
// If not we want to kill runners and stop selenium server
this.killRunners();
return this.stopSelenium();
}
// Launch selenium server instance
}, {
key: 'runSelenium',
value: function runSelenium(success, fail) {
var _this7 = this;
Selenium.startServer(this.seleniumConfig, function (message, n, error) {
_this7.seleniumRunning = true;
// istanbul ignore if
if (error) {
_this7.message(error, 1);
fail({ message: message, error: error });
}
success();
});
}
// Stop selenium instance
}, {
key: 'stopSelenium',
value: function stopSelenium() {
var _this8 = this;
return new Promise(function (resolve, reject) {
// We might be running external selenium server so resolve immediately
// istanbul ignore if
if (_this8.seleniumRunning === false) {
resolve();
}
Selenium.stopServer(function () {
var readyWait = setInterval(function () {
if (!_this8.seleniumRunning || typeof _this8.unhookStdoutFunc !== 'function') {
clearInterval(readyWait);
resolve();
}
}, 50);
});
});
}
// Run runners
}, {
key: 'runRunners',
value: function runRunners() {
var actionsToRun = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
this.runners.map(function (runner, instance) {
runner.done = false;
runner.send({ message: 'run', value: (0, _serialize.serialize)(actionsToRun) });
});
return this.waitRunnersDone();
}
// Handle child process message
}, {
key: 'handleRunners',
value: function handleRunners() {
var data = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
// Unserialize data from runner child process
data = { id: data.id, message: data.message, value: (0, _serialize.unserialize)(data.value) };
switch (data.message) {
// When runners are done running actions, they post 'complete'. The value
// contains the report or error if the promise ends in 'catch'
case 'complete':
this.runners[data.id].done = true;
this.reports[data.id] = data.value;
this.state = this.getState();
break;
// Runner generic errors are logged
// istanbul ignore next
case 'error':
this.message(data.value.toString(), 1);
break;
// Runners post 'ready' when child process initialization is done
case 'ready':
this.readyCount += 1;
break;
// Runners post 'clear_done' when reports are cleared
case 'clear_done':
this.clearCount += 1;
break;
// Runners post status with current report state every time
// a task completes
case 'status':
this.reports[data.id] = data.value;
this.state = this.getState();
break;
// If the next action is function, the runners will emit
// this event and halt.
// We wait for all runners to halt and then run the function and
// continue runner execution.
case 'function':
this.runners[data.id].halted = true;
this.func = this.actionsToRun[data.value];
this.waitRunnersHalt();
break;
}
}
// Continue runners after halt
}, {
key: 'continueRunners',
value: function continueRunners() {
this.func = null;
var _iteratorNormalCompletion6 = true;
var _didIteratorError6 = false;
var _iteratorError6 = undefined;
try {
for (var _iterator6 = this.runners[Symbol.iterator](), _step6; !(_iteratorNormalCompletion6 = (_step6 = _iterator6.next()).done); _iteratorNormalCompletion6 = true) {
var runner = _step6.value;
runner.halted = false;
runner.send({ message: 'continue', value: (0, _serialize.serialize)(this.returns) });
}
} catch (err) {
_didIteratorError6 = true;
_iteratorError6 = err;
} finally {
try {
if (!_iteratorNormalCompletion6 && _iterator6.return) {
_iterator6.return();
}
} finally {
if (_didIteratorError6) {
throw _iteratorError6;
}
}
}
}
// Kill runners
}, {
key: 'killRunners',
value: function killRunners() {
try {
this.runners.map(function (runner, instance) {
runner.kill();
});
} catch (e) {
// istanbul ignore next
this.message('No runner instances to kill', 2);
}
}
// Execute action function
}, {
key: 'executeActionFunc',
value: function executeActionFunc() {
var _this9 = this;
return new Promise(function (resolve, reject) {
if (typeof _this9.func === 'function') {
// Feed current status to the function, call and get result
var result = _this9.func(_this9.reports);
// The function returned a promise
if (result && (typeof result === 'undefined' ? 'undefined' : _typeof(result)) === 'object' && typeof result.then === 'function') {
result.then(function (returnValue) {
// Save return value
_this9.returns.push(returnValue);
resolve();
});
}
// If action function returns {_yield: <array>} those values are interpreted
// as new actions
else if (result && (typeof result === 'undefined' ? 'undefined' : _typeof(result)) === 'object' && _typeof(result._yield) === 'object') {
if (_this9.yieldActions(result._yield) === false) {
_this9.message('functions that yield actions must return {_yield: <Array>}', 2);
}
resolve();
}
// Save return value resolve
else if (result) {
_this9.returns.push(result);
resolve();
}
// Resolve without result
else {
resolve();
}
}
});
}
// Yield new actions to runners
}, {
key: 'yieldActions',
value: function yieldActions(newActions) {
if (Array.isArray(newActions)) {
this.runners.map(function (runner, instance) {
runner.send({ message: 'yield', value: (0, _serialize.serialize)(newActions) });
});
return true;
}
return false;
}
// Wait till runners are done
}, {
key: 'waitRunnersDone',
value: function waitRunnersDone() {
var _this10 = this;
return new Promise(function (resolve, reject) {
var readyWait = setInterval(function () {
var readyStatus = true;
var _iteratorNormalCompletion7 = true;
var _didIteratorError7 = false;
var _iteratorError7 = undefined;
try {
for (var _iterator7 = _this10.runners[Symbol.iterator](), _step7; !(_iteratorNormalCompletion7 = (_step7 = _iterator7.next()).done); _iteratorNormalCompletion7 = true) {
var runner = _step7.value;
readyStatus = readyStatus && runner.done;
}
} catch (err) {
_didIteratorError7 = true;
_iteratorError7 = err;
} finally {
try {
if (!_iteratorNormalCompletion7 && _iterator7.return) {
_iterator7.return();
}
} finally {
if (_didIteratorError7) {
throw _iteratorError7;
}
}
}
if (readyStatus === true) {
clearInterval(readyWait);
resolve();
}
}, 50);
});
}
// Wait till all runners are halted and execute next function
}, {
key: 'waitRunnersHalt',
value: function waitRunnersHalt() {
var _this11 = this;
if (!this.haltWait) {
this.haltWait = setInterval(function () {
var haltStatus = true;
var _iteratorNormalCompletion8 = true;
var _didIteratorError8 = false;
var _iteratorError8 = undefined;
try {
for (var _iterator8 = _this11.runners[Symbol.iterator](), _step8; !(_iteratorNormalCompletion8 = (_step8 = _iterator8.next()).done); _iteratorNormalCompletion8 = true) {
var runner = _step8.value;
haltStatus = haltStatus && runner.halted;
}
// All runners halted
} catch (err) {
_didIteratorError8 = true;
_iteratorError8 = err;
} finally {
try {
if (!_iteratorNormalCompletion8 && _iterator8.return) {
_iterator8.return();
}
} finally {
if (_didIteratorError8) {
throw _iteratorError8;
}
}
}
if (haltStatus === true) {
clearInterval(_this11.haltWait);
_this11.executeActionFunc().then(function () {
_this11.continueRunners();
});
}
}, 50);
}
}
// Hook process.stdout to prevent output when we don't want it.
// ...such as when selenium initializes the missing settings.output
// check causes it to output process pid and startup message
}, {
key: 'hookStdout',
value: function hookStdout() {
var callback = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;
var file = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'stdout';
// We don't hook stdout if verbosity is greater or equal to 4
if (this.config.verbosity >= 4) {
return false;
}
// istanbul ignore if
if (typeof callback !== 'function') {
callback = function callback() {};
}
// This is not included in unit tests because it would suppress
// the test output
var oldWrite = process[file].write;
// Capture callable process.<file>.write
this.processWrite = function (s) {
oldWrite.call(process[file], s);
};
// Replace process.<file>.write
// istanbul ignore next
process[file].write = function (message) {
callback(message);
};
// Return unhook function
return this.unhookStdoutFunc = function () {
process[file].write = oldWrite.bind(process[file]);
};
}
// Unhook stdout
}, {
key: 'unhookStdout',
value: function unhookStdout() {
// istanbul ignore if
if (typeof this.unhookStdoutFunc === 'function') {
this.unhookStdoutFunc();
return true;
}
// istanbul ignore next
return false;
}
// Collect stdout; selenium will log the failures in task order
// with process.stdout.write so collect output if stdout is hoooked
}, {
key: 'collectStdout',
value: function collectStdout(message) {
this.stdout.push(message);
if (message.match(/Selenium\ process\ finished\./gi)) {
this.unhookStdout();
this.seleniumRunning = false;
}
}
// Resolve path to module get an absolute filename
}, {
key: 'resolvePath',
value: function resolvePath(filename) {
var basePath = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : '';
var levels = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 4;
// Return if levels go below 1
if (levels < 1) return null;
// Resolve base path
basePath = this.getBasePath(basePath);
// Get directories in base path
var dirs = this.getDirectories(basePath);
// Get resolve options by filename
var options = this.getResolveOptions(filename);
var abspath = void 0;
var abspath2 = void 0;
var _iteratorNormalCompletion9 = true;
var _didIteratorError9 = false;
var _iteratorError9 = undefined;
try {
for (var _iterator9 = dirs[Symbol.iterator](), _step9; !(_iteratorNormalCompletion9 = (_step9 = _iterator9.next()).done); _iteratorNormalCompletion9 = true) {
var dir = _step9.value;
var _iteratorNormalCompletion10 = true;
var _didIteratorError10 = false;
var _iteratorError10 = undefined;
try {
for (var _iterator10 = options[Symbol.iterator](), _step10; !(_iteratorNormalCompletion10 = (_step10 = _iterator10.next()).done); _iteratorNormalCompletion10 = true) {
var opt = _step10.value;
abspath = path.join(basePath, dir, opt);
abspath2 = path.join(process.cwd(), opt);
// istanbul ignore if
if (fs.existsSync(abspath)) return abspath;
// istanbul ignore if
if (fs.existsSync(abspath2)) return abspath2;
// istanbul ignore if
if (fs.existsSync(opt)) return opt;
}
} catch (err) {
_didIteratorError10 = true;
_iteratorError10 = err;
} finally {
try {
if (!_iteratorNormalCompletion10 && _iterator10.return) {
_iterator10.return();
}
} finally {
if (_didIteratorError10) {
throw _iteratorError10;
}
}
}
}
} catch (err) {
_didIteratorError9 = true;
_iteratorError9 = err;
} finally {
try {
if (!_iteratorNormalCompletion9 && _iterator9.return) {
_iterator9.return();
}
} finally {
if (_didIteratorError9) {
throw _iteratorError9;
}
}
}
return this.resolvePath(filename, path.join(basePath, '../'), levels - 1);
}
// Ensure path exists
}, {
key: 'ensurePath',
value: function ensurePath(location) {
// istanbul ignore if
if (!fs.existsSync(location)) {
fs.mkdirSync(location);
}
}
// Get module base path
}, {
key: 'getBasePath',
value: function getBasePath() {
var basePath = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';
if (basePath === '') {
try {
return path.resolve(path.parse(process.mainModule.filename).dir);
} catch (e) {
// istanbul ignore next
return './';
}
}
return basePath;
}
// Get base paths in directories
}, {
key: 'getDirectories',
value: function getDirectories(basePath) {
return fs.readdirSync(basePath).filter(function (file) {
return fs.statSync(path.join(basePath, file)).isDirectory();
});
}
// Get resolve options by filename
}, {
key: 'getResolveOptions',
value: function getResolveOptions(filename) {
return [filename, path.join('build', filename), path.join('kasmir', filename), path.join('node_modules', filename), path.join('node_modules', 'kasmir', filename)];
}
// Log a message
}, {
key: 'message',
value: function message(text) {
var minVerbosity = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
var fromChild = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
if (this.isStackTraceMessage(text)) {
minVerbosity = 4;
}
if (typeof this.config.verbosity === "number" && this.config.verbosity < minVerbosity) {
return;
}
var outText = text;
if (fromChild) {
if (this.config.verbosity > 3) {
outText = outText.replace(/\n$/, '');
}
} else {
outText = 'Kasmir: ' + outText;
}
if (typeof this.processWrite === "function") {
this.processWrite(outText);
} else {
console.log(outText);
}
}
// Detect nightwatch stack trace messages,
// TODO: This need more thought
}, {
key: 'isStackTraceMessage',
value: function isStackTraceMessage(message) {
return Boolean(message.match(/\(eval at/g) || message.match(/ERROR\:/g) || message.match(/at process\./g));
}
}]);
return Kasmir;
}();
exports.default = Kasmir;
module.exports = exports['default'];
/***/ })
/******/ ]);