"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.WRAPPED_COMMANDS = void 0;
const constants_1 = require("./utils/constants");
const cypressConfigRunFlag = '__AXE_WATCHER_CYPRESS_CONFIG_RUN';
const cypressConfigAutoAnalyzeFlag = '__AXE_WATCHER_AUTO_ANALYZE';
const configTimeout = '__AXE_WATCHER_TIMEOUT_CONFIG';
const cypressAxeCoreSettingsFlag = '__AXE_WATCHER_AXE_CORE_SETTINGS';
const cypressRunOptionsFlag = '__AXE_WATCHER_RUN_OPTIONS';
const cypressEnabledTestingModes = '__AXE_WATCHER_CYPRESS_TESTING_TYPES';
const cypressConfigTakeScreenshotsFlag = '__AXE_WATCHER_TAKE_SCREENSHOTS';
let isStopped = !Cypress.env(cypressConfigAutoAnalyzeFlag);
const takeScreenshots = !!Cypress.env(cypressConfigTakeScreenshotsFlag);
exports.WRAPPED_COMMANDS = [
    'blur',
    'check',
    'clear',
    'click',
    'dblclick',
    'focus',
    'go',
    'reload',
    'scrollIntoView',
    'scrollTo',
    'select',
    'submit',
    'trigger',
    'type',
    'uncheck',
    'visit',
    'wait'
];
const logDebugAxeWatcher = ({ message }) => {
    if (Cypress.env('__AXE_WATCHER_DEBUG')) {
        cy.task('__debugAxeWatcher', message, { log: false });
    }
};
const shouldAnalyzeLocation = (location) => ['http:', 'https:', 'file:'].includes(location.protocol);
function captureScreenshotSafe(screenshotId) {
    const onFail = (err) => {
        logDebugAxeWatcher({
            message: `Screenshot capture failed: ${err.message}`
        });
        return false;
    };
    cy.once('fail', onFail);
    cy.screenshot(screenshotId, {
        capture: 'viewport',
        overwrite: true,
        log: false
    }).then(() => {
        cy.off('fail', onFail);
    });
}
if (!Cypress.env(cypressConfigRunFlag)) {
    throw new Error(`Cypress is not configured for axe watcher. Please ensure that axe watcher's cypressConfig() is invoked within Cypress' defineConfig() in your ${Cypress.config('configFile')}. All tests will fail with this error.`);
}
exports.WRAPPED_COMMANDS.forEach(method => Cypress.Commands.overwrite(method, (originalFn, ...args) => {
    const currentCommand = cy.state('current');
    const currentCommandName = currentCommand?.get('name');
    const currentCommandType = currentCommand?.get('type');
    const tryRequerySubject = 'getSubjectFromChain' in cy;
    const isNestedCommandCall = currentCommandName && currentCommandName !== method;
    const isComponentTestingMode = Cypress.testingType === 'component';
    const isComponentTestingEnabled = Cypress.env(cypressEnabledTestingModes)?.includes('component');
    const isComponentTestingNotConfigured = isComponentTestingMode && !isComponentTestingEnabled;
    if (isNestedCommandCall || isComponentTestingNotConfigured) {
        return originalFn(...args);
    }
    const originalSubject = cy.subject?.();
    const originalSubjectChain = cy.subjectChain?.();
    let commandChain = cy.window().axeWatcherAnalyze({
        __Method: method,
        __UserRequestedAnalyze: false
    });
    if (tryRequerySubject) {
        const timeout = args.find(arg => arg?.timeout)?.timeout;
        commandChain = commandChain.__axeRestoreSubject(originalSubjectChain, timeout);
        return commandChain.then({ timeout: 999999 }, refreshedSubject => originalFn(...updateSubject(args, currentCommandType, refreshedSubject)));
    }
    else {
        return (commandChain
            .then(() => originalSubject)
            .then(() => originalFn(...args)));
    }
}));
function updateSubject(args, commandType, refreshedSubject) {
    if (commandType === 'parent') {
        return args;
    }
    else {
        return [refreshedSubject, ...args.slice(1)];
    }
}
Cypress.Commands.addQuery('__axeRestoreSubject', function (subjectChain, timeout) {
    this.set('timeout', timeout);
    this.set('onFail', (err) => {
        const runner = cy.state('runnable');
        err.codeFrame = runner.invocationDetails;
    });
    return () => cy.getSubjectFromChain(subjectChain);
});
function axeWatcherFlushCommand({ timeout } = {}) {
    logDebugAxeWatcher({
        message: `Flush: Invoked (${isStopped ? 'will not' : 'may'} analyze implicitly)`
    });
    if (Cypress.testingType === 'component' &&
        !Cypress.env(cypressEnabledTestingModes)?.includes('component')) {
        logDebugAxeWatcher({
            message: `Not executing Flush due to be running in component testing mode without watcher enabled for that mode`
        });
        return;
    }
    cy.window().then(win => {
        if (!shouldAnalyzeLocation(win.location)) {
            return Promise.resolve();
        }
        let onFlushEnd;
        let onAxeResult;
        let timer = null;
        const screenshotId = takeScreenshots
            ? `${constants_1.AXE_WATCHER_SCREENSHOT_PREFIX}${crypto.randomUUID()}`
            : undefined;
        return Promise.race([
            new Promise(resolve => {
                const results = [];
                onAxeResult = (event) => {
                    results.push(...event.detail);
                };
                onFlushEnd = () => {
                    resolve(results);
                };
                win.addEventListener('axe:flush-end', onFlushEnd);
                win.addEventListener('axe:result', onAxeResult);
                const event = new CustomEvent('axe:flush-start', {
                    detail: {
                        isStopped,
                        axeCoreSettings: Cypress.env(cypressAxeCoreSettingsFlag),
                        runOptions: Cypress.env(cypressRunOptionsFlag),
                        screenshot_id: screenshotId
                    }
                });
                win.dispatchEvent(event);
            }),
            new Promise((_, reject) => {
                timer = setTimeout(() => {
                    reject(new Error(`Watcher timed out sending results to the server. To resolve this problem, increase the \`timeout.flush\` property within your configuration or see ${constants_1.DOCS_LINK} for more troubleshooting.`));
                }, timeout || Cypress.env(configTimeout).flush);
            })
        ])
            .then((results) => {
            if (takeScreenshots && screenshotId) {
                for (const result of results) {
                    const hasViolations = (result.results?.violations?.length ?? 0) > 0;
                    if (!hasViolations || !result.screenshot_id) {
                        continue;
                    }
                    if (result.screenshot_id === screenshotId) {
                        captureScreenshotSafe(screenshotId);
                        break;
                    }
                }
            }
            cy.task('__uploadAxeWatcherResults', { results }, { log: false }).then(result => {
                const resultWithFailureStatus = result;
                const message = resultWithFailureStatus?.failureStatus
                    ? `Failed. ${resultWithFailureStatus.failureStatus}`
                    : 'Complete';
                logDebugAxeWatcher({ message: `Flush: ${message}` });
            });
        })
            .finally(() => {
            if (timer) {
                clearTimeout(timer);
            }
            win.removeEventListener('axe:flush-end', onFlushEnd);
            win.removeEventListener('axe:result', onAxeResult);
        });
    });
}
const doesCypressCommandExist = (commandName) => {
    return !!Cypress.cy[commandName];
};
function axeWatcherAnalyzeCommand(subject, { __Method, __UserRequestedAnalyze = true } = {}, { timeout } = {}) {
    const userRequestedAnalyze = __UserRequestedAnalyze;
    const message = userRequestedAnalyze
        ? 'User requested analysis'
        : `Invoked${__Method ? ` - ${__Method}` : ''}`;
    logDebugAxeWatcher({
        message: `Analyze: ${message}`
    });
    cy.window().then(win => {
        if (!shouldAnalyzeLocation(win.location)) {
            logDebugAxeWatcher({
                message: `Analyze: Skipped - invalid protocol`
            });
            if (userRequestedAnalyze) {
                return Promise.reject(new Error(`Cannot perform manual analysis - invalid protocol: ${win.location.protocol}`));
            }
            return Promise.resolve({
                message: `Skipped - Invalid protocol`,
                subject
            });
        }
        if (isStopped && !userRequestedAnalyze) {
            logDebugAxeWatcher({
                message: `Analyze: Skipped - manual mode`
            });
            return Promise.resolve({ message: `Skipped (Manual mode)`, subject });
        }
        let timer = null;
        let fn;
        const screenshotId = takeScreenshots
            ? `${constants_1.AXE_WATCHER_SCREENSHOT_PREFIX}${crypto.randomUUID()}`
            : undefined;
        return (Promise.race([
            new Promise(resolve => {
                fn = (event) => {
                    resolve({
                        message: event.detail.message,
                        hasViolations: event.detail.hasViolations,
                        subject
                    });
                };
                win.addEventListener('axe:manual-mode-analyze-done', fn);
                const event = new CustomEvent('axe:manual-mode-analyze', {
                    detail: {
                        userRequestedAnalyze,
                        axeCoreSettings: Cypress.env(cypressAxeCoreSettingsFlag),
                        runOptions: Cypress.env(cypressRunOptionsFlag),
                        screenshot_id: screenshotId
                    }
                });
                win.dispatchEvent(event);
            }),
            new Promise((_, reject) => {
                timer = setTimeout(() => {
                    reject(new Error(`Watcher timed out before it could finish analyzing the page state. To resolve this problem, increase the \`timeout.analyze\` property within your configuration or see ${constants_1.DOCS_LINK} for more troubleshooting.`));
                }, timeout || Cypress.env(configTimeout).analyze);
            })
        ])
            .then(result => {
            logDebugAxeWatcher({ message: `Analyze: ${result?.message}` });
            if (takeScreenshots && result?.hasViolations && screenshotId) {
                captureScreenshotSafe(screenshotId);
            }
            if (result?.subject) {
                return result.subject;
            }
        })
            .finally(() => {
            if (timer) {
                clearTimeout(timer);
            }
            win.removeEventListener('axe:manual-mode-analyze-done', fn);
        }));
    });
}
function axeWatcherStartCommand(subject, { timeout } = {}) {
    logDebugAxeWatcher({ message: 'Start: Invoked' });
    cy.window().then(win => {
        if (!shouldAnalyzeLocation(win.location)) {
            isStopped = false;
            logDebugAxeWatcher({
                message: 'Clean: Skipped - invalid protocol'
            });
            return Promise.resolve({
                message: 'Clean: Skipped - Invalid protocol',
                subject
            });
        }
        let timer = null;
        let fn;
        return (Promise.race([
            new Promise(resolve => {
                fn = (event) => {
                    resolve({ message: event.detail.message, subject });
                };
                win.addEventListener('axe:manual-mode-clean-done', fn);
                const event = new CustomEvent('axe:manual-mode-clean');
                win.dispatchEvent(event);
            }),
            new Promise((_, reject) => {
                timer = setTimeout(() => {
                    reject(new Error('Watcher could not start automatic mode because `start` timed out. To resolve this problem, increase the `timeout.start` property within your configuration or see ${DOCS_LINK} for more troubleshooting.'));
                }, timeout || Cypress.env(configTimeout).start);
            })
        ])
            .then(result => {
            logDebugAxeWatcher({
                message: `Start: ${result?.message}`
            });
            isStopped = false;
            if (result?.subject) {
                return result.subject;
            }
        })
            .finally(() => {
            if (timer) {
                clearTimeout(timer);
            }
            win.removeEventListener('axe:manual-mode-clean-done', fn);
        }));
    });
}
function axeWatcherStopCommand(subject, { timeout } = {}) {
    logDebugAxeWatcher({ message: `Stop: Invoked` });
    cy.window().then(win => {
        if (!shouldAnalyzeLocation(win.location)) {
            isStopped = true;
            logDebugAxeWatcher({
                message: `Stop: Skipped - invalid protocol`
            });
            return Promise.resolve({
                message: `Skipped - Invalid protocol`,
                subject
            });
        }
        if (isStopped) {
            logDebugAxeWatcher({
                message: `Stop: Analysis skipped - manual mode`
            });
            return Promise.resolve({ message: `Skipped (Manual mode)`, subject });
        }
        let timer = null;
        let fn;
        const screenshotId = takeScreenshots
            ? `${constants_1.AXE_WATCHER_SCREENSHOT_PREFIX}${crypto.randomUUID()}`
            : undefined;
        return (Promise.race([
            new Promise(resolve => {
                fn = (event) => {
                    resolve({
                        message: event.detail.message,
                        hasViolations: event.detail.hasViolations,
                        subject
                    });
                };
                win.addEventListener('axe:manual-mode-analyze-done', fn);
                const event = new CustomEvent('axe:manual-mode-analyze', {
                    detail: {
                        userRequestedAnalyze: false,
                        screenshot_id: screenshotId
                    }
                });
                win.dispatchEvent(event);
            }),
            new Promise((_, reject) => {
                timer = setTimeout(() => {
                    reject(new Error(`Watcher could not stop automatic mode because \`stop\` timed out. To resolve this problem, increase the \`timeout.stop\` property within your configuration or see ${constants_1.DOCS_LINK} for more troubleshooting.`));
                }, timeout || Cypress.env(configTimeout).stop);
            })
        ])
            .then(result => {
            logDebugAxeWatcher({ message: `Stop: ${result?.message}` });
            if (takeScreenshots && result?.hasViolations && screenshotId) {
                captureScreenshotSafe(screenshotId);
            }
            isStopped = true;
            if (result?.subject) {
                return result.subject;
            }
        })
            .finally(() => {
            if (timer) {
                clearTimeout(timer);
            }
            win.removeEventListener('axe:manual-mode-analyze-done', fn);
        }));
    });
}
if (!doesCypressCommandExist('axeAnalyze')) {
    Cypress.Commands.add('axeWatcherAnalyze', { prevSubject: 'optional' }, axeWatcherAnalyzeCommand);
}
Cypress.Commands.add('axeFlush', axeWatcherFlushCommand);
Cypress.Commands.add('axeStop', { prevSubject: 'optional' }, axeWatcherStopCommand);
Cypress.Commands.add('axeStart', { prevSubject: 'optional' }, axeWatcherStartCommand);
Cypress.Commands.add('axeWatcherAnalyze', { prevSubject: 'optional' }, axeWatcherAnalyzeCommand);
Cypress.Commands.add('axeWatcherStart', { prevSubject: 'optional' }, axeWatcherStartCommand);
Cypress.Commands.add('axeWatcherStop', { prevSubject: 'optional' }, axeWatcherStopCommand);
Cypress.Commands.add('axeWatcherFlush', axeWatcherFlushCommand);
//# sourceMappingURL=cypressCommands.js.map