/**
 * Default tag filter applied by `runAxe`. Mirrors WCAG 2.0 + 2.1 levels A
 * and AA. Override with `{ tags: [...] }` to widen or narrow the scope.
 */
export const DEFAULT_AXE_TAGS = ['wcag2a', 'wcag2aa', 'wcag21a', 'wcag21aa'];
/**
 * Page-level axe rules that fire on the bare HTML harness Stencil's E2E
 * provides (no `<title>`, no `<html lang>`, no landmarks, no `<h1>`).
 * They are disabled by default because they describe document chrome,
 * not component behavior — flagging them at component scope yields noise.
 *
 * Tests can opt back in for a specific case:
 *
 * ```ts
 * await runAxe(page, { rules: { 'document-title': { enabled: true } } });
 * ```
 */
export const DEFAULT_DISABLED_RULES = [
    'document-title',
    'html-has-lang',
    'landmark-one-main',
    'page-has-heading-one',
    'region',
];
/**
 * Injects axe-core into an active Stencil E2EPage and returns any
 * accessibility violations found in the current document.
 *
 * Usage:
 *
 * ```ts
 * const page = await newE2EPage();
 * await page.setContent('<pds-button>Click me</pds-button>');
 * const violations = await runAxe(page);
 * expect(violations).toEqual([]);
 * ```
 *
 * Component tests should assert against the returned array directly so
 * each component can document its own baseline (zero violations is the
 * goal; suppressions should be deliberate and commented).
 */
export async function runAxe(page, options = {}) {
    var _a, _b;
    // Resolve axe-core's UMD bundle from node_modules at test time so we
    // do not depend on a build step injecting it.
    // eslint-disable-next-line @typescript-eslint/no-var-requires
    const axePath = require.resolve('axe-core/axe.min.js');
    await page.addScriptTag({ path: axePath });
    const defaultRules = DEFAULT_DISABLED_RULES.reduce((acc, rule) => {
        acc[rule] = { enabled: false };
        return acc;
    }, {});
    const runOptions = {
        runOnly: {
            type: 'tag',
            values: (_a = options.tags) !== null && _a !== void 0 ? _a : [...DEFAULT_AXE_TAGS],
        },
        rules: Object.assign(Object.assign({}, defaultRules), ((_b = options.rules) !== null && _b !== void 0 ? _b : {})),
    };
    // Embed options in a string-evaluated IIFE so Istanbul does not instrument
    // the browser-side function (cov_* globals are undefined in Puppeteer).
    const optsJson = JSON.stringify(runOptions);
    const violations = await page.evaluate(`
    (async () => {
      const opts = ${optsJson};
      const axe = window.axe;
      if (!axe) {
        throw new Error('axe-core failed to load on the page.');
      }
      const results = await axe.run(document, opts);
      return results.violations;
    })()
  `);
    return violations;
}
/**
 * Formats an axe target selector, including nested arrays for shadow DOM
 * and iframe boundaries (axe's `UnlabelledFrameSelector` shape).
 */
export function formatAxeTarget(target) {
    return target
        .map((segment) => (Array.isArray(segment) ? segment.join(' ') : segment))
        .join(' >> ');
}
/**
 * Formats an array of axe violations into a readable failure message for
 * use in test output. Returns an empty string when there are no
 * violations, so it can be passed directly into `expect(...).toBe('')`.
 */
export function formatViolations(violations) {
    if (violations.length === 0)
        return '';
    return violations
        .map((v) => {
        var _a;
        const targets = v.nodes.map((n) => formatAxeTarget(n.target)).join(', ');
        return `• [${(_a = v.impact) !== null && _a !== void 0 ? _a : 'unknown'}] ${v.id} — ${v.help}\n    ${targets}\n    ${v.helpUrl}`;
    })
        .join('\n\n');
}
//# sourceMappingURL=axe.js.map
