wdio-mocha-framework
Version:
A WebdriverIO plugin. Adapter for Mocha testing framework.
793 lines (623 loc) • 25.9 kB
JavaScript
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.__RewireAPI__ = exports.__ResetDependency__ = exports.__set__ = exports.__Rewire__ = exports.__GetDependency__ = exports.__get__ = exports.adapterFactory = exports.MochaAdapter = undefined;
var _isExtensible = require('babel-runtime/core-js/object/is-extensible');
var _isExtensible2 = _interopRequireDefault(_isExtensible);
var _typeof2 = require('babel-runtime/helpers/typeof');
var _typeof3 = _interopRequireDefault(_typeof2);
var _defineProperty = require('babel-runtime/core-js/object/define-property');
var _defineProperty2 = _interopRequireDefault(_defineProperty);
var _create = require('babel-runtime/core-js/object/create');
var _create2 = _interopRequireDefault(_create);
var _regenerator = require('babel-runtime/regenerator');
var _regenerator2 = _interopRequireDefault(_regenerator);
var _keys = require('babel-runtime/core-js/object/keys');
var _keys2 = _interopRequireDefault(_keys);
var _promise = require('babel-runtime/core-js/promise');
var _promise2 = _interopRequireDefault(_promise);
var _asyncToGenerator2 = require('babel-runtime/helpers/asyncToGenerator');
var _asyncToGenerator3 = _interopRequireDefault(_asyncToGenerator2);
var _toConsumableArray2 = require('babel-runtime/helpers/toConsumableArray');
var _toConsumableArray3 = _interopRequireDefault(_toConsumableArray2);
var _assign = require('babel-runtime/core-js/object/assign');
var _assign2 = _interopRequireDefault(_assign);
var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck');
var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
var _createClass2 = require('babel-runtime/helpers/createClass');
var _createClass3 = _interopRequireDefault(_createClass2);
var _path = require('path');
var _path2 = _interopRequireDefault(_path);
var _mocha = require('mocha');
var _mocha2 = _interopRequireDefault(_mocha);
var _wdioSync = require('wdio-sync');
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
var INTERFACES = {
bdd: ['it', 'before', 'beforeEach', 'after', 'afterEach'],
tdd: ['test', 'suiteSetup', 'setup', 'suiteTeardown', 'teardown'],
qunit: ['test', 'before', 'beforeEach', 'after', 'afterEach']
};
var EVENTS = {
'suite': 'suite:start',
'suite end': 'suite:end',
'test': 'test:start',
'test end': 'test:end',
'hook': 'hook:start',
'hook end': 'hook:end',
'pass': 'test:pass',
'fail': 'test:fail',
'pending': 'test:pending'
};
var NOOP = function NOOP() {};
var SETTLE_TIMEOUT = 5000;
/**
* Extracts the mocha UI type following this convention:
* - If the mochaOpts.ui provided doesn't contain a '-' then the full name
* is taken as ui type (i.e. 'bdd','tdd','qunit')
* - If it contains a '-' then it asumes we are providing a custom ui for
* mocha. Then it extracts the text after the last '-' (ignoring .js if
* provided) as the interface type. (i.e. strong-bdd in
* https://github.com/strongloop/strong-mocha-interfaces)
*/
var MOCHA_UI_TYPE_EXTRACTOR = /^(?:.*-)?([^-.]+)(?:.js)?$/;
var DEFAULT_INTERFACE_TYPE = 'bdd';
/**
* Mocha runner
*/
var MochaAdapter = function () {
function MochaAdapter(cid, config, specs, capabilities) {
(0, _classCallCheck3.default)(this, MochaAdapter);
/**
* rename requires option to stay backwards compatible
* ToDo remove with next major release
*/
if (config.mochaOpts && config.mochaOpts.requires) {
if (Array.isArray(config.mochaOpts.require)) {
config.mochaOpts.require.push(config.mochaOpts.requires);
} else {
config.mochaOpts.require = config.mochaOpts.requires;
}
}
this.cid = cid;
this.capabilities = capabilities;
this.specs = specs;
this.config = (0, _assign2.default)({
mochaOpts: {}
}, config);
this.runner = {};
this.sentMessages = 0; // number of messages sent to the parent
this.receivedMessages = 0; // number of messages received by the parent
this.messageCounter = 0;
this.messageUIDs = {
suite: {},
hook: {},
test: {}
};
}
(0, _createClass3.default)(MochaAdapter, [{
key: 'options',
value: function options(_options, context) {
var _options$require = _options.require,
require = _options$require === undefined ? [] : _options$require,
_options$compilers = _options.compilers,
compilers = _options$compilers === undefined ? [] : _options$compilers;
if (typeof require === 'string') {
require = [require];
}
this.requireExternalModules([].concat((0, _toConsumableArray3.default)(compilers), (0, _toConsumableArray3.default)(require)), context);
}
}, {
key: 'run',
value: function () {
var _ref = (0, _asyncToGenerator3.default)( /*#__PURE__*/_regenerator2.default.mark(function _callee() {
var _this = this;
var mochaOpts, match, type, mocha, result;
return _regenerator2.default.wrap(function _callee$(_context) {
while (1) {
switch (_context.prev = _context.next) {
case 0:
mochaOpts = this.config.mochaOpts;
match = _get__('MOCHA_UI_TYPE_EXTRACTOR').exec(mochaOpts.ui);
type = match && _get__('INTERFACES')[match[1]] && match[1] || _get__('DEFAULT_INTERFACE_TYPE');
mocha = new (_get__('Mocha'))(mochaOpts);
mocha.loadFiles();
mocha.reporter(_get__('NOOP'));
mocha.fullTrace();
this.specs.forEach(function (spec) {
return mocha.addFile(spec);
});
_get__('wrapCommands')(global.browser, this.config.beforeCommand, this.config.afterCommand);
mocha.suite.on('pre-require', function (context, file, mocha) {
_this.options(mochaOpts, {
context: context, file: file, mocha: mocha, options: mochaOpts
});
_get__('INTERFACES')[type].forEach(function (fnName) {
var testCommand = _get__('INTERFACES')[type][0];
_get__('runInFiberContext')([testCommand, testCommand + '.only'], _this.config.beforeHook, _this.config.afterHook, fnName);
});
});
_context.next = 12;
return _get__('executeHooksWithArgs')(this.config.before, [this.capabilities, this.specs]);
case 12:
_context.next = 14;
return new _promise2.default(function (resolve, reject) {
_this.runner = mocha.run(resolve);
(0, _keys2.default)(_get__('EVENTS')).forEach(function (e) {
return _this.runner.on(e, _this.emit.bind(_this, _get__('EVENTS')[e]));
});
_this.runner.suite.beforeAll(_this.wrapHook('beforeSuite'));
_this.runner.suite.beforeEach(_this.wrapHook('beforeTest'));
_this.runner.suite.afterEach(_this.wrapHook('afterTest'));
_this.runner.suite.afterAll(_this.wrapHook('afterSuite'));
});
case 14:
result = _context.sent;
_context.next = 17;
return _get__('executeHooksWithArgs')(this.config.after, [result, this.capabilities, this.specs]);
case 17:
_context.next = 19;
return this.waitUntilSettled();
case 19:
return _context.abrupt('return', result);
case 20:
case 'end':
return _context.stop();
}
}
}, _callee, this);
}));
function run() {
return _ref.apply(this, arguments);
}
return run;
}()
/**
* Hooks which are added as true Mocha hooks need to call done() to notify async
*/
}, {
key: 'wrapHook',
value: function wrapHook(hookName) {
var _this2 = this;
return function () {
return _get__('executeHooksWithArgs')(_this2.config[hookName], _this2.prepareMessage(hookName)).catch(function (e) {
console.log('Error in ' + hookName + ' hook', e.stack);
});
};
}
}, {
key: 'prepareMessage',
value: function prepareMessage(hookName) {
var params = { type: hookName };
switch (hookName) {
case 'beforeSuite':
case 'afterSuite':
params.payload = this.runner.suite.suites[0];
break;
case 'beforeTest':
case 'afterTest':
params.payload = this.runner.test;
break;
}
params.err = this.runner.lastError;
delete this.runner.lastError;
return this.formatMessage(params);
}
}, {
key: 'formatMessage',
value: function formatMessage(params) {
var message = {
type: params.type
};
if (params.err) {
message.err = {
message: params.err.message,
stack: params.err.stack,
type: params.err.type || params.err.name,
expected: params.err.expected,
actual: params.err.actual
};
}
if (params.payload) {
message.title = params.payload.title;
message.parent = params.payload.parent ? params.payload.parent.title : null;
/**
* get title for hooks in root suite
*/
if (message.parent === '' && params.payload.parent && params.payload.parent.suites) {
message.parent = params.payload.parent.suites[0].title;
}
message.fullTitle = params.payload.fullTitle ? params.payload.fullTitle() : message.parent + ' ' + message.title;
message.pending = params.payload.pending || false;
message.file = params.payload.file;
// Add the current test title to the payload for cases where it helps to
// identify the test, e.g. when running inside a beforeEach hook
if (params.payload.ctx && params.payload.ctx.currentTest) {
message.currentTest = params.payload.ctx.currentTest.title;
}
if (params.type.match(/Test/)) {
message.passed = params.payload.state === 'passed';
message.duration = params.payload.duration;
}
if (params.payload.context) {
message.context = params.payload.context;
}
}
return message;
}
}, {
key: 'requireExternalModules',
value: function requireExternalModules(modules, context) {
var _this3 = this;
modules.forEach(function (module) {
if (module) {
module = module.replace(/.*:/, '');
if (module.substr(0, 1) === '.') {
module = _get__('path').join(process.cwd(), module);
}
_this3.load(module, context);
}
});
}
}, {
key: 'emit',
value: function emit(event, payload, err) {
var _this4 = this;
// For some reason, Mocha fires a second 'suite:end' event for the root suite,
// with no matching 'suite:start', so this can be ignored.
if (payload.root) return;
var message = this.formatMessage({ type: event, payload: payload, err: err });
message.cid = this.cid;
message.specs = this.specs;
message.event = event;
message.runner = {};
message.runner[this.cid] = this.capabilities;
if (err) {
this.runner.lastError = err;
}
var _generateUID = this.generateUID(message),
uid = _generateUID.uid,
parentUid = _generateUID.parentUid;
message.uid = uid;
message.parentUid = parentUid;
// When starting a new test, propagate the details to the test runner so that
// commands, results, screenshots and hooks can be associated with this test
if (event === 'test:start') {
this.sendInternal(event, message);
}
this.send(message, null, {}, function () {
return ++_this4.receivedMessages;
});
this.sentMessages++;
}
}, {
key: 'generateUID',
value: function generateUID(message) {
var uid, parentUid;
switch (message.type) {
case 'suite:start':
uid = this.getUID(message.title, 'suite', true);
parentUid = uid;
break;
case 'suite:end':
uid = this.getUID(message.title, 'suite');
parentUid = uid;
break;
case 'hook:start':
uid = this.getUID(message.title, 'hook', true);
parentUid = this.getUID(message.parent, 'suite');
break;
case 'hook:end':
uid = this.getUID(message.title, 'hook');
parentUid = this.getUID(message.parent, 'suite');
break;
case 'test:start':
uid = this.getUID(message.title, 'test', true);
parentUid = this.getUID(message.parent, 'suite');
break;
case 'test:pending':
case 'test:end':
case 'test:pass':
case 'test:fail':
uid = this.getUID(message.title, 'test');
parentUid = this.getUID(message.parent, 'suite');
break;
default:
throw new Error('Unknown message type : ' + message.type);
}
return {
uid: uid,
parentUid: parentUid
};
}
}, {
key: 'getUID',
value: function getUID(title, type, start) {
if (start !== true && this.messageUIDs[type][title]) {
return this.messageUIDs[type][title];
}
var uid = title + this.messageCounter++;
this.messageUIDs[type][title] = uid;
return uid;
}
}, {
key: 'sendInternal',
value: function sendInternal(event, message) {
process.emit(event, message);
}
/**
* reset globals to rewire it out in tests
*/
}, {
key: 'send',
value: function send() {
for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
args[_key] = arguments[_key];
}
return process.send.apply(process, args);
}
/**
* wait until all messages were sent to parent
*/
}, {
key: 'waitUntilSettled',
value: function waitUntilSettled() {
var _this5 = this;
return new _promise2.default(function (resolve) {
var start = new Date().getTime();
var interval = setInterval(function () {
var now = new Date().getTime();
if (_this5.sentMessages !== _this5.receivedMessages && now - start < _get__('SETTLE_TIMEOUT')) return;
clearInterval(interval);
resolve();
}, 100);
});
}
}, {
key: 'load',
value: function load(name, context) {
try {
module.context = context;
require(name);
} catch (e) {
throw new Error('Module ' + name + ' can\'t get loaded. Are you sure you have installed it?\n' + 'Note: if you\'ve installed WebdriverIO globally you need to install ' + 'these external modules globally too!');
}
}
}]);
return MochaAdapter;
}();
var _MochaAdapter = _get__('MochaAdapter');
var adapterFactory = {};
_get__('adapterFactory').run = function () {
var _ref2 = (0, _asyncToGenerator3.default)( /*#__PURE__*/_regenerator2.default.mark(function _callee2(cid, config, specs, capabilities) {
var adapter, result;
return _regenerator2.default.wrap(function _callee2$(_context2) {
while (1) {
switch (_context2.prev = _context2.next) {
case 0:
adapter = new (_get__('_MochaAdapter'))(cid, config, specs, capabilities);
_context2.next = 3;
return adapter.run();
case 3:
result = _context2.sent;
return _context2.abrupt('return', result);
case 5:
case 'end':
return _context2.stop();
}
}
}, _callee2, this);
}));
return function (_x, _x2, _x3, _x4) {
return _ref2.apply(this, arguments);
};
}();
exports.default = _get__('adapterFactory');
exports.MochaAdapter = MochaAdapter;
exports.adapterFactory = adapterFactory;
function _getGlobalObject() {
try {
if (!!global) {
return global;
}
} catch (e) {
try {
if (!!window) {
return window;
}
} catch (e) {
return this;
}
}
}
;
var _RewireModuleId__ = null;
function _getRewireModuleId__() {
if (_RewireModuleId__ === null) {
var globalVariable = _getGlobalObject();
if (!globalVariable.__$$GLOBAL_REWIRE_NEXT_MODULE_ID__) {
globalVariable.__$$GLOBAL_REWIRE_NEXT_MODULE_ID__ = 0;
}
_RewireModuleId__ = __$$GLOBAL_REWIRE_NEXT_MODULE_ID__++;
}
return _RewireModuleId__;
}
function _getRewireRegistry__() {
var theGlobalVariable = _getGlobalObject();
if (!theGlobalVariable.__$$GLOBAL_REWIRE_REGISTRY__) {
theGlobalVariable.__$$GLOBAL_REWIRE_REGISTRY__ = (0, _create2.default)(null);
}
return __$$GLOBAL_REWIRE_REGISTRY__;
}
function _getRewiredData__() {
var moduleId = _getRewireModuleId__();
var registry = _getRewireRegistry__();
var rewireData = registry[moduleId];
if (!rewireData) {
registry[moduleId] = (0, _create2.default)(null);
rewireData = registry[moduleId];
}
return rewireData;
}
(function registerResetAll() {
var theGlobalVariable = _getGlobalObject();
if (!theGlobalVariable['__rewire_reset_all__']) {
theGlobalVariable['__rewire_reset_all__'] = function () {
theGlobalVariable.__$$GLOBAL_REWIRE_REGISTRY__ = (0, _create2.default)(null);
};
}
})();
var INTENTIONAL_UNDEFINED = '__INTENTIONAL_UNDEFINED__';
var _RewireAPI__ = {};
(function () {
function addPropertyToAPIObject(name, value) {
(0, _defineProperty2.default)(_RewireAPI__, name, {
value: value,
enumerable: false,
configurable: true
});
}
addPropertyToAPIObject('__get__', _get__);
addPropertyToAPIObject('__GetDependency__', _get__);
addPropertyToAPIObject('__Rewire__', _set__);
addPropertyToAPIObject('__set__', _set__);
addPropertyToAPIObject('__reset__', _reset__);
addPropertyToAPIObject('__ResetDependency__', _reset__);
addPropertyToAPIObject('__with__', _with__);
})();
function _get__(variableName) {
var rewireData = _getRewiredData__();
if (rewireData[variableName] === undefined) {
return _get_original__(variableName);
} else {
var value = rewireData[variableName];
if (value === INTENTIONAL_UNDEFINED) {
return undefined;
} else {
return value;
}
}
}
function _get_original__(variableName) {
switch (variableName) {
case 'MOCHA_UI_TYPE_EXTRACTOR':
return MOCHA_UI_TYPE_EXTRACTOR;
case 'INTERFACES':
return INTERFACES;
case 'DEFAULT_INTERFACE_TYPE':
return DEFAULT_INTERFACE_TYPE;
case 'Mocha':
return _mocha2.default;
case 'NOOP':
return NOOP;
case 'wrapCommands':
return _wdioSync.wrapCommands;
case 'runInFiberContext':
return _wdioSync.runInFiberContext;
case 'executeHooksWithArgs':
return _wdioSync.executeHooksWithArgs;
case 'EVENTS':
return EVENTS;
case 'path':
return _path2.default;
case 'SETTLE_TIMEOUT':
return SETTLE_TIMEOUT;
case 'MochaAdapter':
return MochaAdapter;
case 'adapterFactory':
return adapterFactory;
case '_MochaAdapter':
return _MochaAdapter;
}
return undefined;
}
function _assign__(variableName, value) {
var rewireData = _getRewiredData__();
if (rewireData[variableName] === undefined) {
return _set_original__(variableName, value);
} else {
return rewireData[variableName] = value;
}
}
function _set_original__(variableName, _value) {
switch (variableName) {}
return undefined;
}
function _update_operation__(operation, variableName, prefix) {
var oldValue = _get__(variableName);
var newValue = operation === '++' ? oldValue + 1 : oldValue - 1;
_assign__(variableName, newValue);
return prefix ? newValue : oldValue;
}
function _set__(variableName, value) {
var rewireData = _getRewiredData__();
if ((typeof variableName === 'undefined' ? 'undefined' : (0, _typeof3.default)(variableName)) === 'object') {
(0, _keys2.default)(variableName).forEach(function (name) {
rewireData[name] = variableName[name];
});
} else {
if (value === undefined) {
rewireData[variableName] = INTENTIONAL_UNDEFINED;
} else {
rewireData[variableName] = value;
}
return function () {
_reset__(variableName);
};
}
}
function _reset__(variableName) {
var rewireData = _getRewiredData__();
delete rewireData[variableName];
if ((0, _keys2.default)(rewireData).length == 0) {
delete _getRewireRegistry__()[_getRewireModuleId__];
}
;
}
function _with__(object) {
var rewireData = _getRewiredData__();
var rewiredVariableNames = (0, _keys2.default)(object);
var previousValues = {};
function reset() {
rewiredVariableNames.forEach(function (variableName) {
rewireData[variableName] = previousValues[variableName];
});
}
return function (callback) {
rewiredVariableNames.forEach(function (variableName) {
previousValues[variableName] = rewireData[variableName];
rewireData[variableName] = object[variableName];
});
var result = callback();
if (!!result && typeof result.then == 'function') {
result.then(reset).catch(reset);
} else {
reset();
}
return result;
};
}
var _typeOfOriginalExport = typeof adapterFactory === 'undefined' ? 'undefined' : (0, _typeof3.default)(adapterFactory);
function addNonEnumerableProperty(name, value) {
(0, _defineProperty2.default)(adapterFactory, name, {
value: value,
enumerable: false,
configurable: true
});
}
if ((_typeOfOriginalExport === 'object' || _typeOfOriginalExport === 'function') && (0, _isExtensible2.default)(adapterFactory)) {
addNonEnumerableProperty('__get__', _get__);
addNonEnumerableProperty('__GetDependency__', _get__);
addNonEnumerableProperty('__Rewire__', _set__);
addNonEnumerableProperty('__set__', _set__);
addNonEnumerableProperty('__reset__', _reset__);
addNonEnumerableProperty('__ResetDependency__', _reset__);
addNonEnumerableProperty('__with__', _with__);
addNonEnumerableProperty('__RewireAPI__', _RewireAPI__);
}
exports.__get__ = _get__;
exports.__GetDependency__ = _get__;
exports.__Rewire__ = _set__;
exports.__set__ = _set__;
exports.__ResetDependency__ = _reset__;
exports.__RewireAPI__ = _RewireAPI__;