@@ -8,2 +8,3 @@ # Changelog | ||
### Bug Fixes | ||
* Firefox now launches successfully if TestCafe installation directory contains whitespaces ([#1042](https://github.com/DevExpress/testcafe/issues/1042)). | ||
@@ -10,0 +11,0 @@ |
@@ -122,3 +122,3 @@ 'use strict'; | ||
this.program.version(version, '-v, --version').usage('[options] <comma-separated-browser-list> <file-or-glob ...>').description(CLIArgumentParser._getDescription()).option('-b, --list-browsers [provider]', 'output the aliases for local browsers or browsers available through the specified browser provider').option('-r, --reporter <name>', 'specify the reporter type to use').option('-s, --screenshots <path>', 'enable screenshot capturing and specify the path to save the screenshots to').option('-S, --screenshots-on-fails', 'take a screenshot whenever a test fails').option('-q, --quarantine-mode', 'enable the quarantine mode').option('-e, --skip-js-errors', 'make tests not fail when a JS error happens on a page').option('-t, --test <name>', 'run only tests with the specified name').option('-T, --test-grep <pattern>', 'run only tests matching the specified pattern').option('-f, --fixture <name>', 'run only fixtures with the specified name').option('-F, --fixture-grep <pattern>', 'run only fixtures matching the specified pattern').option('--selector-timeout <ms>', 'set the amount of time within which selectors make attempts to obtain a node to be returned').option('--assertion-timeout <ms>', 'set the amount of time within which assertion should pass').option('--speed <factor>', 'set the speed of test execution (0.01 ... 1)').option('--ports <port1,port2>', 'specify custom port numbers').option('--hostname <name>', 'specify the hostname').option('--qr-code', 'outputs QR-code that repeats URLs used to connect the remote browsers') | ||
this.program.version(version, '-v, --version').usage('[options] <comma-separated-browser-list> <file-or-glob ...>').description(CLIArgumentParser._getDescription()).option('-b, --list-browsers [provider]', 'output the aliases for local browsers or browsers available through the specified browser provider').option('-r, --reporter <name>', 'specify the reporter type to use').option('-s, --screenshots <path>', 'enable screenshot capturing and specify the path to save the screenshots to').option('-S, --screenshots-on-fails', 'take a screenshot whenever a test fails').option('-q, --quarantine-mode', 'enable the quarantine mode').option('-e, --skip-js-errors', 'make tests not fail when a JS error happens on a page').option('-t, --test <name>', 'run only tests with the specified name').option('-T, --test-grep <pattern>', 'run only tests matching the specified pattern').option('-f, --fixture <name>', 'run only fixtures with the specified name').option('-F, --fixture-grep <pattern>', 'run only fixtures matching the specified pattern').option('-a, --app <command>', 'launch the tested app using the specified command before running tests').option('--app-init-delay <ms>', 'specify how much time it takes for the tested app to initialize').option('--selector-timeout <ms>', 'set the amount of time within which selectors make attempts to obtain a node to be returned').option('--assertion-timeout <ms>', 'set the amount of time within which assertion should pass').option('--speed <factor>', 'set the speed of test execution (0.01 ... 1)').option('--ports <port1,port2>', 'specify custom port numbers').option('--hostname <name>', 'specify the hostname').option('--qr-code', 'outputs QR-code that repeats URLs used to connect the remote browsers') | ||
@@ -160,2 +160,8 @@ // NOTE: these options will be handled by chalk internally | ||
CLIArgumentParser.prototype._parseAppInitDelay = function _parseAppInitDelay() { | ||
if (this.opts.appInitDelay) { | ||
if (CLIArgumentParser._isInteger(this.opts.appInitDelay)) this.opts.appInitDelay = parseInt(this.opts.appInitDelay, 10);else throw new _runtime.GeneralError(_message2.default.appInitDelayIsNotAnInteger); | ||
} | ||
}; | ||
CLIArgumentParser.prototype._parseSelectorTimeout = function _parseSelectorTimeout() { | ||
@@ -385,7 +391,13 @@ if (this.opts.selectorTimeout) { | ||
this._parseFilteringOptions(); | ||
this._parseSelectorTimeout(); | ||
this._parseAssertionTimeout(); | ||
this._parseAppInitDelay(); | ||
this._parseSpeed(); | ||
this._parsePorts(); | ||
this._parseBrowserList(); | ||
_context5.next = 8; | ||
return _pinkie2.default.all([this._parseSelectorTimeout(), this._parseAssertionTimeout(), this._parseSpeed(), this._parsePorts(), this._parseScreenshotsPath(), this._parseBrowserList(), this._parseFileList()]); | ||
_context5.next = 14; | ||
return _pinkie2.default.all([this._parseScreenshotsPath(), this._parseFileList()]); | ||
case 8: | ||
case 14: | ||
case 'end': | ||
@@ -392,0 +404,0 @@ return _context5.stop(); |
@@ -40,3 +40,3 @@ 'use strict'; | ||
runner.src(argParser.src).browsers(browsers).reporter(opts.reporter).filter(argParser.filter).screenshots(opts.screenshots, opts.screenshotsOnFails); | ||
runner.src(argParser.src).browsers(browsers).reporter(opts.reporter).filter(argParser.filter).screenshots(opts.screenshots, opts.screenshotsOnFails).startApp(opts.app, opts.appInitDelay); | ||
@@ -49,8 +49,3 @@ runner.once('done-bootstrapping', function () { | ||
_context.next = 18; | ||
return runner.run({ | ||
skipJsErrors: opts.skipJsErrors, | ||
quarantineMode: opts.quarantineMode, | ||
selectorTimeout: opts.selectorTimeout, | ||
speed: opts.speed | ||
}); | ||
return runner.run(opts); | ||
@@ -57,0 +52,0 @@ case 18: |
@@ -96,3 +96,3 @@ 'use strict'; | ||
var filterNodes = new _clientFunctionBuilder2.default(function (nodes, filter, querySelectorRoot) { | ||
var filterNodes = new _clientFunctionBuilder2.default(function (nodes, filter, querySelectorRoot, originNode) { | ||
if (typeof filter === 'number') return [nodes[filter]]; | ||
@@ -118,3 +118,3 @@ | ||
for (var j = 0; j < nodes.length; j++) { | ||
if (filter(nodes[j], j)) result.push(nodes[j]); | ||
if (filter(nodes[j], j, originNode)) result.push(nodes[j]); | ||
} | ||
@@ -410,3 +410,3 @@ } | ||
return filterNodes(nodes, filter, document); | ||
return filterNodes(nodes, filter, document, void 0); | ||
/* eslint-enable no-undef */ | ||
@@ -449,3 +449,3 @@ }; | ||
return filterNodes(results, filter, null); | ||
return filterNodes(results, filter, null, node); | ||
}); | ||
@@ -469,5 +469,5 @@ /* eslint-enable no-undef */ | ||
for (node = node.parentNode; node; node = node.parentNode) { | ||
parents.push(node); | ||
}return filter !== void 0 ? filterNodes(parents, filter, document) : parents; | ||
for (var parent = node.parentNode; parent; parent = parent.parentNode) { | ||
parents.push(parent); | ||
}return filter !== void 0 ? filterNodes(parents, filter, document, node) : parents; | ||
}); | ||
@@ -498,3 +498,3 @@ /* eslint-enable no-undef */ | ||
return filter !== void 0 ? filterNodes(childElements, filter, node) : childElements; | ||
return filter !== void 0 ? filterNodes(childElements, filter, node, node) : childElements; | ||
}); | ||
@@ -529,3 +529,3 @@ /* eslint-enable no-undef */ | ||
return filter !== void 0 ? filterNodes(siblings, filter, parent) : siblings; | ||
return filter !== void 0 ? filterNodes(siblings, filter, parent, node) : siblings; | ||
}); | ||
@@ -532,0 +532,0 @@ /* eslint-enable no-undef */ |
@@ -18,2 +18,4 @@ 'use strict'; | ||
assertionTimeoutIsNotAnInteger: 'Assertion timeout should be an integer.', | ||
appInitDelayIsNotAnInteger: 'Tested app initialization delay should be an integer.', | ||
testedAppFailedWithError: 'Tested app failed with an error:\n\n{errMessage}', | ||
invalidSpeedValue: 'Speed should be a number between 0.01 and 1.', | ||
@@ -20,0 +22,0 @@ portsOptionRequiresTwoNumbers: 'The "--ports" option requires two numbers to be specified.', |
@@ -45,4 +45,10 @@ 'use strict'; | ||
var _testedApp = require('./tested-app'); | ||
var _testedApp2 = _interopRequireDefault(_testedApp); | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
var DEFAULT_APP_INIT_DELAY = 1000; | ||
var Bootstrapper = function () { | ||
@@ -58,2 +64,4 @@ function Bootstrapper(browserConnectionGateway) { | ||
this.reporter = null; | ||
this.appCommand = null; | ||
this.appInitDelay = DEFAULT_APP_INIT_DELAY; | ||
} | ||
@@ -209,2 +217,39 @@ | ||
Bootstrapper.prototype._startTestedApp = function () { | ||
var _ref4 = (0, _asyncToGenerator3.default)(_regenerator2.default.mark(function _callee4() { | ||
var testedApp; | ||
return _regenerator2.default.wrap(function _callee4$(_context4) { | ||
while (1) { | ||
switch (_context4.prev = _context4.next) { | ||
case 0: | ||
if (!this.appCommand) { | ||
_context4.next = 5; | ||
break; | ||
} | ||
testedApp = new _testedApp2.default(); | ||
_context4.next = 4; | ||
return testedApp.start(this.appCommand, this.appInitDelay); | ||
case 4: | ||
return _context4.abrupt('return', testedApp); | ||
case 5: | ||
return _context4.abrupt('return', null); | ||
case 6: | ||
case 'end': | ||
return _context4.stop(); | ||
} | ||
} | ||
}, _callee4, this); | ||
})); | ||
function _startTestedApp() { | ||
return _ref4.apply(this, arguments); | ||
} | ||
return _startTestedApp; | ||
}(); | ||
// API | ||
@@ -214,7 +259,7 @@ | ||
Bootstrapper.prototype.createRunnableConfiguration = function () { | ||
var _ref4 = (0, _asyncToGenerator3.default)(_regenerator2.default.mark(function _callee4() { | ||
var reporterPlugin, browserInfo, tests, browserSet; | ||
return _regenerator2.default.wrap(function _callee4$(_context4) { | ||
var _ref5 = (0, _asyncToGenerator3.default)(_regenerator2.default.mark(function _callee5() { | ||
var reporterPlugin, browserInfo, tests, testedApp, browserSet; | ||
return _regenerator2.default.wrap(function _callee5$(_context5) { | ||
while (1) { | ||
switch (_context4.prev = _context4.next) { | ||
switch (_context5.prev = _context5.next) { | ||
case 0: | ||
@@ -228,29 +273,34 @@ reporterPlugin = this._getReporterPlugin(); | ||
_context4.next = 3; | ||
_context5.next = 3; | ||
return this._getBrowserInfo(); | ||
case 3: | ||
browserInfo = _context4.sent; | ||
_context4.next = 6; | ||
browserInfo = _context5.sent; | ||
_context5.next = 6; | ||
return this._getTests(); | ||
case 6: | ||
tests = _context4.sent; | ||
_context4.next = 9; | ||
return this._getBrowserConnections(browserInfo); | ||
tests = _context5.sent; | ||
_context5.next = 9; | ||
return this._startTestedApp(); | ||
case 9: | ||
browserSet = _context4.sent; | ||
return _context4.abrupt('return', { reporterPlugin: reporterPlugin, browserSet: browserSet, tests: tests }); | ||
testedApp = _context5.sent; | ||
_context5.next = 12; | ||
return this._getBrowserConnections(browserInfo); | ||
case 11: | ||
case 12: | ||
browserSet = _context5.sent; | ||
return _context5.abrupt('return', { reporterPlugin: reporterPlugin, browserSet: browserSet, tests: tests, testedApp: testedApp }); | ||
case 14: | ||
case 'end': | ||
return _context4.stop(); | ||
return _context5.stop(); | ||
} | ||
} | ||
}, _callee4, this); | ||
}, _callee5, this); | ||
})); | ||
function createRunnableConfiguration() { | ||
return _ref4.apply(this, arguments); | ||
return _ref5.apply(this, arguments); | ||
} | ||
@@ -257,0 +307,0 @@ |
@@ -89,4 +89,4 @@ 'use strict'; | ||
Runner._disposeTaskAndBrowsers = function () { | ||
var _ref = (0, _asyncToGenerator3.default)(_regenerator2.default.mark(function _callee(task, browserSet) { | ||
Runner._disposeTaskAndRelatedAssets = function () { | ||
var _ref = (0, _asyncToGenerator3.default)(_regenerator2.default.mark(function _callee(task, browserSet, testedApp) { | ||
return _regenerator2.default.wrap(function _callee$(_context) { | ||
@@ -100,3 +100,3 @@ while (1) { | ||
_context.next = 4; | ||
return browserSet.dispose(); | ||
return Runner._disposeBrowserSetAndTestedApp(browserSet, testedApp); | ||
@@ -111,14 +111,47 @@ case 4: | ||
function _disposeTaskAndBrowsers(_x, _x2) { | ||
function _disposeTaskAndRelatedAssets(_x, _x2, _x3) { | ||
return _ref.apply(this, arguments); | ||
} | ||
return _disposeTaskAndBrowsers; | ||
return _disposeTaskAndRelatedAssets; | ||
}(); | ||
Runner._disposeBrowserSetAndTestedApp = function () { | ||
var _ref2 = (0, _asyncToGenerator3.default)(_regenerator2.default.mark(function _callee2(browserSet, testedApp) { | ||
return _regenerator2.default.wrap(function _callee2$(_context2) { | ||
while (1) { | ||
switch (_context2.prev = _context2.next) { | ||
case 0: | ||
_context2.next = 2; | ||
return browserSet.dispose(); | ||
case 2: | ||
if (!testedApp) { | ||
_context2.next = 5; | ||
break; | ||
} | ||
_context2.next = 5; | ||
return testedApp.kill(); | ||
case 5: | ||
case 'end': | ||
return _context2.stop(); | ||
} | ||
} | ||
}, _callee2, this); | ||
})); | ||
function _disposeBrowserSetAndTestedApp(_x4, _x5) { | ||
return _ref2.apply(this, arguments); | ||
} | ||
return _disposeBrowserSetAndTestedApp; | ||
}(); | ||
Runner.prototype._createCancelablePromise = function _createCancelablePromise(taskPromise) { | ||
var _this2 = this; | ||
var promise = taskPromise.then(function (_ref2) { | ||
var completionPromise = _ref2.completionPromise; | ||
var promise = taskPromise.then(function (_ref3) { | ||
var completionPromise = _ref3.completionPromise; | ||
return completionPromise; | ||
@@ -133,4 +166,4 @@ }); | ||
promise.cancel = function () { | ||
return taskPromise.then(function (_ref3) { | ||
var cancelTask = _ref3.cancelTask; | ||
return taskPromise.then(function (_ref4) { | ||
var cancelTask = _ref4.cancelTask; | ||
return cancelTask(); | ||
@@ -148,6 +181,7 @@ }).then(removeFromPending); | ||
Runner.prototype._getTaskResult = function () { | ||
var _ref4 = (0, _asyncToGenerator3.default)(_regenerator2.default.mark(function _callee2(task, browserSet, reporter) { | ||
return _regenerator2.default.wrap(function _callee2$(_context2) { | ||
var _ref5 = (0, _asyncToGenerator3.default)(_regenerator2.default.mark(function _callee3(task, browserSet, reporter, testedApp) { | ||
var promises; | ||
return _regenerator2.default.wrap(function _callee3$(_context3) { | ||
while (1) { | ||
switch (_context2.prev = _context2.next) { | ||
switch (_context3.prev = _context3.next) { | ||
case 0: | ||
@@ -158,36 +192,41 @@ task.on('browser-job-done', function (job) { | ||
_context2.prev = 1; | ||
_context2.next = 4; | ||
return _pinkie2.default.race([(0, _promisifyEvent2.default)(task, 'done'), (0, _promisifyEvent2.default)(browserSet, 'error')]); | ||
promises = [(0, _promisifyEvent2.default)(task, 'done'), (0, _promisifyEvent2.default)(browserSet, 'error')]; | ||
case 4: | ||
_context2.next = 11; | ||
break; | ||
if (testedApp) promises.push(testedApp.errorPromise); | ||
_context3.prev = 3; | ||
_context3.next = 6; | ||
return _pinkie2.default.race(promises); | ||
case 6: | ||
_context2.prev = 6; | ||
_context2.t0 = _context2['catch'](1); | ||
_context2.next = 10; | ||
return Runner._disposeTaskAndBrowsers(task, browserSet); | ||
_context3.next = 13; | ||
break; | ||
case 10: | ||
throw _context2.t0; | ||
case 8: | ||
_context3.prev = 8; | ||
_context3.t0 = _context3['catch'](3); | ||
_context3.next = 12; | ||
return Runner._disposeTaskAndRelatedAssets(task, browserSet, testedApp); | ||
case 11: | ||
_context2.next = 13; | ||
return browserSet.dispose(); | ||
case 12: | ||
throw _context3.t0; | ||
case 13: | ||
return _context2.abrupt('return', reporter.testCount - reporter.passed); | ||
_context3.next = 15; | ||
return Runner._disposeBrowserSetAndTestedApp(browserSet, testedApp); | ||
case 14: | ||
case 15: | ||
return _context3.abrupt('return', reporter.testCount - reporter.passed); | ||
case 16: | ||
case 'end': | ||
return _context2.stop(); | ||
return _context3.stop(); | ||
} | ||
} | ||
}, _callee2, this, [[1, 6]]); | ||
}, _callee3, this, [[3, 8]]); | ||
})); | ||
function _getTaskResult(_x3, _x4, _x5) { | ||
return _ref4.apply(this, arguments); | ||
function _getTaskResult(_x6, _x7, _x8, _x9) { | ||
return _ref5.apply(this, arguments); | ||
} | ||
@@ -198,3 +237,3 @@ | ||
Runner.prototype._runTask = function _runTask(reporterPlugin, browserSet, tests) { | ||
Runner.prototype._runTask = function _runTask(reporterPlugin, browserSet, tests, testedApp) { | ||
var _this3 = this; | ||
@@ -205,4 +244,6 @@ | ||
var reporter = new _reporter3.default(reporterPlugin, task, this.opts.reportOutStream); | ||
var completionPromise = this._getTaskResult(task, browserSet, reporter); | ||
var completionPromise = this._getTaskResult(task, browserSet, reporter, testedApp); | ||
if (testedApp) completionPromise = _pinkie2.default.race([completionPromise, testedApp.errorPromise]); | ||
var setCompleted = function setCompleted() { | ||
@@ -215,25 +256,25 @@ completed = true; | ||
var cancelTask = function () { | ||
var _ref5 = (0, _asyncToGenerator3.default)(_regenerator2.default.mark(function _callee3() { | ||
return _regenerator2.default.wrap(function _callee3$(_context3) { | ||
var _ref6 = (0, _asyncToGenerator3.default)(_regenerator2.default.mark(function _callee4() { | ||
return _regenerator2.default.wrap(function _callee4$(_context4) { | ||
while (1) { | ||
switch (_context3.prev = _context3.next) { | ||
switch (_context4.prev = _context4.next) { | ||
case 0: | ||
if (completed) { | ||
_context3.next = 3; | ||
_context4.next = 3; | ||
break; | ||
} | ||
_context3.next = 3; | ||
return Runner._disposeTaskAndBrowsers(task, browserSet); | ||
_context4.next = 3; | ||
return Runner._disposeTaskAndRelatedAssets(task, browserSet, testedApp); | ||
case 3: | ||
case 'end': | ||
return _context3.stop(); | ||
return _context4.stop(); | ||
} | ||
} | ||
}, _callee3, _this3); | ||
}, _callee4, _this3); | ||
})); | ||
return function cancelTask() { | ||
return _ref5.apply(this, arguments); | ||
return _ref6.apply(this, arguments); | ||
}; | ||
@@ -294,12 +335,19 @@ }(); | ||
Runner.prototype.startApp = function startApp(command, initDelay) { | ||
this.bootstrapper.appCommand = command; | ||
this.bootstrapper.appInitDelay = initDelay; | ||
return this; | ||
}; | ||
Runner.prototype.run = function run() { | ||
var _this4 = this; | ||
var _ref6 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}, | ||
skipJsErrors = _ref6.skipJsErrors, | ||
quarantineMode = _ref6.quarantineMode, | ||
selectorTimeout = _ref6.selectorTimeout, | ||
assertionTimeout = _ref6.assertionTimeout, | ||
_ref6$speed = _ref6.speed, | ||
speed = _ref6$speed === undefined ? 1 : _ref6$speed; | ||
var _ref7 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}, | ||
skipJsErrors = _ref7.skipJsErrors, | ||
quarantineMode = _ref7.quarantineMode, | ||
selectorTimeout = _ref7.selectorTimeout, | ||
assertionTimeout = _ref7.assertionTimeout, | ||
_ref7$speed = _ref7.speed, | ||
speed = _ref7$speed === undefined ? 1 : _ref7$speed; | ||
@@ -315,10 +363,11 @@ this.opts.skipJsErrors = !!skipJsErrors; | ||
var runTaskPromise = this.bootstrapper.createRunnableConfiguration().then(function (_ref7) { | ||
var reporterPlugin = _ref7.reporterPlugin, | ||
browserSet = _ref7.browserSet, | ||
tests = _ref7.tests; | ||
var runTaskPromise = this.bootstrapper.createRunnableConfiguration().then(function (_ref8) { | ||
var reporterPlugin = _ref8.reporterPlugin, | ||
browserSet = _ref8.browserSet, | ||
tests = _ref8.tests, | ||
testedApp = _ref8.testedApp; | ||
_this4.emit('done-bootstrapping'); | ||
return _this4._runTask(reporterPlugin, browserSet, tests); | ||
return _this4._runTask(reporterPlugin, browserSet, tests, testedApp); | ||
}); | ||
@@ -330,7 +379,7 @@ | ||
Runner.prototype.stop = function () { | ||
var _ref8 = (0, _asyncToGenerator3.default)(_regenerator2.default.mark(function _callee4() { | ||
var _ref9 = (0, _asyncToGenerator3.default)(_regenerator2.default.mark(function _callee5() { | ||
var cancellationPromises; | ||
return _regenerator2.default.wrap(function _callee4$(_context4) { | ||
return _regenerator2.default.wrap(function _callee5$(_context5) { | ||
while (1) { | ||
switch (_context4.prev = _context4.next) { | ||
switch (_context5.prev = _context5.next) { | ||
case 0: | ||
@@ -344,3 +393,3 @@ // NOTE: When taskPromise is cancelled, it is removed from | ||
}); | ||
_context4.next = 3; | ||
_context5.next = 3; | ||
return _pinkie2.default.all(cancellationPromises); | ||
@@ -350,10 +399,10 @@ | ||
case 'end': | ||
return _context4.stop(); | ||
return _context5.stop(); | ||
} | ||
} | ||
}, _callee4, this); | ||
}, _callee5, this); | ||
})); | ||
function stop() { | ||
return _ref8.apply(this, arguments); | ||
return _ref9.apply(this, arguments); | ||
} | ||
@@ -360,0 +409,0 @@ |
@@ -5,3 +5,3 @@ { | ||
"license": "MIT", | ||
"version": "0.12.0-alpha1", | ||
"version": "0.12.0-alpha2", | ||
"author": { | ||
@@ -104,2 +104,3 @@ "name": "Developer Express Inc.", | ||
"time-limit-promise": "^1.0.2", | ||
"tree-kill": "^1.1.0", | ||
"useragent": "^2.1.7" | ||
@@ -141,2 +142,3 @@ }, | ||
"gulp-webmake": "0.0.4", | ||
"http-server": "^0.9.0", | ||
"js-yaml": "^3.6.1", | ||
@@ -143,0 +145,0 @@ "markdownlint": ">=0.0.8", |
Shell access
Supply chain riskThis module accesses the system shell. Accessing the system shell increases the risk of executing arbitrary code.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 1 instance in 1 package
855514
1.12%106
0.95%11148
1.75%53
1.92%47
2.17%15
15.38%6
20%