UNPKG

@browserstack/testcafe

Version:

Automated browser testing for the modern web development stack.

706 lines 114 kB
"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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