Innovenergy_trunk/frontend/node_modules/testcafe/lib/test-run/index.js

1131 lines
197 KiB
JavaScript
Raw Normal View History

"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const lodash_1 = require("lodash");
const nanoid_1 = require("nanoid");
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 runtime_1 = require("../errors/runtime");
const test_run_1 = require("../errors/test-run/");
const client_messages_1 = __importDefault(require("./client-messages"));
const type_1 = __importDefault(require("./commands/type"));
const delay_1 = __importDefault(require("../utils/delay"));
const is_password_input_1 = __importDefault(require("../utils/is-password-input"));
const marker_symbol_1 = __importDefault(require("./marker-symbol"));
const test_run_tracker_1 = __importDefault(require("../api/test-run-tracker"));
const phase_1 = __importDefault(require("../role/phase"));
const plugin_host_1 = __importDefault(require("../reporter/plugin-host"));
const browser_console_messages_1 = __importDefault(require("./browser-console-messages"));
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 actions_1 = require("./commands/actions");
const types_1 = require("../errors/types");
const process_test_fn_error_1 = __importDefault(require("../errors/process-test-fn-error"));
const hook_method_names_1 = __importDefault(require("../api/request-hooks/hook-method-names"));
const replicator_1 = require("../client-functions/replicator");
const session_controller_1 = __importDefault(require("./session-controller"));
const browser_manipulation_queue_1 = __importDefault(require("./browser-manipulation-queue"));
const observed_callsites_storage_1 = __importDefault(require("./observed-callsites-storage"));
const base_js_1 = require("./commands/base.js");
const get_assertion_timeout_1 = __importDefault(require("../utils/get-options/get-assertion-timeout"));
const phase_2 = __importDefault(require("./phase"));
const observation_1 = require("./commands/observation");
const marker_1 = require("../services/serialization/replicator/transforms/re-executable-promise-transform/marker");
const re_executable_promise_1 = __importDefault(require("../utils/re-executable-promise"));
const add_rendered_warning_1 = __importDefault(require("../notifications/add-rendered-warning"));
const get_browser_1 = __importDefault(require("../utils/get-browser"));
const executor_1 = __importDefault(require("../assertions/executor"));
const async_filter_1 = __importDefault(require("../utils/async-filter"));
const execute_fn_with_timeout_1 = __importDefault(require("../utils/execute-fn-with-timeout"));
const url_1 = require("url");
const skip_js_errors_1 = require("../api/skip-js-errors");
const factory_1 = require("./cookies/factory");
const factory_2 = require("./storages/factory");
const wrap_custom_action_1 = __importDefault(require("../api/wrap-custom-action"));
const role_provider_1 = require("./role-provider");
const lazyRequire = require('import-lazy')(require);
const ClientFunctionBuilder = lazyRequire('../client-functions/client-function-builder');
const TestRunBookmark = lazyRequire('./bookmark');
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 = (0, read_file_relative_1.readSync)('../client/test-run/index.js.mustache');
const IFRAME_TEST_RUN_TEMPLATE = (0, 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';
const COMPILER_SERVICE_EVENTS = [
'setMock',
'setConfigureResponseEventOptions',
'setHeaderOnConfigureResponseEvent',
'removeHeaderOnConfigureResponseEvent',
];
class TestRun extends async_event_emitter_1.default {
constructor({ test, browserConnection, screenshotCapturer, globalWarningLog, opts, compilerService, messageBus, startRunExecutionTime }) {
super();
this._clientEnvironmentPrepared = false;
this[marker_symbol_1.default] = true;
this._messageBus = messageBus;
this.warningLog = new warning_log_1.default(globalWarningLog, warning_log_1.default.createAddWarningCallback(messageBus, this));
this.opts = opts;
this.test = test;
this.browserConnection = browserConnection;
this.unstable = false;
this.browser = (0, get_browser_1.default)(browserConnection);
this.phase = phase_2.default.initial;
this.driverTaskQueue = [];
this.testDoneCommandQueued = false;
this.activeDialogHandler = null;
this.activeIframeSelector = null;
this.speed = this.opts.speed;
this.pageLoadTimeout = this._getPageLoadTimeout(test, opts);
this.testExecutionTimeout = this._getTestExecutionTimeout(opts);
this.disablePageReloads = test.disablePageReloads || opts.disablePageReloads && test.disablePageReloads !== false;
this.disablePageCaching = test.disablePageCaching || opts.disablePageCaching;
this.disableMultipleWindows = opts.disableMultipleWindows;
this.requestTimeout = this._getRequestTimeout(test, opts);
this.session = session_controller_1.default.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.testRunCtx = null;
this.currentRoleId = null;
this.usedRoleStates = Object.create(null);
this.errs = [];
this.lastDriverStatusId = null;
this.lastDriverStatusResponse = null;
this.fileDownloadingHandled = false;
this.resolveWaitForFileDownloadingPromise = null;
this.attachmentDownloadingHandled = false;
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 browser_manipulation_queue_1.default(browserConnection, screenshotCapturer, this.warningLog);
this.debugLog = new debug_log_1.default(this.browserConnection.userAgent);
this.quarantine = null;
this.debugLogger = this.opts.debugLogger;
this.observedCallsites = new observed_callsites_storage_1.default();
this.compilerService = compilerService;
this.asyncJsExpressionCallsites = new Map();
this.replicator = (0, replicator_1.createReplicator)([new replicator_1.SelectorNodeTransform()]);
this.disconnected = false;
this.errScreenshotPath = null;
this.startRunExecutionTime = startRunExecutionTime;
this.runExecutionTimeout = this._getRunExecutionTimeout(opts);
this._requestHookEventProvider = this._getRequestHookEventProvider();
this._roleProvider = this._getRoleProvider();
this._cookieProvider = factory_1.CookieProviderFactory.create(this, this.opts.experimentalProxyless);
this._storagesProvider = factory_2.StoragesProviderFactory.create(this, this.opts.experimentalProxyless);
this._addInjectables();
}
_getRequestHookEventProvider() {
if (!this.opts.experimentalProxyless)
return this.session.requestHookEventProvider;
return this._proxylessRequestPipeline.requestHookEventProvider;
}
saveStoragesSnapshot(storageSnapshot) {
if (this.opts.experimentalProxyless)
this._proxylessRequestPipeline.restoringStorages = storageSnapshot;
}
get _proxylessRequestPipeline() {
return this._proxyless.requestPipeline;
}
get _proxyless() {
const runtimeInfo = this.browserConnection.provider.plugin.openedBrowsers[this.browserConnection.id];
return runtimeInfo.proxyless;
}
_getRoleProvider() {
if (this.opts.experimentalProxyless)
return new role_provider_1.ProxylessRoleProvider(this);
return new role_provider_1.ProxyRoleProvider(this);
}
_getPageLoadTimeout(test, opts) {
var _a;
if (((_a = test.timeouts) === null || _a === void 0 ? void 0 : _a.pageLoadTimeout) !== void 0)
return test.timeouts.pageLoadTimeout;
return opts.pageLoadTimeout;
}
_getRequestTimeout(test, opts) {
var _a, _b;
return {
page: ((_a = test.timeouts) === null || _a === void 0 ? void 0 : _a.pageRequestTimeout) || opts.pageRequestTimeout,
ajax: ((_b = test.timeouts) === null || _b === void 0 ? void 0 : _b.ajaxRequestTimeout) || opts.ajaxRequestTimeout,
};
}
_getExecutionTimeout(timeout, error) {
return {
timeout,
rejectWith: error,
};
}
_getTestExecutionTimeout(opts) {
const testExecutionTimeout = opts.testExecutionTimeout || 0;
if (!testExecutionTimeout)
return null;
return this._getExecutionTimeout(testExecutionTimeout, new test_run_1.TestTimeoutError(testExecutionTimeout));
}
_getRunExecutionTimeout(opts) {
const runExecutionTimeout = opts.runExecutionTimeout || 0;
if (!runExecutionTimeout)
return null;
return this._getExecutionTimeout(runExecutionTimeout, new test_run_1.RunTimeoutError(runExecutionTimeout));
}
get restRunExecutionTimeout() {
if (!this.startRunExecutionTime || !this.runExecutionTimeout)
return null;
const currentTimeout = Math.max(this.runExecutionTimeout.timeout - (Date.now() - this.startRunExecutionTime.getTime()), 0);
return this._getExecutionTimeout(currentTimeout, this.runExecutionTimeout.rejectWith);
}
get executionTimeout() {
return this.restRunExecutionTimeout && (!this.testExecutionTimeout || this.restRunExecutionTimeout.timeout < this.testExecutionTimeout.timeout)
? this.restRunExecutionTimeout
: this.testExecutionTimeout || null;
}
_addClientScriptContentWarningsIfNecessary() {
const { empty, duplicatedContent } = (0, utils_1.findProblematicScripts)(this.test.clientScripts);
if (empty.length)
this.warningLog.addWarning(warning_message_1.default.clientScriptsWithEmptyContent);
if (duplicatedContent.length) {
const suffix = (0, string_1.getPluralSuffix)(duplicatedContent);
const duplicatedContentClientScriptsStr = (0, 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: (0, 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;
}
async _addRequestHook(hook) {
if (this.test.requestHooks.includes(hook))
return;
this.test.requestHooks.push(hook);
await this._initRequestHook(hook);
}
async _removeRequestHook(hook) {
if (!this.test.requestHooks.includes(hook))
return;
(0, lodash_1.pull)(this.test.requestHooks, hook);
await this._disposeRequestHook(hook);
}
async _initRequestHook(hook) {
hook._warningLog = this.warningLog;
await Promise.all(hook._requestFilterRules.map(rule => {
return this._requestHookEventProvider.addRequestEventListeners(rule, {
onRequest: hook.onRequest.bind(hook),
onConfigureResponse: hook._onConfigureResponse.bind(hook),
onResponse: hook.onResponse.bind(hook),
}, (err) => this._onRequestHookMethodError(err, hook._className));
}));
}
async _initRequestHookForCompilerService(hookId, hookClassName, rules) {
const testId = this.test.id;
await Promise.all(rules.map(rule => {
return this._requestHookEventProvider.addRequestEventListeners(rule, {
onRequest: (event) => { var _a; return (_a = this.compilerService) === null || _a === void 0 ? void 0 : _a.onRequestHookEvent({ testId, hookId, name: hook_method_names_1.default.onRequest, eventData: event }); },
onConfigureResponse: (event) => { var _a; return (_a = this.compilerService) === null || _a === void 0 ? void 0 : _a.onRequestHookEvent({ testId, hookId, name: hook_method_names_1.default._onConfigureResponse, eventData: event }); },
onResponse: (event) => { var _a; return (_a = this.compilerService) === null || _a === void 0 ? void 0 : _a.onRequestHookEvent({ testId, hookId, name: hook_method_names_1.default.onResponse, eventData: event }); },
}, err => this._onRequestHookMethodError(err, hookClassName));
}));
}
_onRequestHookMethodError(event, hookClassName) {
let err = event.error;
const isRequestHookNotImplementedMethodError = (err === null || err === void 0 ? void 0 : err.code) === types_1.TEST_RUN_ERRORS.requestHookNotImplementedError;
if (!isRequestHookNotImplementedMethodError)
err = new test_run_1.RequestHookUnhandledError(err, hookClassName, event.methodName);
this.addError(err);
}
async _disposeRequestHook(hook) {
hook._warningLog = null;
await Promise.all(hook._requestFilterRules.map(rule => {
return this._requestHookEventProvider.removeRequestEventListeners(rule);
}));
}
async _detachRequestEventListeners(rules) {
await Promise.all(rules.map(rule => {
return this._requestHookEventProvider.removeRequestEventListeners(rule);
}));
}
_subscribeOnCompilerServiceEvents() {
COMPILER_SERVICE_EVENTS.forEach(eventName => {
if (this.compilerService) {
this.compilerService.on(eventName, async (args) => {
// @ts-ignore
await this.session[eventName](...args);
});
}
});
if (this.compilerService) {
this.compilerService.on('addRequestEventListeners', async ({ hookId, hookClassName, rules }) => {
await this._initRequestHookForCompilerService(hookId, hookClassName, rules);
});
this.compilerService.on('removeRequestEventListeners', async ({ rules }) => {
await this._detachRequestEventListeners(rules);
});
}
}
async _initRequestHooks() {
if (this.compilerService) {
this._subscribeOnCompilerServiceEvents();
await Promise.all(this.test.requestHooks.map(hook => {
return this._initRequestHookForCompilerService(hook.id, hook._className, hook._requestFilterRules);
}));
}
else
await Promise.all(this.test.requestHooks.map(hook => this._initRequestHook(hook)));
}
_prepareSkipJsErrorsOption() {
const options = this.test.skipJsErrorsOptions !== void 0
? this.test.skipJsErrorsOptions
: this.opts.skipJsErrors || false;
return (0, skip_js_errors_1.prepareSkipJsErrorsOptions)(options);
}
// Hammerhead payload
async getPayloadScript() {
this.fileDownloadingHandled = false;
this.resolveWaitForFileDownloadingPromise = null;
const skipJsErrors = this._prepareSkipJsErrorsOption();
return mustache_1.default.render(TEST_RUN_TEMPLATE, {
testRunId: JSON.stringify(this.session.id),
browserId: JSON.stringify(this.browserConnection.id),
activeWindowId: JSON.stringify(this.activeWindowId),
browserHeartbeatRelativeUrl: JSON.stringify(this.browserConnection.heartbeatRelativeUrl),
browserStatusRelativeUrl: JSON.stringify(this.browserConnection.statusRelativeUrl),
browserStatusDoneRelativeUrl: JSON.stringify(this.browserConnection.statusDoneRelativeUrl),
browserIdleRelativeUrl: JSON.stringify(this.browserConnection.idleRelativeUrl),
browserActiveWindowIdUrl: JSON.stringify(this.browserConnection.activeWindowIdUrl),
browserCloseWindowUrl: JSON.stringify(this.browserConnection.closeWindowUrl),
browserOpenFileProtocolRelativeUrl: JSON.stringify(this.browserConnection.openFileProtocolRelativeUrl),
browserDispatchProxylessEventRelativeUrl: JSON.stringify(this.browserConnection.dispatchProxylessEventRelativeUrl),
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: JSON.stringify(skipJsErrors),
retryTestPages: this.opts.retryTestPages,
speed: this.speed,
dialogHandler: JSON.stringify(this.activeDialogHandler),
canUseDefaultWindowActions: JSON.stringify(await this.browserConnection.canUseDefaultWindowActions()),
proxyless: JSON.stringify(this.opts.experimentalProxyless),
domain: JSON.stringify(this.browserConnection.browserConnectionGateway.proxy.server1Info.domain),
});
}
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),
proxyless: JSON.stringify(this.opts.experimentalProxyless),
});
}
// Hammerhead handlers
getAuthCredentials() {
return this.test.authCredentials;
}
handleFileDownload() {
if (this.resolveWaitForFileDownloadingPromise) {
this.resolveWaitForFileDownloadingPromise(true);
this.resolveWaitForFileDownloadingPromise = null;
}
else
this.fileDownloadingHandled = true;
}
handleAttachment(data) {
if (data.isOpenedInNewWindow)
this.attachmentDownloadingHandled = true;
}
handlePageError(ctx, err) {
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, timeout) {
this.phase = phase;
try {
await (0, execute_fn_with_timeout_1.default)(fn, timeout, this);
}
catch (err) {
await this._makeScreenshotOnFail();
this.addError(err);
return false;
}
finally {
this.errScreenshotPath = null;
}
return !this._addPendingPageErrorIfAny();
}
async _runBeforeHook() {
var _a, _b;
if (this.test.globalBeforeFn)
await this._executeTestFn(phase_2.default.inTestBeforeHook, this.test.globalBeforeFn, this.executionTimeout);
if (this.test.beforeFn)
return await this._executeTestFn(phase_2.default.inTestBeforeHook, this.test.beforeFn, this.executionTimeout);
if ((_a = this.test.fixture) === null || _a === void 0 ? void 0 : _a.beforeEachFn)
return await this._executeTestFn(phase_2.default.inFixtureBeforeEachHook, (_b = this.test.fixture) === null || _b === void 0 ? void 0 : _b.beforeEachFn, this.executionTimeout);
return true;
}
async _runAfterHook() {
var _a, _b;
if (this.test.afterFn)
await this._executeTestFn(phase_2.default.inTestAfterHook, this.test.afterFn, this.executionTimeout);
else if ((_a = this.test.fixture) === null || _a === void 0 ? void 0 : _a.afterEachFn)
await this._executeTestFn(phase_2.default.inFixtureAfterEachHook, (_b = this.test.fixture) === null || _b === void 0 ? void 0 : _b.afterEachFn, this.executionTimeout);
if (this.test.globalAfterFn)
await this._executeTestFn(phase_2.default.inTestAfterHook, this.test.globalAfterFn, this.executionTimeout);
}
async _finalizeTestRun(id) {
if (this.compilerService) {
const warnings = await this.compilerService.getWarningMessages({ testRunId: id });
warnings.forEach(warning => {
this.warningLog.addWarning(warning);
});
await this.compilerService.removeTestRunFromState({ testRunId: id });
}
test_run_tracker_1.default.removeActiveTestRun(id);
}
async start() {
test_run_tracker_1.default.addActiveTestRun(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_2.default.inTest, this.test.fn, this.executionTimeout);
await this._runAfterHook();
}
if (this.disconnected)
return;
this.phase = phase_2.default.pendingFinalization;
this.browserConnection.removeListener('disconnected', onDisconnected);
if (this.errs.length && this.debugOnFail) {
const errStr = this.debugReporterPluginHost.formatError(this.errs[0]);
await this._enqueueSetBreakpointCommand(void 0, errStr);
}
await this.emit('before-done');
await this._internalExecuteCommand(new serviceCommands.TestDoneCommand());
this._addPendingPageErrorIfAny();
this._requestHookEventProvider.clearRequestEventListeners();
this.normalizeRequestHookErrors();
await this._finalizeTestRun(this.session.id);
await this.emit('done');
}
// Errors
_addPendingPageErrorIfAny() {
const error = this.pendingPageError;
if (error) {
this.addError(error);
this.pendingPageError = null;
return true;
}
return false;
}
_ensureErrorId(err) {
// @ts-ignore
err.id = err.id || (0, nanoid_1.nanoid)(7);
}
_createErrorAdapter(err) {
this._ensureErrorId(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 = (0, 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 = (0, lodash_1.chain)(requestHookErrors)
.uniqBy(e => {
const err = e;
return err.hookClassName + err.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 ? (0, 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();
// @ts-ignore
return consoleMessageCopy[String(this.activeWindowId)];
}
async _enqueueGetCookies(command) {
const { cookies, urls } = command;
return this._cookieProvider.getCookies(cookies, urls);
}
async _enqueueSetCookies(command) {
const cookies = command.cookies;
const url = command.url || await this.getCurrentUrl();
return this._cookieProvider.setCookies(cookies, url);
}
async _enqueueDeleteCookies(command) {
const { cookies, urls } = command;
return this._cookieProvider.deleteCookies(cookies, urls);
}
async _enqueueSetBreakpointCommand(callsite, error) {
if (this.debugLogger)
this.debugLogger.showBreakpoint(this.session.id, this.browserConnection.userAgent, callsite, error);
this.debugging = await this._internalExecuteCommand(new serviceCommands.SetBreakpointCommand(!!error, !!this.compilerService), callsite);
}
_removeAllNonServiceTasks() {
this.driverTaskQueue = this.driverTaskQueue.filter(driverTask => (0, utils_2.isServiceCommand)(driverTask.command));
this.browserManipulationQueue.removeAllNonServiceManipulations();
}
_handleDebugState(driverStatus) {
if (driverStatus.debug)
this.emit(driverStatus.debug);
}
// 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) {
// @ts-ignore
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;
if (this.pendingRequest)
this.pendingRequest.resolve(command);
this._clearPendingRequest();
}
// Handle driver request
_shouldResolveCurrentDriverTask(driverStatus) {
const currentCommand = this.currentDriverTask.command;
const isExecutingObservationCommand = currentCommand instanceof observationCommands.ExecuteSelectorCommand ||
currentCommand instanceof observation_1.ExecuteClientFunctionCommand;
const isDebugActive = currentCommand instanceof serviceCommands.SetBreakpointCommand;
const shouldExecuteCurrentCommand = driverStatus.isFirstRequestAfterWindowSwitching && (isExecutingObservationCommand || isDebugActive);
return !shouldExecuteCurrentCommand;
}
_fulfillCurrentDriverTask(driverStatus) {
var _a;
if (!this.currentDriverTask)
return;
if ((_a = driverStatus.warnings) === null || _a === void 0 ? void 0 : _a.length) {
driverStatus.warnings.forEach((warning) => {
(0, add_rendered_warning_1.default)(this.warningLog, warning_message_1.default[warning.type], this.currentDriverTask.callsite, ...warning.args);
});
}
if (driverStatus.executionError)
this._rejectCurrentDriverTask(driverStatus.executionError);
else if (this._shouldResolveCurrentDriverTask(driverStatus))
this._resolveCurrentDriverTask(driverStatus.result);
}
_handlePageErrorStatus(pageError) {
if (this.currentDriverTask && (0, utils_2.isCommandRejectableByPageError)(this.currentDriverTask.command)) {
this._rejectCurrentDriverTask(pageError);
this.pendingPageError = null;
return true;
}
this.pendingPageError = this.pendingPageError || pageError;
return false;
}
async _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);
this.consoleMessages.concat(driverStatus.consoleMessages);
this._handleDebugState(driverStatus);
if (!currentTaskRejectedByError && driverStatus.isCommandResult) {
if (isTestDone) {
this._resolveCurrentDriverTask();
return TEST_DONE_CONFIRMATION_RESPONSE;
}
this._fulfillCurrentDriverTask(driverStatus);
if (driverStatus.isPendingWindowSwitching)
return null;
}
return this._getCurrentDriverTaskCommand();
}
async _getCurrentDriverTaskCommand() {
if (!this.currentDriverTask)
return null;
const command = this.currentDriverTask.command;
if (command.type === type_1.default.navigateTo && command.stateSnapshot)
await this._roleProvider.useStateSnapshot(JSON.parse(command.stateSnapshot));
return command;
}
// Execute command
async _executeJsExpression(command) {
const resultVariableName = command.resultVariableName;
let expression = command.expression;
if (resultVariableName)
expression = `${resultVariableName} = ${expression}, ${resultVariableName}`;
if (this.compilerService) {
return this.compilerService.executeJsExpression({
expression,
testRunId: this.id,
options: { skipVisibilityCheck: false },
});
}
return executeJsExpression(expression, this, { skipVisibilityCheck: false });
}
async _executeAsyncJsExpression(command, callsite) {
if (this.compilerService) {
this.asyncJsExpressionCallsites.clear();
return this.compilerService.executeAsyncJsExpression({
expression: command.expression,
testRunId: this.id,
callsite,
});
}
return executeAsyncJsExpression(command.expression, this, callsite);
}
_redirectReExecutablePromiseExecutionToCompilerService(command) {
if (!this.compilerService)
return;
const self = this;
command.actual = re_executable_promise_1.default.fromFn(async () => {
var _a;
return (_a = self.compilerService) === null || _a === void 0 ? void 0 : _a.getAssertionActualValue({
testRunId: self.id,
commandId: command.id,
});
});
}
_redirectAssertionFnExecutionToCompilerService(executor) {
executor.fn = () => {
var _a;
return (_a = this.compilerService) === null || _a === void 0 ? void 0 : _a.executeAssertionFn({
testRunId: this.id,
commandId: executor.command.id,
});
};
}
async _executeAssertion(command, callsite) {
if (command.actual === Symbol.for(marker_1.RE_EXECUTABLE_PROMISE_MARKER_DESCRIPTION))
this._redirectReExecutablePromiseExecutionToCompilerService(command);
const assertionTimeout = (0, get_assertion_timeout_1.default)(command, this.opts);
const executor = new executor_1.default(command, assertionTimeout, callsite);
executor.once('start-assertion-retries', (timeout) => this._internalExecuteCommand(new serviceCommands.ShowAssertionRetriesStatusCommand(timeout)));
executor.once('end-assertion-retries', (success) => this._internalExecuteCommand(new serviceCommands.HideAssertionRetriesStatusCommand(success)));
executor.once('non-serializable-actual-value', this._redirectAssertionFnExecutionToCompilerService);
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;
else if (command.type === type_1.default.disableDebug) {
this.debugLogger.hideBreakpoint(this.session.id);
this.debugging = false;
}
}
async _adjustScreenshotCommand(command) {
const browserId = this.browserConnection.id;
const { hasChromelessScreenshots } = await this.browserConnection.provider.hasCustomActionForBrowser(browserId);
if (!hasChromelessScreenshots)
command.generateScreenshotMark();
}
async _adjustCommandOptionsAndEnvironment(command, callsite) {
var _a;
if (((_a = command.options) === null || _a === void 0 ? void 0 : _a.confidential) !== void 0)
return;
if (command.type === type_1.default.typeText) {
const result = await this._internalExecuteCommand(command.selector, callsite);
if (!result)
return;
const node = this.replicator.decode(result);
command.options.confidential = (0, is_password_input_1.default)(node);
}
else if (command.type === type_1.default.pressKey) {
const result = await this._internalExecuteCommand(new serviceCommands.GetActiveElementCommand());
if (!result)
return;
const node = this.replicator.decode(result);
command.options.confidential = (0, is_password_input_1.default)(node);
}
else if (command instanceof observation_1.ExecuteClientFunctionCommandBase && !!this.compilerService && !this._clientEnvironmentPrepared) {
this._clientEnvironmentPrepared = true;
await this._internalExecuteCommand(new serviceCommands.PrepareClientEnvironmentInDebugMode(command.esmRuntime));
}
}
async _setBreakpointIfNecessary(command, callsite) {
if (!this.disableDebugBreakpoints && this.debugging && (0, utils_2.canSetDebuggerBreakpointBeforeCommand)(command))
await this._enqueueSetBreakpointCommand(callsite);
}
async executeCommand(command, callsite) {
return command instanceof base_js_1.ActionCommandBase
? this._executeActionCommand(command, callsite)
: this._internalExecuteCommand(command, callsite);
}
async _executeActionCommand(command, callsite) {
const actionArgs = { apiActionName: command.methodName, command };
let errorAdapter = null;
let error = null;
let result = null;
const start = new Date().getTime();
try {
await this._adjustCommandOptionsAndEnvironment(command, callsite);
}
catch (err) {
error = err;
}
await this.emitActionEvent('action-start', actionArgs);
try {
if (!error)
result = await this._internalExecuteCommand(command, callsite);
}
catch (err) {
if (this.phase === phase_2.default.pendingFinalization && err instanceof test_run_1.ExternalAssertionLibraryError)
(0, add_rendered_warning_1.default)(this.warningLog, { message: warning_message_1.default.unawaitedMethodWithAssertion, actionId: command.actionId }, callsite);
else
error = err;
}
const duration = new Date().getTime() - 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(command.actionId);
errorAdapter = this._createErrorAdapter((0, process_test_fn_error_1.default)(error));
}
else
errorAdapter = error.adapter;
}
Object.assign(actionArgs, {
result,
duration,
err: errorAdapter,
});
await this.emitActionEvent('action-done', actionArgs);
if (error)
throw error;
return result;
}
async _internalExecuteCommand(command, callsite) {
this.debugLog.command(command);
if (this.pendingPageError && (0, utils_2.isCommandRejectableByPageError)(command))
return this._rejectCommandWithPageError(callsite);
if ((0, utils_2.isExecutableOnClientCommand)(command))
this.addingDriverTasksCount++;
this._adjustConfigurationWithCommand(command);
await this._setBreakpointIfNecessary(command, callsite);
if ((0, utils_2.isScreenshotCommand)(command)) {
if (this.opts.disableScreenshots) {
this.warningLog.addWarning({ message: warning_message_1.default.screenshotsDisabled, actionId: command.actionId });
return null;
}
await this._adjustScreenshotCommand(command);
}
if ((0, utils_2.isBrowserManipulationCommand)(command)) {
this.browserManipulationQueue.push(command);
if ((0, utils_2.isResizeWindowCommand)(command) && this.opts.videoPath)
this.warningLog.addWarning({ message: warning_message_1.default.videoBrowserResizing, actionId: command.actionId }, this.test.name);
}
if (command.type === type_1.default.wait)
return (0, delay_1.default)(command.timeout);
if (command.type === type_1.default.setPageLoadTimeout)
return null;
if (command.type === type_1.default.debug) {
// NOTE: In regular mode, it's possible to debug tests only using TestCafe UI ('Resume' and 'Next step' buttons).
// So, we should warn on trying to debug in headless mode.
// In compiler service mode, we can debug even in headless mode using any debugging tools. So, in this case, the warning is excessive.
const canDebug = !!this.compilerService || !this.browserConnection.isHeadlessBrowser();
if (canDebug)
return await this._enqueueSetBreakpointCommand(callsite, void 0);
this.debugging = false;
this.warningLog.addWarning({ message: warning_message_1.default.debugInHeadlessError, actionId: command.actionId });
return null;
}
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.runCustomAction) {
const { fn, args } = command;
const wrappedFn = (0, wrap_custom_action_1.default)(fn);
return await wrappedFn(this, args);
}
if (command.type === type_1.default.assertion)
return this._executeAssertion(command, callsite);
if (command.type === type_1.default.executeExpression)
return await this._executeJsExpression(command);
if (command.type === type_1.default.executeAsyncExpression)
return this._executeAsyncJsExpression(command, callsite);
if (command.type === type_1.default.getBrowserConsoleMessages)
return this._enqueueBrowserConsoleMessagesCommand(command, callsite);
if (command.type === type_1.default.switchToPreviousWindow)
command.windowId = this.browserConnection.previousActiveWindowId;
if (command.type === type_1.default.switchToWindowByPredicate)
return this._switchToWindowByPredicate(command);
if (command.type === type_1.default.getCookies)
return this._enqueueGetCookies(command);
if (command.type === type_1.default.setCookies)
return this._enqueueSetCookies(command);
if (command.type === type_1.default.deleteCookies)
return this._enqueueDeleteCookies(command);
if (command.type === type_1.default.addRequestHooks)
return Promise.all(command.hooks.map(hook => this._addRequestHook(hook)));
if (command.type === type_1.default.removeRequestHooks)
return Promise.all(command.hooks.map(hook => this._removeRequestHook(hook)));
return this._enqueueCommand(command, callsite);
}
_rejectCommandWithPageError(callsite) {
const err = this.pendingPageError;
// @ts-ignore
err.callsite = callsite;
this.pendingPageError = null;
return Promise.reject(err);
}
_sendCloseChildWindowOnFileDownloadingCommand() {
return new actionCommands.CloseChildWindowOnFileDownloading();
}
async _makeScreenshotOnFail(failedActionId) {
const { screenshots } = this.opts;
if (!this.errScreenshotPath && (screenshots === null || screenshots === void 0 ? void 0 : screenshots.takeOnFails))
this.errScreenshotPath = await this._internalExecuteCommand(new browserManipulationCommands.TakeScreenshotOnFailCommand({ failedActionId }));
}
_decorateWithFlag(fn, flagName, value) {
return async () => {
// @ts-ignore
this[flagName] = value;
try {
return await fn();
}
finally {
// @ts-ignore
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 = await this._roleProvider.getStateSnapshot();
state.storages = await this._internalExecuteCommand(new serviceCommands.BackupStoragesCommand());
return state;
}
async _cleanUpCtxs() {
if (this.compilerService) {
await this.compilerService.setCtx({
testRunId: this.id,
value: Object.create(null),
});
await this.compilerService.setFixtureCtx({
testRunId: this.id,
value: Object.create(null),
});
}
else {
this.ctx = Object.create(null);
this.fixtureCtx = Object.create(null);
this.testRunCtx = Object.create(null);
}
}
async switchToCleanRun(url) {
await this._cleanUpCtxs();
this.consoleMessages = new browser_console_messages_1.default();
await this._roleProvider.useStateSnapshot(testcafe_hammerhead_1.StateSnapshot.empty());
if (this.speed !== this.opts.speed) {
const setSpeedCommand = new actionCommands.SetTestSpeedCommand({ speed: this.opts.speed });
await this._internalExecuteCommand(setSpeedCommand);
}
if (this.pageLoadTimeout !== this.opts.pageLoadTimeout) {
const setPageLoadTimeoutCommand = new actionCommands.SetPageLoadTimeoutCommand({ duration: this.opts.pageLoadTimeout });
await this._internalExecuteCommand(setPageLoadTimeoutCommand);
}
await this.navigateToUrl(url, true);
if (this.activeDialogHandler) {
const removeDialogHandlerCommand = new actionCommands.SetNativeDialogHandlerCommand({ dialogHandler: { fn: null } });
await this._internalExecuteCommand(removeDialogHandlerCommand);
}
}
async navigateToUrl(url, forceReload, stateSnapshot) {
const navigateCommand = new actionCommands.NavigateToCommand({ url, forceReload, stateSnapshot });
await this._internalExecuteCommand(navigateCommand);
}
async _getStateSnapshotFromRole(role) {
const prevPhase = this.phase;
if (role.phase === phase_1.default.initialized && role.initErr instanceof error_list_1.default && role.initErr.hasErrors)
role.initErr.adapter = this._createErrorAdapter(role.initErr.items[0]);
this.phase = phase_2.default.inRoleInitializer;
if (role.phase === phase_1.default.uninitialized)
await role.initialize(this);
else if (role.phase === phase_1.default.pendingInitialization)
await (0, 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_2.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);
await this._roleProvider.useStateSnapshot(stateSnapshot);
this.currentRoleId = role.id;
await bookmark.restore(callsite, stateSnapshot);
}
async getCurrentUrl() {
const builder = new ClientFunctionBuilder(() => {
return window.location.href; // eslint-disable-line no-undef
}, { boundTestRun: this });
const getLocation = builder.getFunction();
return await getLocation();
}
async _switchToWindowByPredicate(command) {
const currentWindows = await this._internalExecuteCommand(new actions_1.GetCurrentWindowsCommand({}, this));
const windows = await (0, async_filter_1.default)(currentWindows, async (wnd) => {
try {
const predicateData = {
url: new url_1.URL(wnd.url),
title: wnd.title,
};
if (this.compilerService) {
const compilerServicePredicateData = Object.assign(predicateData, {
testRunId: this.id,
commandId: command.id,
});
return this.compilerService.checkWindow(compilerServicePredicateData);
}
return command.checkWindow(predicateData);
}
catch (e) {
throw new test_run_1.SwitchToWindowPredicateError(e.message);
}
});
if (!windows.length)
throw new test_run_1.WindowNotFoundError();
if (windows.length > 1)
this.warningLog.addWarning({ message: warning_message_1.default.multipleWindowsFoundByPredicate, actionId: command.actionId });
await this._internalExecuteCommand(new actions_1.SwitchToWindowCommand({ windowId: windows[0].id }, this));
}
_disconnect(err) {
this.disconnected = true;
if (this.currentDriverTask)
this._rejectCurrentDriverTask(err);
this.emit('disconnected', err);
test_run_tracker_1.default.removeActiveTestRun(this.session.id);
}
_handleFileDownloadingInNewWindowRequest() {
if (this.attachmentDownloadingHandled) {
this.attachmentDownloadingHandled = false;
return this._sendCloseChildWindowOnFileDownloadingCommand();
}
return null;
}
async emitActionEvent(eventName, args) {
// @ts-ignore
if (!this.preventEmitActionEvents)
await this.emit(eventName, args);
}
static isMultipleWindowsAllowed(testRun) {
const { disableMultipleWindows, test } = testRun;
return !disableMultipleWindows && !test.isLegacy && !!testRun.activeWindowId;
}
async initialize() {
await this._clearCookiesAndStorages();
await this._initRequestHooks();
if (!this.compilerService)
return;
await this.compilerService.initializeTestRunData({
testRunId: this.id,
testId: this.test.id,
browser: this.browser,
activeWindowId: this.activeWindowId,
messageBus: this._messageBus,
});
}
async _clearCookiesAndStorages() {
if (this.disablePageReloads)
return;
await this._cookieProvider.initialize();
await this._storagesProvider.initialize();
}
get activeWindowId() {
return this.browserConnection.activeWindowId;
}
// NOTE: this function is time-critical and must return ASAP to avoid client disconnection
async [client_messages_1.default.ready](msg) {
if (msg.status.isObservingFileDownloadingInNewWindow)
return this._handleFileDownloadingInNewWindowRequest();
this.debugLog.driverMessage(msg);
if (this.disconnected)
return Promise.reject(new runtime_1.GeneralError(types_1.RUNTIME_ERRORS.testRunRequestInDisconnectedBrowser, this.browserConnection.browserInfo.alias));
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 = await 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 };
});
}
async [client_messages_1.default.readyForBrowserManipulation](msg) {
this.debugLog.driverMessage(msg);
let result = null;
let error = null;
try {
result = await this.browserManipulationQueue.executePendingManipulation(msg, this._messageBus);
}
catch (err) {
if (err instanceof Error) {
error = {
name: err.name,
message: err.message,
stack: err.stack,
isInternalError: true,
};
}
else
error = err;
}
return { result, error };
}
async [client_messages_1.default.waitForFileDownload](msg) {
this.debugLog.driverMessage(msg);
return new Promise(resolve => {
if (this.fileDownloadingHandled) {
this.fileDownloadingHandled = false;
resolve(true);
}
else
this.resolveWaitForFileDownloadingPromise = resolve;
});
}
}
exports.default = TestRun;
module.exports = exports.default;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvdGVzdC1ydW4vaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQUFBLG1DQUlnQjtBQUVoQixtQ0FBZ0M7QUFDaEMsMkRBQXNEO0FBQ3RELHNFQUE2QztBQUM3Qyx3REFBZ0M7QUFDaEMsdUZBQTZEO0FBQzdELDREQUEwQztBQUMxQyxpR0FBb0Y7QUFDcEYsc0VBQXFEO0FBQ3JELCtDQUFpRDtBQUVqRCxrREFVNkI7QUFFN0Isd0VBQWdEO0FBQ2hELDJEQUEyQztBQUMzQywyREFBbUM7QUFDbkMsbUZBQXlEO0FBQ3pELG9FQUE0QztBQUM1QywrRUFBcUQ7QUFDckQsMERBQXVDO0FBQ3ZDLDBFQUF5RDtBQUN6RCwwRkFBZ0U7QUFDaEUsK0VBQXNEO0FBQ3RELHVGQUErRDtBQUUvRCw2REFXNkI7QUFFN0IsbUVBQXFEO0FBQ3JELDBEQUF3RTtBQUN4RSwrRUFBd0U7QUFDeEUsNENBQStFO0FBRS9FLDRDQVEwQjtBQUUxQixnREFZNEI7QUFFNUIsMkNBQWtFO0FBQ2xFLDRGQUFpRTtBQUNqRSwrRkFBNEU7QUFDNUUsK0RBQXlGO0FBS3pGLDhFQUFxRDtBQUVyRCw4RkFBb0U7QUFDcEUsOEZBQW9FO0FBTXBFLGdEQUFvRTtBQUtwRSx1R0FBNkU7QUFNN0Usb0RBQW1DO0FBRW5DLHdEQUlnQztBQUVoQyxtSEFBa0o7QUFDbEosMkZBQWlFO0FBQ2pFLGlHQUF1RTtBQUN2RSx1RUFBOEM7QUFDOUMsc0VBQXVEO0FBQ3ZELHlFQUFnRDtBQUdoRCwrRkFBb0U7QUFDcEUsNkJBQTBCO0FBRTFCLDBEQUFtRTtBQUNuRSwrQ0FBMEQ7QUFHMUQsZ0RBQTZEO0FBRTdELG1GQUF5RDtBQUV6RCxtREFJeUI7QUFLekIsTUFBTSxXQUFXLEdBQW1CLE9BQU8sQ0FBQyxhQUFhLENBQUMsQ0FBQyxPQUFPLENBQUMsQ0FBQztBQUNwRSxNQUFN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