testcafe
Version:
Automated browser testing for the modern web development stack.
607 lines • 103 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const path_1 = require("path");
const debug_1 = __importDefault(require("debug"));
const promisify_event_1 = __importDefault(require("promisify-event"));
const events_1 = require("events");
const lodash_1 = require("lodash");
const bootstrapper_1 = __importDefault(require("./bootstrapper"));
const reporter_1 = __importDefault(require("../reporter"));
const task_1 = __importDefault(require("./task"));
const debug_logger_1 = __importDefault(require("../notifications/debug-logger"));
const runtime_1 = require("../errors/runtime");
const types_1 = require("../errors/types");
const type_assertions_1 = require("../errors/runtime/type-assertions");
const utils_1 = require("../errors/test-run/utils");
const detect_ffmpeg_1 = __importDefault(require("../utils/detect-ffmpeg"));
const check_file_path_1 = __importDefault(require("../utils/check-file-path"));
const handle_errors_1 = require("../utils/handle-errors");
const option_names_1 = __importDefault(require("../configuration/option-names"));
const flag_list_1 = __importDefault(require("../utils/flag-list"));
const prepare_reporters_1 = __importDefault(require("../utils/prepare-reporters"));
const load_1 = __importDefault(require("../custom-client-scripts/load"));
const utils_2 = require("../custom-client-scripts/utils");
const reporter_stream_controller_1 = __importDefault(require("./reporter-stream-controller"));
const customizable_compilers_1 = __importDefault(require("../configuration/customizable-compilers"));
const string_1 = require("../utils/string");
const is_localhost_1 = __importDefault(require("../utils/is-localhost"));
const warning_log_1 = __importDefault(require("../notifications/warning-log"));
const authentication_helper_1 = __importDefault(require("../cli/authentication-helper"));
const testcafe_browser_tools_1 = require("testcafe-browser-tools");
const is_ci_1 = __importDefault(require("is-ci"));
const remote_1 = __importDefault(require("../browser/provider/built-in/remote"));
const connection_1 = __importDefault(require("../browser/connection"));
const os_family_1 = __importDefault(require("os-family"));
const detect_display_1 = __importDefault(require("../utils/detect-display"));
const quarantine_1 = require("../utils/get-options/quarantine");
const log_entry_1 = __importDefault(require("../utils/log-entry"));
const message_bus_1 = __importDefault(require("../utils/message-bus"));
const skip_js_errors_1 = require("../utils/get-options/skip-js-errors");
const DEBUG_LOGGER = (0, debug_1.default)('testcafe:runner');
class Runner extends events_1.EventEmitter {
constructor({ proxy, browserConnectionGateway, configuration }) {
super();
this._messageBus = new message_bus_1.default();
this.proxy = proxy;
this.bootstrapper = this._createBootstrapper(browserConnectionGateway, this._messageBus, configuration);
this.pendingTaskPromises = [];
this.configuration = configuration;
this.isCli = configuration._options && configuration._options.isCli;
this.warningLog = new warning_log_1.default(null, warning_log_1.default.createAddWarningCallback(this._messageBus));
this._options = {};
this._hasTaskErrors = false;
this._reporters = null;
this.apiMethodWasCalled = new flag_list_1.default([
option_names_1.default.src,
option_names_1.default.browsers,
option_names_1.default.reporter,
option_names_1.default.clientScripts,
]);
}
_createBootstrapper(browserConnectionGateway, messageBus, configuration) {
return new bootstrapper_1.default({ browserConnectionGateway, messageBus, configuration });
}
_disposeBrowserSet(browserSet) {
return browserSet.dispose().catch(e => DEBUG_LOGGER(e));
}
_disposeReporters(reporters) {
return Promise.all(reporters.map(reporter => reporter.dispose().catch(e => DEBUG_LOGGER(e))));
}
_disposeTestedApp(testedApp) {
return testedApp ? testedApp.kill().catch(e => DEBUG_LOGGER(e)) : Promise.resolve();
}
async _disposeTaskAndRelatedAssets(task, browserSet, reporters, testedApp) {
task.abort();
task.clearListeners();
this._messageBus.abort();
await this._disposeAssets(browserSet, reporters, testedApp);
}
_disposeAssets(browserSet, reporters, testedApp) {
return Promise.all([
this._disposeBrowserSet(browserSet),
this._disposeReporters(reporters),
this._disposeTestedApp(testedApp),
]);
}
_prepareArrayParameter(array) {
array = (0, lodash_1.flattenDeep)(array);
if (this.isCli)
return array.length === 0 ? void 0 : array;
return array;
}
_createCancelablePromise(taskPromise) {
const promise = taskPromise.then(({ completionPromise }) => completionPromise);
const removeFromPending = () => (0, lodash_1.pull)(this.pendingTaskPromises, promise);
promise
.then(removeFromPending)
.catch(removeFromPending);
promise.cancel = () => taskPromise
.then(({ cancelTask }) => cancelTask())
.then(removeFromPending);
this.pendingTaskPromises.push(promise);
return promise;
}
// Run task
_getFailedTestCount(task, reporter) {
let failedTestCount = reporter.taskInfo.testCount - reporter.taskInfo.passed;
if (task.opts.stopOnFirstFail && !!failedTestCount)
failedTestCount = 1;
return failedTestCount;
}
async _getTaskResult(task, browserSet, reporters, testedApp, runnableConfigurationId) {
if (!task.opts.live) {
task.on('browser-job-done', async (job) => {
await Promise.all(job.browserConnections.map(async (bc) => {
await browserSet.releaseConnection(bc);
}));
});
}
this._messageBus.clearListeners('error');
const browserSetErrorPromise = (0, promisify_event_1.default)(browserSet, 'error');
const taskErrorPromise = (0, promisify_event_1.default)(task, 'error');
const messageBusErrorPromise = (0, promisify_event_1.default)(this._messageBus, 'error');
const streamController = new reporter_stream_controller_1.default(this._messageBus, reporters);
const taskDonePromise = this._messageBus.once('done')
.then(() => browserSetErrorPromise.cancel())
.then(() => {
return Promise.all(reporters.map(reporter => reporter.taskInfo.pendingTaskDonePromise));
});
const promises = [
taskDonePromise,
browserSetErrorPromise,
taskErrorPromise,
messageBusErrorPromise,
];
if (testedApp)
promises.push(testedApp.errorPromise);
try {
await Promise.race(promises);
}
catch (err) {
await this._messageBus.emit('unhandled-rejection');
await Promise.all(reporters.map(reporter => reporter.taskInfo.pendingTaskDonePromise));
await this._disposeTaskAndRelatedAssets(task, browserSet, reporters, testedApp, runnableConfigurationId);
throw err;
}
await this._disposeAssets(browserSet, reporters, testedApp);
if (streamController.multipleStreamError)
throw streamController.multipleStreamError;
return this._getFailedTestCount(task, reporters[0]);
}
_createTask(tests, browserConnectionGroups, proxy, opts, warningLog) {
return new task_1.default({
tests,
browserConnectionGroups,
proxy,
opts,
runnerWarningLog: warningLog,
messageBus: this._messageBus,
});
}
_runTask({ reporters, browserSet, tests, testedApp, options, runnableConfigurationId }) {
const task = this._createTask(tests, browserSet.browserConnectionGroups, this.proxy, options, this.warningLog);
const completionPromise = this._getTaskResult(task, browserSet, reporters, testedApp, runnableConfigurationId);
let completed = false;
this._messageBus.on('start', handle_errors_1.startHandlingTestErrors);
if (!this.configuration.getOption(option_names_1.default.skipUncaughtErrors)) {
this._messageBus.on('test-run-start', handle_errors_1.addRunningTest);
this._messageBus.on('test-run-done', ({ errs }) => {
if (errs.length)
this._hasTaskErrors = true;
(0, handle_errors_1.removeRunningTest)();
});
}
this._messageBus.on('done', handle_errors_1.stopHandlingTestErrors);
this._messageBus.on('before-test-run-created-error', handle_errors_1.stopHandlingTestErrors);
task.on('error', handle_errors_1.stopHandlingTestErrors);
const onTaskCompleted = () => {
completed = true;
};
completionPromise
.then(onTaskCompleted)
.catch(onTaskCompleted);
const cancelTask = async () => {
if (!completed)
await this._disposeTaskAndRelatedAssets(task, browserSet, reporters, testedApp, runnableConfigurationId);
};
return { completionPromise, cancelTask };
}
_registerAssets(assets) {
assets.forEach(asset => this.proxy.GET(asset.path, asset.info));
}
_validateDebugLogger() {
const debugLogger = this.configuration.getOption(option_names_1.default.debugLogger);
const debugLoggerDefinedCorrectly = debugLogger === null || !!debugLogger &&
['showBreakpoint', 'hideBreakpoint'].every(method => method in debugLogger && (0, lodash_1.isFunction)(debugLogger[method]));
if (!debugLoggerDefinedCorrectly) {
this.configuration.mergeOptions({
[option_names_1.default.debugLogger]: debug_logger_1.default,
});
}
}
_validateSpeedOption() {
const speed = this.configuration.getOption(option_names_1.default.speed);
if (speed === void 0)
return;
if (typeof speed !== 'number' || isNaN(speed) || speed < 0.01 || speed > 1)
throw new runtime_1.GeneralError(types_1.RUNTIME_ERRORS.invalidSpeedValue);
}
_validateConcurrencyOption() {
const concurrency = this.configuration.getOption(option_names_1.default.concurrency);
if (concurrency === void 0)
return;
if (typeof concurrency !== 'number' || isNaN(concurrency) || concurrency < 1)
throw new runtime_1.GeneralError(types_1.RUNTIME_ERRORS.invalidConcurrencyFactor);
if (concurrency > 1 && this.bootstrapper.browsers.some(browser => {
return browser instanceof connection_1.default
? browser.browserInfo.browserOption.cdpPort
: browser.browserOption.cdpPort;
}))
throw new runtime_1.GeneralError(types_1.RUNTIME_ERRORS.cannotSetConcurrencyWithCDPPort);
}
_validateSkipJsErrorsOption() {
const skipJsErrorsOptions = this.configuration.getOption(option_names_1.default.skipJsErrors);
if (!skipJsErrorsOptions)
return;
(0, skip_js_errors_1.validateSkipJsErrorsOptionValue)(skipJsErrorsOptions, runtime_1.GeneralError);
}
_validateCustomActionsOption() {
const customActions = this.configuration.getOption(option_names_1.default.customActions);
if (!customActions)
return;
if (typeof customActions !== 'object')
throw new runtime_1.GeneralError(types_1.RUNTIME_ERRORS.invalidCustomActionsOptionType);
for (const name in customActions) {
if (typeof customActions[name] !== 'function')
throw new runtime_1.GeneralError(types_1.RUNTIME_ERRORS.invalidCustomActionType, name, typeof customActions[name]);
}
}
async _validateBrowsers() {
const browsers = this.configuration.getOption(option_names_1.default.browsers);
if (!browsers || Array.isArray(browsers) && !browsers.length)
throw new runtime_1.GeneralError(types_1.RUNTIME_ERRORS.browserNotSet);
if (os_family_1.default.mac)
await this._checkRequiredPermissions(browsers);
if (os_family_1.default.linux && !(0, detect_display_1.default)())
await this._checkThatTestsCanRunWithoutDisplay(browsers);
}
_validateRequestTimeoutOption(optionName) {
const requestTimeout = this.configuration.getOption(optionName);
if (requestTimeout === void 0)
return;
(0, type_assertions_1.assertType)(type_assertions_1.is.nonNegativeNumber, null, `"${optionName}" option`, requestTimeout);
}
_validateProxyBypassOption() {
let proxyBypass = this.configuration.getOption(option_names_1.default.proxyBypass);
if (proxyBypass === void 0)
return;
(0, type_assertions_1.assertType)([type_assertions_1.is.string, type_assertions_1.is.array], null, 'The "proxyBypass" argument', proxyBypass);
if (typeof proxyBypass === 'string')
proxyBypass = [proxyBypass];
proxyBypass = proxyBypass.reduce((arr, rules) => {
(0, type_assertions_1.assertType)(type_assertions_1.is.string, null, 'The "proxyBypass" argument', rules);
return arr.concat(rules.split(','));
}, []);
this.configuration.mergeOptions({ proxyBypass });
}
_getScreenshotOptions() {
let { path, pathPattern, pathPatternOnFails } = this.configuration.getOption(option_names_1.default.screenshots) || {};
if (!path)
path = this.configuration.getOption(option_names_1.default.screenshotPath);
if (!pathPattern)
pathPattern = this.configuration.getOption(option_names_1.default.screenshotPathPattern);
if (!pathPatternOnFails)
pathPatternOnFails = this.configuration.getOption(option_names_1.default.screenshotPathPatternOnFails);
return { path, pathPattern, pathPatternOnFails };
}
_validateScreenshotOptions() {
const { path, pathPattern, pathPatternOnFails } = this._getScreenshotOptions();
const disableScreenshots = this.configuration.getOption(option_names_1.default.disableScreenshots) || !path;
this.configuration.mergeOptions({ [option_names_1.default.disableScreenshots]: disableScreenshots });
if (disableScreenshots)
return;
if (path) {
this._validateScreenshotPath(path, 'screenshots base directory path');
this.configuration.mergeOptions({ [option_names_1.default.screenshots]: { path: (0, path_1.resolve)(path) } });
}
if (pathPattern) {
this._validateScreenshotPath(pathPattern, 'screenshots path pattern');
this.configuration.mergeOptions({ [option_names_1.default.screenshots]: { pathPattern } });
}
if (pathPatternOnFails) {
this._validateScreenshotPath(pathPatternOnFails, 'screenshots path pattern on fails');
this.configuration.mergeOptions({ [option_names_1.default.screenshots]: { pathPatternOnFails } });
}
}
async _validateVideoOptions() {
const videoPath = this.configuration.getOption(option_names_1.default.videoPath);
const videoEncodingOptions = this.configuration.getOption(option_names_1.default.videoEncodingOptions);
let videoOptions = this.configuration.getOption(option_names_1.default.videoOptions);
if (!videoPath) {
if (videoOptions || videoEncodingOptions)
throw new runtime_1.GeneralError(types_1.RUNTIME_ERRORS.cannotSetVideoOptionsWithoutBaseVideoPathSpecified);
return;
}
this.configuration.mergeOptions({ [option_names_1.default.videoPath]: (0, path_1.resolve)(videoPath) });
if (!videoOptions) {
videoOptions = {};
this.configuration.mergeOptions({ [option_names_1.default.videoOptions]: videoOptions });
}
if (videoOptions.ffmpegPath)
videoOptions.ffmpegPath = (0, path_1.resolve)(videoOptions.ffmpegPath);
else
videoOptions.ffmpegPath = await (0, detect_ffmpeg_1.default)();
if (!videoOptions.ffmpegPath)
throw new runtime_1.GeneralError(types_1.RUNTIME_ERRORS.cannotFindFFMPEG);
}
_validateCompilerOptions() {
const compilerOptions = this.configuration.getOption(option_names_1.default.compilerOptions);
if (!compilerOptions)
return;
const specifiedCompilers = Object.keys(compilerOptions);
const customizedCompilers = Object.keys(customizable_compilers_1.default);
const wrongCompilers = specifiedCompilers.filter(compiler => !customizedCompilers.includes(compiler));
if (!wrongCompilers.length)
return;
const compilerListStr = (0, string_1.getConcatenatedValuesString)(wrongCompilers, void 0, "'");
const pluralSuffix = (0, string_1.getPluralSuffix)(wrongCompilers);
throw new runtime_1.GeneralError(types_1.RUNTIME_ERRORS.cannotCustomizeSpecifiedCompilers, compilerListStr, pluralSuffix);
}
_validateRetryTestPagesOption() {
const retryTestPagesOption = this.configuration.getOption(option_names_1.default.retryTestPages);
if (!retryTestPagesOption)
return;
const ssl = this.configuration.getOption(option_names_1.default.ssl);
if (ssl)
return;
const hostname = this.configuration.getOption(option_names_1.default.hostname);
if ((0, is_localhost_1.default)(hostname))
return;
throw new runtime_1.GeneralError(types_1.RUNTIME_ERRORS.cannotEnableRetryTestPagesOption);
}
_validateQuarantineOptions() {
const quarantineMode = this.configuration.getOption(option_names_1.default.quarantineMode);
if (typeof quarantineMode === 'object')
(0, quarantine_1.validateQuarantineOptions)(quarantineMode);
}
async _validateRunOptions() {
this._validateDebugLogger();
this._validateScreenshotOptions();
await this._validateVideoOptions();
this._validateSpeedOption();
this._validateProxyBypassOption();
this._validateCompilerOptions();
this._validateRetryTestPagesOption();
this._validateRequestTimeoutOption(option_names_1.default.pageRequestTimeout);
this._validateRequestTimeoutOption(option_names_1.default.ajaxRequestTimeout);
this._validateQuarantineOptions();
this._validateConcurrencyOption();
this._validateSkipJsErrorsOption();
this._validateCustomActionsOption();
await this._validateBrowsers();
}
_createRunnableConfiguration() {
return this.bootstrapper
.createRunnableConfiguration()
.then(runnableConfiguration => {
this.emit('done-bootstrapping');
return runnableConfiguration;
});
}
_validateScreenshotPath(screenshotPath, pathType) {
const forbiddenCharsList = (0, check_file_path_1.default)(screenshotPath);
if (forbiddenCharsList.length)
throw new runtime_1.GeneralError(types_1.RUNTIME_ERRORS.forbiddenCharatersInScreenshotPath, screenshotPath, pathType, (0, utils_1.renderForbiddenCharsList)(forbiddenCharsList));
}
_setBootstrapperOptions() {
this.configuration.prepare();
this.configuration.notifyAboutOverriddenOptions(this.warningLog);
this.configuration.notifyAboutDeprecatedOptions(this.warningLog);
this.bootstrapper.sources = this.configuration.getOption(option_names_1.default.src) || this.bootstrapper.sources;
this.bootstrapper.browsers = this.configuration.getOption(option_names_1.default.browsers) || this.bootstrapper.browsers;
this.bootstrapper.concurrency = this.configuration.getOption(option_names_1.default.concurrency);
this.bootstrapper.appCommand = this.configuration.getOption(option_names_1.default.appCommand) || this.bootstrapper.appCommand;
this.bootstrapper.appInitDelay = this.configuration.getOption(option_names_1.default.appInitDelay);
this.bootstrapper.filter = this.configuration.getOption(option_names_1.default.filter) || this.bootstrapper.filter;
this.bootstrapper.reporters = this.configuration.getOption(option_names_1.default.reporter) || this.bootstrapper.reporters;
this.bootstrapper.tsConfigPath = this.configuration.getOption(option_names_1.default.tsConfigPath);
this.bootstrapper.clientScripts = this.configuration.getOption(option_names_1.default.clientScripts) || this.bootstrapper.clientScripts;
this.bootstrapper.disableMultipleWindows = this.configuration.getOption(option_names_1.default.disableMultipleWindows);
this.bootstrapper.compilerOptions = this.configuration.getOption(option_names_1.default.compilerOptions);
this.bootstrapper.browserInitTimeout = this.configuration.getOption(option_names_1.default.browserInitTimeout);
this.bootstrapper.hooks = this.configuration.getOption(option_names_1.default.hooks);
this.bootstrapper.configuration = this.configuration;
}
_resetBeforeRun() {
this.apiMethodWasCalled.reset();
this._messageBus.clearListeners();
}
_prepareAndRunTask(options) {
const messageBusErrorPromise = (0, promisify_event_1.default)(this._messageBus, 'error');
const taskOptionsPromise = this._getRunTaskOptions(options);
const bindedTaskRunner = this._runTask.bind(this);
const runTaskPromise = taskOptionsPromise.then(bindedTaskRunner);
const promise = Promise.race([
runTaskPromise,
messageBusErrorPromise,
]);
return this._createCancelablePromise(promise);
}
async _prepareReporters() {
var _a;
const reporterPlugins = await reporter_1.default.getReporterPlugins(this.configuration.getOption(option_names_1.default.reporter));
const reporterHooks = (_a = this.configuration.getOption(option_names_1.default.hooks)) === null || _a === void 0 ? void 0 : _a.reporter;
if (reporterHooks)
this._assertReporterHooks(reporterHooks);
this._reporters = reporterPlugins.map(reporter => {
const reporterOptions = {
plugin: reporter.plugin,
messageBus: this._messageBus,
outStream: reporter.outStream,
name: reporter.name,
reporterPluginHooks: this._resolvePluginHooks(reporter.name, reporterHooks),
};
return new reporter_1.default(reporterOptions);
});
await Promise.all(this._reporters.map(reporter => reporter.init()));
}
_resolvePluginHooks(name, reporterHooks) {
if (!reporterHooks)
return void 0;
const resultHooks = {};
if (reporterHooks.onBeforeWrite && reporterHooks.onBeforeWrite[name])
resultHooks.onBeforeWrite = reporterHooks.onBeforeWrite[name];
return resultHooks;
}
_assertReporterHooks(hooks) {
if (hooks === null || hooks === void 0 ? void 0 : hooks.onBeforeWrite) {
(0, type_assertions_1.assertType)(type_assertions_1.is.nonNullObject, 'onBeforeWrite', 'The reporter.onBeforeWrite', hooks.onBeforeWrite);
Object.entries(hooks === null || hooks === void 0 ? void 0 : hooks.onBeforeWrite).forEach(([reporterName, hook]) => {
(0, type_assertions_1.assertType)(type_assertions_1.is.function, reporterName, `The reporter.onBeforeWrite.${reporterName}`, hook);
});
}
}
async _prepareOptions(options) {
this._options = Object.assign(this._options, options);
await this._setConfigurationOptions();
await this._prepareReporters();
await this._setBootstrapperOptions();
(0, log_entry_1.default)(DEBUG_LOGGER, this.configuration);
await this._validateRunOptions();
}
async _getRunTaskOptions(options) {
await this._prepareOptions(options);
const { browserSet, tests, testedApp, commonClientScripts, id } = await this._createRunnableConfiguration();
await this._prepareClientScripts(tests, commonClientScripts);
const resultOptions = Object.assign({}, this.configuration.getOptions());
return {
browserSet,
tests,
testedApp,
runnableConfigurationId: id,
options: resultOptions,
reporters: this._reporters,
};
}
async _prepareClientScripts(tests, clientScripts) {
return Promise.all(tests.map(async (test) => {
if (test.isLegacy)
return;
let loadedTestClientScripts = await (0, load_1.default)(test.clientScripts, (0, path_1.dirname)(test.testFile.filename));
loadedTestClientScripts = clientScripts.concat(loadedTestClientScripts);
test.clientScripts = (0, utils_2.setUniqueUrls)(loadedTestClientScripts);
}));
}
async _hasLocalBrowsers(browserInfo) {
for (const browser of browserInfo) {
if (browser instanceof connection_1.default)
continue;
if (await browser.provider.isLocalBrowser(void 0, browser.browserName))
return true;
}
return false;
}
async _checkRequiredPermissions(browserInfo) {
const hasLocalBrowsers = await this._hasLocalBrowsers(browserInfo);
const { error } = await (0, authentication_helper_1.default)(() => (0, testcafe_browser_tools_1.findWindow)(''), testcafe_browser_tools_1.errors.UnableToAccessScreenRecordingAPIError, {
interactive: hasLocalBrowsers && !is_ci_1.default,
});
if (!error)
return;
if (hasLocalBrowsers)
throw error;
remote_1.default.canDetectLocalBrowsers = false;
}
async _checkThatTestsCanRunWithoutDisplay(browserInfoSource) {
for (let browserInfo of browserInfoSource) {
if (browserInfo instanceof connection_1.default)
browserInfo = browserInfo.browserInfo;
const isLocalBrowser = await browserInfo.provider.isLocalBrowser(void 0, browserInfo.browserName);
const isHeadlessBrowser = await browserInfo.provider.isHeadlessBrowser(void 0, browserInfo.browserName);
if (isLocalBrowser && !isHeadlessBrowser) {
throw new runtime_1.GeneralError(types_1.RUNTIME_ERRORS.cannotRunLocalNonHeadlessBrowserWithoutDisplay, browserInfo.alias);
}
}
}
async _setConfigurationOptions() {
await this.configuration.asyncMergeOptions(this._options);
}
// API
embeddingOptions(opts) {
const { assets, TestRunCtor } = opts;
this._registerAssets(assets);
this._options.TestRunCtor = TestRunCtor;
return this;
}
src(...sources) {
if (this.apiMethodWasCalled.src)
throw new runtime_1.GeneralError(types_1.RUNTIME_ERRORS.multipleAPIMethodCallForbidden, option_names_1.default.src);
this._options[option_names_1.default.src] = this._prepareArrayParameter(sources);
this.apiMethodWasCalled.src = true;
return this;
}
browsers(...browsers) {
if (this.apiMethodWasCalled.browsers)
throw new runtime_1.GeneralError(types_1.RUNTIME_ERRORS.multipleAPIMethodCallForbidden, option_names_1.default.browsers);
this._options.browsers = this._prepareArrayParameter(browsers);
this.apiMethodWasCalled.browsers = true;
return this;
}
concurrency(concurrency) {
this._options.concurrency = concurrency;
return this;
}
reporter(name, output) {
if (this.apiMethodWasCalled.reporter)
throw new runtime_1.GeneralError(types_1.RUNTIME_ERRORS.multipleAPIMethodCallForbidden, option_names_1.default.reporter);
this._options[option_names_1.default.reporter] = this._prepareArrayParameter((0, prepare_reporters_1.default)(name, output));
this.apiMethodWasCalled.reporter = true;
return this;
}
filter(filter) {
this._options.filter = filter;
return this;
}
useProxy(proxy, proxyBypass) {
this._options.proxy = proxy;
this._options.proxyBypass = proxyBypass;
return this;
}
screenshots(...options) {
let fullPage;
let thumbnails;
let pathPatternOnFails;
let [path, takeOnFails, pathPattern] = options;
if (options.length === 1 && options[0] && typeof options[0] === 'object')
({ path, takeOnFails, pathPattern, pathPatternOnFails, fullPage, thumbnails } = options[0]);
this._options.screenshots = { path, takeOnFails, pathPattern, pathPatternOnFails, fullPage, thumbnails };
return this;
}
video(path, options, encodingOptions) {
this._options[option_names_1.default.videoPath] = path;
this._options[option_names_1.default.videoOptions] = options;
this._options[option_names_1.default.videoEncodingOptions] = encodingOptions;
return this;
}
startApp(command, initDelay) {
this._options[option_names_1.default.appCommand] = command;
this._options[option_names_1.default.appInitDelay] = initDelay;
return this;
}
tsConfigPath(path) {
this._options[option_names_1.default.tsConfigPath] = path;
return this;
}
clientScripts(...scripts) {
if (this.apiMethodWasCalled.clientScripts)
throw new runtime_1.GeneralError(types_1.RUNTIME_ERRORS.multipleAPIMethodCallForbidden, option_names_1.default.clientScripts);
this._options[option_names_1.default.clientScripts] = this._prepareArrayParameter(scripts);
this.apiMethodWasCalled.clientScripts = true;
return this;
}
compilerOptions(opts) {
this._options[option_names_1.default.compilerOptions] = opts;
return this;
}
run(options = {}) {
this._resetBeforeRun();
return this._prepareAndRunTask(options);
}
async stop() {
// NOTE: When taskPromise is cancelled, it is removed from
// the pendingTaskPromises array, which leads to shifting indexes
// towards the beginning. So, we must copy the array in order to iterate it,
// or we can perform iteration from the end to the beginning.
const cancellationPromises = this.pendingTaskPromises.reduceRight((result, taskPromise) => {
result.push(taskPromise.cancel());
return result;
}, []);
await Promise.all(cancellationPromises);
}
}
exports.default = Runner;
module.exports = exports.default;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvcnVubmVyL2luZGV4LmpzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7O0FBQUEsK0JBQXVEO0FBQ3ZELGtEQUEwQjtBQUMxQixzRUFBNkM7QUFDN0MsbUNBQXNDO0FBRXRDLG1DQUlnQjtBQUVoQixrRUFBMEM7QUFDMUMsMkRBQW1DO0FBQ25DLGtEQUEwQjtBQUMxQixpRkFBK0Q7QUFDL0QsK0NBQWlEO0FBQ2pELDJDQUFpRDtBQUNqRCx1RUFBbUU7QUFDbkUsb0RBQW9FO0FBQ3BFLDJFQUFrRDtBQUNsRCwrRUFBcUQ7QUFDckQsMERBS2dDO0FBRWhDLGlGQUF5RDtBQUN6RCxtRUFBMEM7QUFDMUMsbUZBQTBEO0FBQzFELHlFQUE4RDtBQUM5RCwwREFBK0Q7QUFDL0QsOEZBQW9FO0FBQ3BFLHFHQUE0RTtBQUM1RSw0Q0FBK0U7QUFDL0UseUVBQWdEO0FBQ2hELCtFQUFzRDtBQUN0RCx5RkFBZ0U7QUFDaEUsbUVBQTREO0FBQzVELGtEQUF5QjtBQUN6QixpRkFBd0U7QUFDeEUsdUVBQXNEO0FBQ3RELDBEQUEyQjtBQUMzQiw2RUFBb0Q7QUFDcEQsZ0VBQTRFO0FBQzVFLG1FQUEwQztBQUMxQyx1RUFBOEM7QUFDOUMsd0VBQXNGO0FBRXRGLE1BQU0sWUFBWSxHQUFHLElBQUEsZUFBSyxFQUFDLGlCQUFpQixDQUFDLENBQUM7QUFFOUMsTUFBcUIsTUFBTyxTQUFRLHFCQUFZO0lBQzVDLFlBQWEsRUFBRSxLQUFLLEVBQUUsd0JBQXdCLEVBQUUsYUFBYSxFQUFFO1FBQzNELEtBQUssRUFBRSxDQUFDO1FBRVIsSUFBSSxDQUFDLFdBQVcsR0FBVyxJQUFJLHFCQUFVLEVBQUUsQ0FBQztRQUM1QyxJQUFJLENBQUMsS0FBSyxHQUFpQixLQUFLLENBQUM7UUFDakMsSUFBSSxDQUFDLFlBQVksR0FBVSxJQUFJLENBQUMsbUJBQW1CLENBQUMsd0JBQXdCLEVBQUUsSUFBSSxDQUFDLFdB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