"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const path_1 = __importDefault(require("path"));
const read_file_relative_1 = require("read-file-relative");
const mustache_1 = __importDefault(require("mustache"));
const testcafe_hammerhead_1 = require("testcafe-hammerhead");
const command_1 = __importDefault(require("./command"));
const type_1 = __importDefault(require("../test-run-error/type"));
const formattable_adapter_1 = __importDefault(require("../test-run-error/formattable-adapter"));
// Const
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 ASYNC_SERVICE_MESSAGE_HANDLERS = [command_1.default.takeScreenshot, command_1.default.fatalError, command_1.default.assertionFailed, command_1.default.done];
class LegacyTestRun extends testcafe_hammerhead_1.Session {
    constructor({ test, browserConnection, screenshotCapturer, opts }) {
        var uploadsRoot = path_1.default.dirname(test.fixture.path);
        super(uploadsRoot);
        this.methodLock = Promise.resolve();
        this.unstable = false;
        this.opts = opts;
        this.test = test;
        this.browserConnection = browserConnection;
        this.isFileDownloading = false;
        this.errs = [];
        this.nativeDialogsInfo = null;
        this.nativeDialogsInfoTimeStamp = 0;
        this.stepsSharedData = {};
        this.screenshotCapturer = screenshotCapturer;
        this.injectable.scripts.push('/testcafe-core.js');
        this.injectable.scripts.push('/testcafe-ui.js');
        this.injectable.scripts.push('/testcafe-automation.js');
        this.injectable.scripts.push('/testcafe-legacy-runner.js');
        this.injectable.styles.push('/testcafe-ui-styles.css');
    }
    static makeBlocking(target, methodName) {
        const method = target[methodName];
        target[methodName] = function (...args) {
            this.methodLock = this.methodLock
                .then(() => method.apply(this, args));
            return this.methodLock;
        };
    }
    async getPayloadScript() {
        var sharedJs = this.test.fixture.getSharedJs();
        return mustache_1.default.render(TEST_RUN_TEMPLATE, {
            stepNames: JSON.stringify(this.test.stepData.names),
            testSteps: this.test.stepData.js,
            sharedJs: sharedJs,
            testRunId: this.id,
            browserId: this.browserConnection.id,
            browserHeartbeatUrl: this.browserConnection.heartbeatUrl,
            browserStatusUrl: this.browserConnection.statusDoneUrl,
            takeScreenshots: this.screenshotCapturer.enabled,
            takeScreenshotsOnFails: this.opts.takeScreenshotsOnFails,
            skipJsErrors: this.opts.skipJsErrors,
            nativeDialogsInfo: JSON.stringify(this.nativeDialogsInfo),
            selectorTimeout: this.opts.selectorTimeout,
            canUseDefaultWindowActions: JSON.stringify(await this.browserConnection.canUseDefaultWindowActions())
        });
    }
    async getIframePayloadScript(iframeWithoutSrc) {
        var sharedJs = this.test.fixture.getSharedJs();
        var payloadScript = mustache_1.default.render(IFRAME_TEST_RUN_TEMPLATE, {
            sharedJs: sharedJs,
            takeScreenshotsOnFails: this.opts.takeScreenshotsOnFails,
            skipJsErrors: this.opts.skipJsErrors,
            nativeDialogsInfo: JSON.stringify(this.nativeDialogsInfo),
            selectorTimeout: this.opts.selectorTimeout
        });
        return iframeWithoutSrc ? 'var isIFrameWithoutSrc = true;' + payloadScript : payloadScript;
    }
    async _takeScreenshot(msg) {
        try {
            return await this.screenshotCapturer.captureAction(msg);
        }
        catch (e) {
            // NOTE: swallow the error silently if we can't take screenshots for some
            // reason (e.g. we don't have permissions to write a screenshot file).
            return null;
        }
    }
    async _addError(err) {
        var screenshotPath = null;
        var callsite = err.__sourceIndex !== void 0 &&
            err.__sourceIndex !== null &&
            this.test.sourceIndex[err.__sourceIndex];
        try {
            screenshotPath = await this.screenshotCapturer.captureError(err);
        }
        catch (e) {
            // NOTE: swallow the error silently if we can't take screenshots for some
            // reason (e.g. we don't have permissions to write a screenshot file).
        }
        var errAdapter = new formattable_adapter_1.default(err, {
            userAgent: this.browserConnection.userAgent,
            screenshotPath: screenshotPath,
            callsite: callsite
        });
        this.errs.push(errAdapter);
    }
    async _fatalError(err) {
        await this._addError(err);
        this.emit('done');
    }
    getAuthCredentials() {
        return this.test.fixture.authCredentials;
    }
    handleFileDownload() {
        this.isFileDownloading = true;
    }
    handleAttachment() {
    }
    handlePageError(ctx, errMsg) {
        this._fatalError({
            type: type_1.default.pageNotLoaded,
            message: errMsg
        });
        ctx.redirect(this.browserConnection.forcedIdleUrl);
    }
    async start() {
        // NOTE: required to keep API similar to TestRun. Just do nothing here.
        this.emit('start');
    }
    async initialize() {
        // NOTE: required to keep API compatible to the regular TestRun
    }
    // Service message handlers
    // Asynchronous
    [command_1.default.takeScreenshot](msg) {
        return this._takeScreenshot(msg);
    }
    [command_1.default.fatalError](msg) {
        return this._fatalError(msg.err);
    }
    [command_1.default.assertionFailed](msg) {
        return this._addError(msg.err);
    }
    [command_1.default.done]() {
        this.emit('done');
    }
    // Synchronous
    [command_1.default.setStepsSharedData](msg) {
        this.stepsSharedData = msg.stepsSharedData;
    }
    [command_1.default.getStepsSharedData]() {
        return this.stepsSharedData;
    }
    [command_1.default.getAndUncheckFileDownloadingFlag]() {
        var isFileDownloading = this.isFileDownloading;
        this.isFileDownloading = false;
        return isFileDownloading;
    }
    [command_1.default.waitForFileDownload]() {
        // NOTE: required to keep API similar to TestRun. Just do nothing here.
    }
    [command_1.default.nativeDialogsInfoSet](msg) {
        if (msg.timeStamp >= this.nativeDialogsInfoTimeStamp) {
            //NOTE: the server can get messages in the wrong sequence if they was sent with a little distance (several milliseconds),
            // we don't take to account old messages
            this.nativeDialogsInfoTimeStamp = msg.timeStamp;
            this.nativeDialogsInfo = msg.info;
        }
    }
}
exports.default = LegacyTestRun;
for (const handler of ASYNC_SERVICE_MESSAGE_HANDLERS)
    LegacyTestRun.makeBlocking(LegacyTestRun.prototype, handler);