"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.normalizeTestingTypes = exports.createSetupNodeEvents = exports.cypressConfig = exports.cypressAxeWatcherDebug = exports.cypressTakeScreenshotsFlag = exports.cypressEnabledTestingModes = exports.cypressRunOptionsFlag = exports.cypressAxeCoreSettingsFlag = exports.cypressConfigAutoAnalyzeFlag = exports.cypressConfigRunFlag = exports.configTimeout = void 0;
const fs_1 = __importDefault(require("fs"));
const path_1 = __importDefault(require("path"));
const sendResultsToServer_1 = __importDefault(require("../sendResultsToServer"));
const EventForwarder_1 = __importDefault(require("../EventForwarder"));
const writeVariables_1 = __importDefault(require("../utils/writeVariables"));
const writeExtensionManifest_1 = __importDefault(require("../utils/writeExtensionManifest"));
const headlessNotSupportedError_1 = require("../utils/headlessNotSupportedError");
const mergeChromeArgs_1 = __importDefault(require("../utils/mergeChromeArgs"));
const createDebugger_1 = __importDefault(require("../createDebugger"));
const readVariables_1 = __importDefault(require("../utils/readVariables"));
const checkUserArgs_1 = require("../utils/checkUserArgs");
const constants_1 = require("../utils/constants");
const debugLogger = (0, createDebugger_1.default)('CypressController');
exports.configTimeout = '__AXE_WATCHER_TIMEOUT_CONFIG';
exports.cypressConfigRunFlag = '__AXE_WATCHER_CYPRESS_CONFIG_RUN';
exports.cypressConfigAutoAnalyzeFlag = '__AXE_WATCHER_AUTO_ANALYZE';
exports.cypressAxeCoreSettingsFlag = '__AXE_WATCHER_AXE_CORE_SETTINGS';
exports.cypressRunOptionsFlag = '__AXE_WATCHER_RUN_OPTIONS';
exports.cypressEnabledTestingModes = '__AXE_WATCHER_CYPRESS_TESTING_TYPES';
exports.cypressTakeScreenshotsFlag = '__AXE_WATCHER_TAKE_SCREENSHOTS';
exports.cypressAxeWatcherDebug = '__AXE_WATCHER_DEBUG';
function isErrnoException(error) {
    return error instanceof Error && 'code' in error;
}
function moveFile(src, dest) {
    try {
        fs_1.default.renameSync(src, dest);
    }
    catch (error) {
        if (isErrnoException(error) && error.code === 'EXDEV') {
            fs_1.default.copyFileSync(src, dest);
            fs_1.default.unlinkSync(src);
        }
        else {
            throw error;
        }
    }
}
const cypressConfig = (config) => {
    const { axe, ...userConfig } = config;
    const { DEBUG } = process.env;
    const hasWatcherDebug = DEBUG && DEBUG.includes('axe-watcher');
    const testingTypes = (0, exports.normalizeTestingTypes)(axe.testingTypes);
    if (!axe.projectId) {
        console.warn('Warning: `projectId` within axe configuration will become a mandatory field in a future release. Please supply your `projectId` found on your projects page');
    }
    (0, writeVariables_1.default)({
        ...axe,
        cypress: true
    });
    (0, writeExtensionManifest_1.default)({
        all_frames: true,
        exclude_globs: [
            '*/__/#/specs/runner?file=*'
        ]
    });
    const variables = (0, readVariables_1.default)();
    const shouldRunWatcherInComponentMode = testingTypes?.includes('component');
    const envVariables = {
        [exports.cypressConfigRunFlag]: true,
        [exports.configTimeout]: variables.timeout,
        [exports.cypressAxeCoreSettingsFlag]: variables.axe_core_settings,
        [exports.cypressRunOptionsFlag]: variables.run_options,
        [exports.cypressEnabledTestingModes]: testingTypes,
        [exports.cypressAxeWatcherDebug]: hasWatcherDebug,
        [exports.cypressTakeScreenshotsFlag]: !!variables.take_screenshots,
        [exports.cypressConfigAutoAnalyzeFlag]: axe.autoAnalyze === undefined ? true : axe.autoAnalyze
    };
    if (userConfig.e2e?.env) {
        userConfig.e2e.env = Object.assign({}, userConfig.e2e.env, envVariables);
    }
    if (userConfig.component?.env && shouldRunWatcherInComponentMode) {
        userConfig.component.env = Object.assign({}, userConfig.component.env, envVariables);
    }
    if (!userConfig.e2e?.env &&
        !(userConfig.component?.env && shouldRunWatcherInComponentMode)) {
        userConfig.env = Object.assign({}, userConfig.env, envVariables);
    }
    return {
        ...userConfig,
        e2e: {
            ...userConfig.e2e,
            setupNodeEvents: (0, exports.createSetupNodeEvents)('e2e', userConfig, variables.screenshot_dir)
        },
        ...(shouldRunWatcherInComponentMode &&
            userConfig.component?.devServer && {
            component: {
                ...userConfig.component,
                setupNodeEvents: (0, exports.createSetupNodeEvents)('component', userConfig, variables.screenshot_dir)
            }
        })
    };
};
exports.cypressConfig = cypressConfig;
const createSetupNodeEvents = (testType, userConfig, screenshotDir) => {
    return async function setupNodeEvents(cypressOn, ...args) {
        const eventForwarder = new EventForwarder_1.default();
        const on = eventForwarder.on;
        const userNodeEventConfig = await userConfig[testType]?.setupNodeEvents?.(on, ...args);
        if (userNodeEventConfig) {
            userNodeEventConfig.env = Object.assign({}, userNodeEventConfig.env, {
                [exports.cypressConfigRunFlag]: true
            });
        }
        const screenshotStore = {};
        on('after:screenshot', details => {
            if (!details.name ||
                !details.name.startsWith(constants_1.AXE_WATCHER_SCREENSHOT_PREFIX)) {
                return details;
            }
            try {
                const base64 = fs_1.default.readFileSync(details.path).toString('base64');
                if (screenshotDir) {
                    fs_1.default.mkdirSync(screenshotDir, { recursive: true });
                    const dest = path_1.default.join(screenshotDir, `${details.name}.png`);
                    moveFile(details.path, dest);
                    screenshotStore[details.name] = { base64, path: dest };
                    debugLogger('Screenshot captured and moved', {
                        name: details.name,
                        dest
                    });
                }
                else {
                    fs_1.default.unlinkSync(details.path);
                    screenshotStore[details.name] = { base64 };
                    debugLogger('Screenshot captured', { name: details.name });
                }
            }
            catch (error) {
                debugLogger('Failed to process screenshot file', { error });
            }
            return details;
        });
        on('task', {
            __uploadAxeWatcherResults: async ({ results, skipped_url }) => {
                if (!results?.length && !skipped_url) {
                    return null;
                }
                for (const result of results ?? []) {
                    if (!result.screenshot_id) {
                        continue;
                    }
                    if (!(result.screenshot_id in screenshotStore)) {
                        debugLogger('Screenshot missing for result; clearing screenshot_id', {
                            screenshot_id: result.screenshot_id
                        });
                        result.screenshot_id = null;
                        continue;
                    }
                    const stored = screenshotStore[result.screenshot_id];
                    result.screenshot = stored.base64;
                    result.screenshot_path = stored.path ?? null;
                    delete screenshotStore[result.screenshot_id];
                    debugLogger('Screenshot attached for result', {
                        screenshot_id: result.screenshot_id
                    });
                }
                const sentResult = await (0, sendResultsToServer_1.default)({
                    skipped_url,
                    results,
                    debugLogger
                });
                return sentResult || null;
            },
            __debugAxeWatcher: (message) => {
                debugLogger(message);
                return null;
            }
        });
        on('before:browser:launch', (browser, launchOptions) => {
            if (browser.name.startsWith('firefox') ||
                browser.name.startsWith('electron')) {
                throw new Error(`The @axe-core/watcher package only supports running in Chrome browsers such as "Chrome", "Chrome for Testing" or "Chromium", but Cypress is configured with browser "${browser.name}". Please refer to our System Requirements for more information: https://docs.deque.com/developer-hub/2/en/dh-system-requirements`);
            }
            if (browser.isHeadless && launchOptions.args.includes('--headless')) {
                throw new headlessNotSupportedError_1.HeadlessNotSupportedError('In Cypress, "--headless=new" became the default headless mode in Cypress version 12.15.0. Ensure your Cypress version is up to date and that you are not using a "before:browser:launch" configuration that adds "--headless" to launchOptions.args.');
            }
            const existingArgs = launchOptions.args;
            (0, checkUserArgs_1.checkUserArgs)(existingArgs);
            launchOptions.args = (0, mergeChromeArgs_1.default)(existingArgs, {
                disableOtherExtensions: false,
                disableLoadExtensionCommandFeature: true
            });
            return launchOptions;
        });
        eventForwarder.forward(cypressOn);
        return userNodeEventConfig;
    };
};
exports.createSetupNodeEvents = createSetupNodeEvents;
const normalizeTestingTypes = (testingTypes) => {
    const validTestingTypes = ['e2e', 'component'];
    if (!testingTypes) {
        return ['e2e'];
    }
    if (Array.isArray(testingTypes)) {
        if (!testingTypes.length) {
            throw new Error('`testingTypes` should include `e2e`, `component`, or both. Specifying an empty array is not supported.');
        }
        const invalidTestingTypes = testingTypes.filter(testingType => testingType && !validTestingTypes.includes(testingType));
        if (invalidTestingTypes.length) {
            throw new Error(`Invalid testing types provided: ${invalidTestingTypes.join(', ')}. Valid options are: ${validTestingTypes.join(', ')}.`);
        }
    }
    else if (typeof testingTypes === 'string') {
        if (!validTestingTypes.includes(testingTypes)) {
            throw new Error(`Invalid testing type provided: ${testingTypes}. Valid options are: ${validTestingTypes.join(', ')}.`);
        }
    }
    return Array.isArray(testingTypes) ? testingTypes : [testingTypes];
};
exports.normalizeTestingTypes = normalizeTestingTypes;
//# sourceMappingURL=cypress.js.map