@browserstack/testcafe
Version:
Automated browser testing for the modern web development stack.
706 lines • 114 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
result["default"] = mod;
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
const lodash_1 = require("lodash");
const read_file_relative_1 = require("read-file-relative");
const promisify_event_1 = __importDefault(require("promisify-event"));
const mustache_1 = __importDefault(require("mustache"));
const async_event_emitter_1 = __importDefault(require("../utils/async-event-emitter"));
const debug_log_1 = __importDefault(require("./debug-log"));
const formattable_adapter_1 = __importDefault(require("../errors/test-run/formattable-adapter"));
const error_list_1 = __importDefault(require("../errors/error-list"));
const test_run_1 = require("../errors/test-run/");
const phase_1 = __importDefault(require("./phase"));
const client_messages_1 = __importDefault(require("./client-messages"));
const type_1 = __importDefault(require("./commands/type"));
const delay_1 = __importDefault(require("../utils/delay"));
const marker_symbol_1 = __importDefault(require("./marker-symbol"));
const test_run_tracker_1 = __importDefault(require("../api/test-run-tracker"));
const phase_2 = __importDefault(require("../role/phase"));
const plugin_host_1 = __importDefault(require("../reporter/plugin-host"));
const browser_console_messages_1 = __importDefault(require("./browser-console-messages"));
const unstable_network_mode_1 = require("../browser/connection/unstable-network-mode");
const warning_log_1 = __importDefault(require("../notifications/warning-log"));
const warning_message_1 = __importDefault(require("../notifications/warning-message"));
const testcafe_hammerhead_1 = require("testcafe-hammerhead");
const INJECTABLES = __importStar(require("../assets/injectables"));
const utils_1 = require("../custom-client-scripts/utils");
const get_url_1 = __importDefault(require("../custom-client-scripts/get-url"));
const string_1 = require("../utils/string");
const utils_2 = require("./commands/utils");
const types_1 = require("../errors/types");
const process_test_fn_error_1 = __importDefault(require("../errors/process-test-fn-error"));
const lazyRequire = require('import-lazy')(require);
const SessionController = lazyRequire('./session-controller');
const ClientFunctionBuilder = lazyRequire('../client-functions/client-function-builder');
const BrowserManipulationQueue = lazyRequire('./browser-manipulation-queue');
const TestRunBookmark = lazyRequire('./bookmark');
const AssertionExecutor = lazyRequire('../assertions/executor');
const actionCommands = lazyRequire('./commands/actions');
const browserManipulationCommands = lazyRequire('./commands/browser-manipulation');
const serviceCommands = lazyRequire('./commands/service');
const observationCommands = lazyRequire('./commands/observation');
const { executeJsExpression, executeAsyncJsExpression } = lazyRequire('./execute-js-expression');
const TEST_RUN_TEMPLATE = read_file_relative_1.readSync('../client/test-run/index.js.mustache');
const IFRAME_TEST_RUN_TEMPLATE = read_file_relative_1.readSync('../client/test-run/iframe.js.mustache');
const TEST_DONE_CONFIRMATION_RESPONSE = 'test-done-confirmation';
const MAX_RESPONSE_DELAY = 3000;
const CHILD_WINDOW_READY_TIMEOUT = 30 * 1000;
const ALL_DRIVER_TASKS_ADDED_TO_QUEUE_EVENT = 'all-driver-tasks-added-to-queue';
class TestRun extends async_event_emitter_1.default {
constructor(test, browserConnection, screenshotCapturer, globalWarningLog, opts) {
super();
this[marker_symbol_1.default] = true;
this.warningLog = new warning_log_1.default(globalWarningLog);
this.opts = opts;
this.test = test;
this.browserConnection = browserConnection;
this.phase = phase_1.default.initial;
this.driverTaskQueue = [];
this.testDoneCommandQueued = false;
this.activeDialogHandler = null;
this.activeIframeSelector = null;
this.speed = this.opts.speed;
this.pageLoadTimeout = this.opts.pageLoadTimeout;
this.disablePageReloads = test.disablePageReloads || opts.disablePageReloads && test.disablePageReloads !==
false;
this.disablePageCaching = test.disablePageCaching || opts.disablePageCaching;
this.allowMultipleWindows = opts.allowMultipleWindows;
this.session = SessionController.getSession(this);
this.consoleMessages = new browser_console_messages_1.default();
this.pendingRequest = null;
this.pendingPageError = null;
this.controller = null;
this.ctx = Object.create(null);
this.fixtureCtx = null;
this.currentRoleId = null;
this.usedRoleStates = Object.create(null);
this.errs = [];
this.lastDriverStatusId = null;
this.lastDriverStatusResponse = null;
this.fileDownloadingHandled = false;
this.resolveWaitForFileDownloadingPromise = null;
this.addingDriverTasksCount = 0;
this.debugging = this.opts.debugMode;
this.debugOnFail = this.opts.debugOnFail;
this.disableDebugBreakpoints = false;
this.debugReporterPluginHost = new plugin_host_1.default({ noColors: false });
this.browserManipulationQueue = new BrowserManipulationQueue(browserConnection, screenshotCapturer, this.warningLog);
this.debugLog = new debug_log_1.default(this.browserConnection.userAgent);
this.quarantine = null;
this.debugLogger = this.opts.debugLogger;
this._addInjectables();
this._initRequestHooks();
}
_addClientScriptContentWarningsIfNecessary() {
const { empty, duplicatedContent } = utils_1.findProblematicScripts(this.test.clientScripts);
if (empty.length)
this.warningLog.addWarning(warning_message_1.default.clientScriptsWithEmptyContent);
if (duplicatedContent.length) {
const suffix = string_1.getPluralSuffix(duplicatedContent);
const duplicatedContentClientScriptsStr = string_1.getConcatenatedValuesString(duplicatedContent, ',\n ');
this.warningLog.addWarning(warning_message_1.default.clientScriptsWithDuplicatedContent, suffix, duplicatedContentClientScriptsStr);
}
}
_addInjectables() {
this._addClientScriptContentWarningsIfNecessary();
this.injectable.scripts.push(...INJECTABLES.SCRIPTS);
this.injectable.userScripts.push(...this.test.clientScripts.map(script => {
return {
url: get_url_1.default(script),
page: script.page
};
}));
this.injectable.styles.push(INJECTABLES.TESTCAFE_UI_STYLES);
}
get id() {
return this.session.id;
}
get injectable() {
return this.session.injectable;
}
addQuarantineInfo(quarantine) {
this.quarantine = quarantine;
}
addRequestHook(hook) {
if (this.requestHooks.indexOf(hook) !== -1)
return;
this.requestHooks.push(hook);
this._initRequestHook(hook);
}
removeRequestHook(hook) {
if (this.requestHooks.indexOf(hook) === -1)
return;
lodash_1.pull(this.requestHooks, hook);
this._disposeRequestHook(hook);
}
_initRequestHook(hook) {
hook.warningLog = this.warningLog;
hook._instantiateRequestFilterRules();
hook._instantiatedRequestFilterRules.forEach(rule => {
this.session.addRequestEventListeners(rule, {
onRequest: hook.onRequest.bind(hook),
onConfigureResponse: hook._onConfigureResponse.bind(hook),
onResponse: hook.onResponse.bind(hook)
}, err => this._onRequestHookMethodError(err, hook));
});
}
_onRequestHookMethodError(event, hook) {
let err = event.error;
const isRequestHookNotImplementedMethodError = err instanceof test_run_1.RequestHookNotImplementedMethodError;
if (!isRequestHookNotImplementedMethodError) {
const hookClassName = hook.constructor.name;
err = new test_run_1.RequestHookUnhandledError(err, hookClassName, event.methodName);
}
this.addError(err);
}
_disposeRequestHook(hook) {
hook.warningLog = null;
hook._instantiatedRequestFilterRules.forEach(rule => {
this.session.removeRequestEventListeners(rule);
});
}
_initRequestHooks() {
this.requestHooks = Array.from(this.test.requestHooks);
this.requestHooks.forEach(hook => this._initRequestHook(hook));
}
// Hammerhead payload
async getPayloadScript() {
this.fileDownloadingHandled = false;
this.resolveWaitForFileDownloadingPromise = null;
return mustache_1.default.render(TEST_RUN_TEMPLATE, {
testRunId: JSON.stringify(this.session.id),
browserId: JSON.stringify(this.browserConnection.id),
browserHeartbeatRelativeUrl: JSON.stringify(this.browserConnection.heartbeatRelativeUrl),
browserStatusRelativeUrl: JSON.stringify(this.browserConnection.statusRelativeUrl),
browserStatusDoneRelativeUrl: JSON.stringify(this.browserConnection.statusDoneRelativeUrl),
browserActiveWindowIdUrl: JSON.stringify(this.browserConnection.activeWindowIdUrl),
userAgent: JSON.stringify(this.browserConnection.userAgent),
testName: JSON.stringify(this.test.name),
fixtureName: JSON.stringify(this.test.fixture.name),
selectorTimeout: this.opts.selectorTimeout,
pageLoadTimeout: this.pageLoadTimeout,
childWindowReadyTimeout: CHILD_WINDOW_READY_TIMEOUT,
skipJsErrors: this.opts.skipJsErrors,
retryTestPages: this.opts.retryTestPages,
speed: this.speed,
dialogHandler: JSON.stringify(this.activeDialogHandler),
canUseDefaultWindowActions: JSON.stringify(await this.browserConnection.canUseDefaultWindowActions())
});
}
async getIframePayloadScript() {
return mustache_1.default.render(IFRAME_TEST_RUN_TEMPLATE, {
testRunId: JSON.stringify(this.session.id),
selectorTimeout: this.opts.selectorTimeout,
pageLoadTimeout: this.pageLoadTimeout,
retryTestPages: !!this.opts.retryTestPages,
speed: this.speed,
dialogHandler: JSON.stringify(this.activeDialogHandler)
});
}
// Hammerhead handlers
getAuthCredentials() {
return this.test.authCredentials;
}
handleFileDownload() {
if (this.resolveWaitForFileDownloadingPromise) {
this.resolveWaitForFileDownloadingPromise(true);
this.resolveWaitForFileDownloadingPromise = null;
}
else
this.fileDownloadingHandled = true;
}
handlePageError(ctx, err) {
if (ctx.req.headers[unstable_network_mode_1.UNSTABLE_NETWORK_MODE_HEADER]) {
ctx.closeWithError(500, err.toString());
return;
}
this.pendingPageError = new test_run_1.PageLoadError(err, ctx.reqOpts.url);
ctx.redirect(ctx.toProxyUrl(testcafe_hammerhead_1.SPECIAL_ERROR_PAGE));
}
// Test function execution
async _executeTestFn(phase, fn) {
this.phase = phase;
try {
await fn(this);
}
catch (err) {
await this._makeScreenshotOnFail();
this.addError(err);
return false;
}
finally {
this.errScreenshotPath = null;
}
return !this._addPendingPageErrorIfAny();
}
async _runBeforeHook() {
if (this.test.beforeFn)
return await this._executeTestFn(phase_1.default.inTestBeforeHook, this.test.beforeFn);
if (this.test.fixture.beforeEachFn)
return await this._executeTestFn(phase_1.default.inFixtureBeforeEachHook, this.test.fixture.beforeEachFn);
return true;
}
async _runAfterHook() {
if (this.test.afterFn)
return await this._executeTestFn(phase_1.default.inTestAfterHook, this.test.afterFn);
if (this.test.fixture.afterEachFn)
return await this._executeTestFn(phase_1.default.inFixtureAfterEachHook, this.test.fixture.afterEachFn);
return true;
}
async start() {
test_run_tracker_1.default.activeTestRuns[this.session.id] = this;
await this.emit('start');
const onDisconnected = err => this._disconnect(err);
this.browserConnection.once('disconnected', onDisconnected);
await this.once('connected');
await this.emit('ready');
if (await this._runBeforeHook()) {
await this._executeTestFn(phase_1.default.inTest, this.test.fn);
await this._runAfterHook();
}
if (this.disconnected)
return;
this.browserConnection.removeListener('disconnected', onDisconnected);
if (this.errs.length && this.debugOnFail)
await this._enqueueSetBreakpointCommand(null, this.debugReporterPluginHost.formatError(this.errs[0]));
await this.emit('before-done');
await this.executeCommand(new serviceCommands.TestDoneCommand());
this._addPendingPageErrorIfAny();
this.session.clearRequestEventListeners();
this.normalizeRequestHookErrors();
delete test_run_tracker_1.default.activeTestRuns[this.session.id];
await this.emit('done');
}
// Errors
_addPendingPageErrorIfAny() {
if (this.pendingPageError) {
this.addError(this.pendingPageError);
this.pendingPageError = null;
return true;
}
return false;
}
_createErrorAdapter(err) {
return new formattable_adapter_1.default(err, {
userAgent: this.browserConnection.userAgent,
screenshotPath: this.errScreenshotPath || '',
testRunId: this.id,
testRunPhase: this.phase
});
}
addError(err) {
const errList = err instanceof error_list_1.default ? err.items : [err];
errList.forEach(item => {
const adapter = this._createErrorAdapter(item);
this.errs.push(adapter);
});
}
normalizeRequestHookErrors() {
const requestHookErrors = lodash_1.remove(this.errs, e => e.code === types_1.TEST_RUN_ERRORS.requestHookNotImplementedError ||
e.code === types_1.TEST_RUN_ERRORS.requestHookUnhandledError);
if (!requestHookErrors.length)
return;
const uniqRequestHookErrors = lodash_1.chain(requestHookErrors)
.uniqBy(e => e.hookClassName + e.methodName)
.sortBy(['hookClassName', 'methodName'])
.value();
this.errs = this.errs.concat(uniqRequestHookErrors);
}
// Task queue
_enqueueCommand(command, callsite) {
if (this.pendingRequest)
this._resolvePendingRequest(command);
return new Promise(async (resolve, reject) => {
this.addingDriverTasksCount--;
this.driverTaskQueue.push({ command, resolve, reject, callsite });
if (!this.addingDriverTasksCount)
await this.emit(ALL_DRIVER_TASKS_ADDED_TO_QUEUE_EVENT, this.driverTaskQueue.length);
});
}
get driverTaskQueueLength() {
return this.addingDriverTasksCount ? promisify_event_1.default(this, ALL_DRIVER_TASKS_ADDED_TO_QUEUE_EVENT) : Promise.resolve(this.driverTaskQueue.length);
}
async _enqueueBrowserConsoleMessagesCommand(command, callsite) {
await this._enqueueCommand(command, callsite);
const consoleMessageCopy = this.consoleMessages.getCopy();
return consoleMessageCopy[this.browserConnection.activeWindowId];
}
async _enqueueSetBreakpointCommand(callsite, error) {
if (this.browserConnection.isHeadlessBrowser()) {
this.warningLog.addWarning(warning_message_1.default.debugInHeadlessError);
return;
}
if (this.debugLogger)
this.debugLogger.showBreakpoint(this.session.id, this.browserConnection.userAgent, callsite, error);
this.debugging = await this.executeCommand(new serviceCommands.SetBreakpointCommand(!!error), callsite);
}
_removeAllNonServiceTasks() {
this.driverTaskQueue = this.driverTaskQueue.filter(driverTask => utils_2.isServiceCommand(driverTask.command));
this.browserManipulationQueue.removeAllNonServiceManipulations();
}
// Current driver task
get currentDriverTask() {
return this.driverTaskQueue[0];
}
_resolveCurrentDriverTask(result) {
this.currentDriverTask.resolve(result);
this.driverTaskQueue.shift();
if (this.testDoneCommandQueued)
this._removeAllNonServiceTasks();
}
_rejectCurrentDriverTask(err) {
err.callsite = err.callsite || this.currentDriverTask.callsite;
this.currentDriverTask.reject(err);
this._removeAllNonServiceTasks();
}
// Pending request
_clearPendingRequest() {
if (this.pendingRequest) {
clearTimeout(this.pendingRequest.responseTimeout);
this.pendingRequest = null;
}
}
_resolvePendingRequest(command) {
this.lastDriverStatusResponse = command;
this.pendingRequest.resolve(command);
this._clearPendingRequest();
}
// Handle driver request
_shouldResolveCurrentDriverTask(driverStatus) {
const currentCommand = this.currentDriverTask.command;
const isExecutingObservationCommand = currentCommand instanceof observationCommands.ExecuteSelectorCommand ||
currentCommand instanceof observationCommands.ExecuteClientFunctionCommand;
const isDebugActive = currentCommand instanceof serviceCommands.SetBreakpointCommand;
const shouldExecuteCurrentCommand = driverStatus.isFirstRequestAfterWindowSwitching && (isExecutingObservationCommand || isDebugActive);
return !shouldExecuteCurrentCommand;
}
_fulfillCurrentDriverTask(driverStatus) {
if (!this.currentDriverTask)
return;
if (driverStatus.executionError)
this._rejectCurrentDriverTask(driverStatus.executionError);
else if (this._shouldResolveCurrentDriverTask(driverStatus))
this._resolveCurrentDriverTask(driverStatus.result);
}
_handlePageErrorStatus(pageError) {
if (this.currentDriverTask && utils_2.isCommandRejectableByPageError(this.currentDriverTask.command)) {
this._rejectCurrentDriverTask(pageError);
this.pendingPageError = null;
return true;
}
this.pendingPageError = this.pendingPageError || pageError;
return false;
}
_handleDriverRequest(driverStatus) {
const isTestDone = this.currentDriverTask && this.currentDriverTask.command.type ===
type_1.default.testDone;
const pageError = this.pendingPageError || driverStatus.pageError;
const currentTaskRejectedByError = pageError && this._handlePageErrorStatus(pageError);
if (this.disconnected)
return new Promise((_, reject) => reject());
this.consoleMessages.concat(driverStatus.consoleMessages);
if (!currentTaskRejectedByError && driverStatus.isCommandResult) {
if (isTestDone) {
this._resolveCurrentDriverTask();
return TEST_DONE_CONFIRMATION_RESPONSE;
}
this._fulfillCurrentDriverTask(driverStatus);
if (driverStatus.isPendingWindowSwitching)
return null;
}
return this._getCurrentDriverTaskCommand();
}
_getCurrentDriverTaskCommand() {
if (!this.currentDriverTask)
return null;
const command = this.currentDriverTask.command;
if (command.type === type_1.default.navigateTo && command.stateSnapshot)
this.session.useStateSnapshot(JSON.parse(command.stateSnapshot));
return command;
}
// Execute command
_executeJsExpression(command) {
const resultVariableName = command.resultVariableName;
let expression = command.expression;
if (resultVariableName)
expression = `${resultVariableName} = ${expression}, ${resultVariableName}`;
return executeJsExpression(expression, this, { skipVisibilityCheck: false });
}
async _executeAssertion(command, callsite) {
const assertionTimeout = command.options.timeout ===
void 0 ? this.opts.assertionTimeout : command.options.timeout;
const executor = new AssertionExecutor(command, assertionTimeout, callsite);
executor.once('start-assertion-retries', timeout => this.executeCommand(new serviceCommands.ShowAssertionRetriesStatusCommand(timeout)));
executor.once('end-assertion-retries', success => this.executeCommand(new serviceCommands.HideAssertionRetriesStatusCommand(success)));
const executeFn = this.decoratePreventEmitActionEvents(() => executor.run(), { prevent: true });
return await executeFn();
}
_adjustConfigurationWithCommand(command) {
if (command.type === type_1.default.testDone) {
this.testDoneCommandQueued = true;
if (this.debugLogger)
this.debugLogger.hideBreakpoint(this.session.id);
}
else if (command.type === type_1.default.setNativeDialogHandler)
this.activeDialogHandler = command.dialogHandler;
else if (command.type === type_1.default.switchToIframe)
this.activeIframeSelector = command.selector;
else if (command.type === type_1.default.switchToMainWindow)
this.activeIframeSelector = null;
else if (command.type === type_1.default.setTestSpeed)
this.speed = command.speed;
else if (command.type === type_1.default.setPageLoadTimeout)
this.pageLoadTimeout = command.duration;
else if (command.type === type_1.default.debug)
this.debugging = true;
}
async _adjustScreenshotCommand(command) {
const browserId = this.browserConnection.id;
const { hasChromelessScreenshots } = await this.browserConnection.provider.hasCustomActionForBrowser(browserId);
if (!hasChromelessScreenshots)
command.generateScreenshotMark();
}
async _setBreakpointIfNecessary(command, callsite) {
if (!this.disableDebugBreakpoints && this.debugging && utils_2.canSetDebuggerBreakpointBeforeCommand(command))
await this._enqueueSetBreakpointCommand(callsite);
}
async executeAction(apiActionName, command, callsite) {
const actionArgs = { apiActionName, command };
let errorAdapter = null;
let error = null;
let result = null;
await this.emitActionEvent('action-start', actionArgs);
const start = new Date();
try {
result = await this.executeCommand(command, callsite);
}
catch (err) {
error = err;
}
const duration = new Date() - start;
if (error) {
// NOTE: check if error is TestCafeErrorList is specific for the `useRole` action
// if error is TestCafeErrorList we do not need to create an adapter,
// since error is already was processed in role initializer
if (!(error instanceof error_list_1.default)) {
await this._makeScreenshotOnFail();
errorAdapter = this._createErrorAdapter(process_test_fn_error_1.default(error));
}
}
Object.assign(actionArgs, {
result,
duration,
err: errorAdapter
});
await this.emitActionEvent('action-done', actionArgs);
if (error)
throw error;
return result;
}
async executeCommand(command, callsite) {
await this.debugLog.command(command, {
id: this.browserConnection.id
});
if (this.pendingPageError && utils_2.isCommandRejectableByPageError(command))
return this._rejectCommandWithPageError(callsite);
if (utils_2.isExecutableOnClientCommand(command))
this.addingDriverTasksCount++;
this._adjustConfigurationWithCommand(command);
await this._setBreakpointIfNecessary(command, callsite);
if (utils_2.isScreenshotCommand(command)) {
if (this.opts.disableScreenshots) {
this.warningLog.addWarning(warning_message_1.default.screenshotsDisabled);
return null;
}
await this._adjustScreenshotCommand(command);
}
if (utils_2.isBrowserManipulationCommand(command)) {
this.browserManipulationQueue.push(command);
if (utils_2.isResizeWindowCommand(command) && this.opts.videoPath)
this.warningLog.addWarning(warning_message_1.default.videoBrowserResizing, this.test.name);
}
if (command.type === type_1.default.wait)
return delay_1.default(command.timeout);
if (command.type === type_1.default.setPageLoadTimeout)
return null;
if (command.type === type_1.default.debug)
return await this._enqueueSetBreakpointCommand(callsite);
if (command.type === type_1.default.useRole) {
let fn = () => this._useRole(command.role, callsite);
fn = this.decoratePreventEmitActionEvents(fn, { prevent: true });
fn = this.decorateDisableDebugBreakpoints(fn, { disable: true });
return await fn();
}
if (command.type === type_1.default.assertion)
return this._executeAssertion(command, callsite);
if (command.type === type_1.default.executeExpression)
return await this._executeJsExpression(command, callsite);
if (command.type === type_1.default.executeAsyncExpression)
return await executeAsyncJsExpression(command.expression, this, callsite);
if (command.type === type_1.default.getBrowserConsoleMessages)
return await this._enqueueBrowserConsoleMessagesCommand(command, callsite);
return this._enqueueCommand(command, callsite);
}
_rejectCommandWithPageError(callsite) {
const err = this.pendingPageError;
err.callsite = callsite;
this.pendingPageError = null;
return Promise.reject(err);
}
async _makeScreenshotOnFail() {
const { screenshots } = this.opts;
if (!this.errScreenshotPath && screenshots && screenshots.takeOnFails)
this.errScreenshotPath = await this.executeCommand(new browserManipulationCommands.TakeScreenshotOnFailCommand());
}
_decorateWithFlag(fn, flagName, value) {
return async () => {
this[flagName] = value;
try {
return await fn();
}
catch (err) {
throw err;
}
finally {
this[flagName] = !value;
}
};
}
decoratePreventEmitActionEvents(fn, { prevent }) {
return this._decorateWithFlag(fn, 'preventEmitActionEvents', prevent);
}
decorateDisableDebugBreakpoints(fn, { disable }) {
return this._decorateWithFlag(fn, 'disableDebugBreakpoints', disable);
}
// Role management
async getStateSnapshot() {
const state = this.session.getStateSnapshot();
state.storages = await this.executeCommand(new serviceCommands.BackupStoragesCommand());
return state;
}
async switchToCleanRun(url) {
this.ctx = Object.create(null);
this.fixtureCtx = Object.create(null);
this.consoleMessages = new browser_console_messages_1.default();
this.session.useStateSnapshot(testcafe_hammerhead_1.StateSnapshot.empty());
if (this.speed !== this.opts.speed) {
const setSpeedCommand = new actionCommands.SetTestSpeedCommand({ speed: this.opts.speed });
await this.executeCommand(setSpeedCommand);
}
if (this.pageLoadTimeout !== this.opts.pageLoadTimeout) {
const setPageLoadTimeoutCommand = new actionCommands.SetPageLoadTimeoutCommand({ duration: this.opts.pageLoadTimeout });
await this.executeCommand(setPageLoadTimeoutCommand);
}
await this.navigateToUrl(url, true);
if (this.activeDialogHandler) {
const removeDialogHandlerCommand = new actionCommands.SetNativeDialogHandlerCommand({ dialogHandler: { fn: null } });
await this.executeCommand(removeDialogHandlerCommand);
}
}
async navigateToUrl(url, forceReload, stateSnapshot) {
const navigateCommand = new actionCommands.NavigateToCommand({ url, forceReload, stateSnapshot });
await this.executeCommand(navigateCommand);
}
async _getStateSnapshotFromRole(role) {
const prevPhase = this.phase;
this.phase = phase_1.default.inRoleInitializer;
if (role.phase === phase_2.default.uninitialized)
await role.initialize(this);
else if (role.phase === phase_2.default.pendingInitialization)
await promisify_event_1.default(role, 'initialized');
if (role.initErr)
throw role.initErr;
this.phase = prevPhase;
return role.stateSnapshot;
}
async _useRole(role, callsite) {
if (this.phase === phase_1.default.inRoleInitializer)
throw new test_run_1.RoleSwitchInRoleInitializerError(callsite);
const bookmark = new TestRunBookmark(this, role);
await bookmark.init();
if (this.currentRoleId)
this.usedRoleStates[this.currentRoleId] = await this.getStateSnapshot();
const stateSnapshot = this.usedRoleStates[role.id] || await this._getStateSnapshotFromRole(role);
this.session.useStateSnapshot(stateSnapshot);
this.currentRoleId = role.id;
await bookmark.restore(callsite, stateSnapshot);
}
async getCurrentUrl() {
const builder = new ClientFunctionBuilder(() => {
/* eslint-disable no-undef */
return window.location.href;
/* eslint-enable no-undef */
}, { boundTestRun: this });
const getLocation = builder.getFunction();
return await getLocation();
}
_disconnect(err) {
this.disconnected = true;
if (this.currentDriverTask)
this._rejectCurrentDriverTask(err);
this.emit('disconnected', err);
delete test_run_tracker_1.default.activeTestRuns[this.session.id];
}
async emitActionEvent(eventName, args) {
if (!this.preventEmitActionEvents)
await this.emit(eventName, args);
}
}
exports.default = TestRun;
// Service message handlers
const ServiceMessages = TestRun.prototype;
// NOTE: this function is time-critical and must return ASAP to avoid client disconnection
ServiceMessages[client_messages_1.default.ready] = function (msg) {
this.debugLog.driverMessage(msg);
this.emit('connected');
this._clearPendingRequest();
// NOTE: the driver sends the status for the second time if it didn't get a response at the
// first try. This is possible when the page was unloaded after the driver sent the status.
if (msg.status.id === this.lastDriverStatusId)
return this.lastDriverStatusResponse;
this.lastDriverStatusId = msg.status.id;
this.lastDriverStatusResponse = this._handleDriverRequest(msg.status);
if (this.lastDriverStatusResponse || msg.status.isPendingWindowSwitching)
return this.lastDriverStatusResponse;
// NOTE: we send an empty response after the MAX_RESPONSE_DELAY timeout is exceeded to keep connection
// with the client and prevent the response timeout exception on the client side
const responseTimeout = setTimeout(() => this._resolvePendingRequest(null), MAX_RESPONSE_DELAY);
return new Promise((resolve, reject) => {
this.pendingRequest = { resolve, reject, responseTimeout };
});
};
ServiceMessages[client_messages_1.default.readyForBrowserManipulation] = async function (msg) {
this.debugLog.driverMessage(msg);
let result = null;
let error = null;
try {
result = await this.browserManipulationQueue.executePendingManipulation(msg);
}
catch (err) {
error = err;
}
return { result, error };
};
ServiceMessages[client_messages_1.default.waitForFileDownload] = function (msg) {
this.debugLog.driverMessage(msg);
return new Promise(resolve => {
if (this.fileDownloadingHandled) {
this.fileDownloadingHandled = false;
resolve(true);
}
else
this.resolveWaitForFileDownloadingPromise = resolve;
});
};
module.exports = exports.default;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvdGVzdC1ydW4vaW5kZXguanMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7O0FBQUEsbUNBQTZDO0FBQzdDLDJEQUFzRDtBQUN0RCxzRUFBNkM7QUFDN0Msd0RBQWdDO0FBQ2hDLHVGQUE2RDtBQUM3RCw0REFBMEM7QUFDMUMsaUdBQW9GO0FBQ3BGLHNFQUFxRDtBQUNyRCxrREFLNkI7QUFDN0Isb0RBQTRCO0FBQzVCLHdFQUFnRDtBQUNoRCwyREFBMkM7QUFDM0MsMkRBQW1DO0FBQ25DLG9FQUE0QztBQUM1QywrRUFBcUQ7QUFDckQsMERBQXVDO0FBQ3ZDLDBFQUF5RDtBQUN6RCwwRkFBZ0U7QUFDaEUsdUZBQTJGO0FBQzNGLCtFQUFzRDtBQUN0RCx1RkFBK0Q7QUFDL0QsNkRBQXdFO0FBQ3hFLG1FQUFxRDtBQUNyRCwwREFBd0U7QUFDeEUsK0VBQXdFO0FBQ3hFLDRDQUErRTtBQUUvRSw0Q0FRMEI7QUFFMUIsMkNBQWtEO0FBQ2xELDRGQUFpRTtBQUVqRSxNQUFNLFdBQVcsR0FBbUIsT0FBTyxDQUFDLGFBQWEsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxDQUFDO0FBQ3BFLE1BQU0saUJBQWlCLEdBQWEsV0FBVyxDQUFDLHNCQUFzQixDQUFDLENBQUM7QUFDeEUsTUFBTSxxQkFBcUIsR0FBUyxXQUFXLENBQUMsNkNBQTZDLENBQUMsQ0FBQztBQUMvRixNQUFNLHdCQUF3QixHQUFNLFdBQVcsQ0FBQyw4QkFBOEIsQ0FBQyxDQUFDO0FBQ2hGLE1BQU0sZUFBZSxHQUFlLFdBQVcsQ0FBQyxZQUFZLENBQUMsQ0FBQztBQUM5RCxNQUFNLGlCQUFpQixHQUFhLFdBQVcsQ0FBQyx3QkFBd0IsQ0FBQyxDQUFDO0FBQzFFLE1BQU0sY0FBYyxHQUFnQixXQUFXLENBQUMsb0JBQW9CLENBQUMsQ0FBQztBQUN0RSxNQUFNLDJCQUEyQixHQUFHLFdBQVcsQ0FBQyxpQ0FBaUMsQ0FB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