{"_id":"@accesslint/jest","_rev":"6-e76c06f064a56254afb37e735a269d8e","name":"@accesslint/jest","dist-tags":{"latest":"0.1.3"},"versions":{"0.1.0":{"name":"@accesslint/jest","version":"0.1.0","keywords":["jest","accessibility","a11y","wcag","aria","accesslint","matcher","testing","jest-axe-alternative","react-testing-library","testing-library","jsdom"],"license":"MIT","_id":"@accesslint/jest@0.1.0","maintainers":[{"name":"ckundo","email":"cameron@accesslint.com"}],"homepage":"https://github.com/AccessLint/accesslint#readme","bugs":{"url":"https://github.com/AccessLint/accesslint/issues"},"dist":{"shasum":"cd2df6ca320067e41a4ee81becfe1358bfa7c5ef","tarball":"https://registry.npmjs.org/@accesslint/jest/-/jest-0.1.0.tgz","fileCount":7,"integrity":"sha512-fE1wGF11b7UafDdZRJzuCPfgr8G75ftBj2UYH0cVHHskLHQC3fPzaj/HsnhBjC8Iw7LD6lsbc5hSG4Dvf3fJyQ==","signatures":[{"sig":"MEYCIQDpd+/pzkBEKDRO8xIAsUejktgleIfPPL2XDAh8ih/3GAIhAM87ujZwMS3bNHlV+TXenkNDDEm/tRb37Wix2jGXUvQA","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":41075},"main":"dist/index.cjs","type":"module","types":"dist/index.d.ts","module":"dist/index.js","exports":{".":{"import":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"require":{"types":"./dist/index.d.cts","default":"./dist/index.cjs"}}},"gitHead":"c6fde24db16e5659df8bcf2adf0efb09129b4640","scripts":{"test":"jest","build":"tsdown","typecheck":"tsc --noEmit","prepublishOnly":"bun run build"},"_npmUser":{"name":"ckundo","email":"cameron@accesslint.com"},"deprecated":"Broken publish (workspace:* not substituted) — use 0.1.2+","repository":{"url":"git+https://github.com/AccessLint/accesslint.git","type":"git","directory":"jest"},"_npmVersion":"11.9.0","description":"Accessibility assertions for Jest — toBeAccessible() matcher powered by AccessLint","directories":{},"_nodeVersion":"24.14.0","dependencies":{"@accesslint/core":"workspace:*"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"jest":"^29.7.0","expect":"^29.7.0","tsdown":"^0.21.9","ts-jest":"^29.2.5","typescript":"^5.7.0","@types/jest":"^29.5.14","@jest/globals":"^29.7.0","jest-environment-jsdom":"^29.7.0","@accesslint/matchers-internal":"workspace:*"},"peerDependencies":{"jest":">=28"},"_npmOperationalInternal":{"tmp":"tmp/jest_0.1.0_1776477521318_0.19444776012129794","host":"s3://npm-registry-packages-npm-production"}},"0.1.1":{"name":"@accesslint/jest","version":"0.1.1","keywords":["jest","accessibility","a11y","wcag","aria","accesslint","matcher","testing","jest-axe-alternative","react-testing-library","testing-library","jsdom"],"license":"MIT","_id":"@accesslint/jest@0.1.1","maintainers":[{"name":"ckundo","email":"cameron@accesslint.com"}],"homepage":"https://github.com/AccessLint/accesslint#readme","bugs":{"url":"https://github.com/AccessLint/accesslint/issues"},"dist":{"shasum":"d23cee0a0f5399bd722b0fa5c11cf78771d3543b","tarball":"https://registry.npmjs.org/@accesslint/jest/-/jest-0.1.1.tgz","fileCount":7,"integrity":"sha512-nZQeOS9r0rA57Bai0354TOLsTN1cJMPQfrwuAzH1RmZrK350eglxZUpKVdxwdaYxVrrFZ1pKWgmRb9JiPSxO2w==","signatures":[{"sig":"MEUCIB1ygPEpPIT1pRuOEvbkvxZgEzBY2SKhJfzlDF1x4BcXAiEA8B7j99oV6zxH8eJBn2IooGtP7TghnJ9Z0hgAkSCB2fo=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":41063},"main":"dist/index.cjs","type":"module","types":"dist/index.d.ts","module":"dist/index.js","exports":{".":{"import":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"require":{"types":"./dist/index.d.cts","default":"./dist/index.cjs"}}},"gitHead":"30ed0f718b61c6d59ed23d46ff82fe9b69837d5c","scripts":{"test":"jest","build":"tsdown","typecheck":"tsc --noEmit","prepublishOnly":"bun run build"},"_npmUser":{"name":"ckundo","email":"cameron@accesslint.com"},"deprecated":"Docs bug (wrong Jest setup option) — use 0.1.2+","repository":{"url":"git+https://github.com/AccessLint/accesslint.git","type":"git","directory":"jest"},"_npmVersion":"11.9.0","description":"Accessibility assertions for Jest — toBeAccessible() matcher powered by AccessLint","directories":{},"_nodeVersion":"24.14.0","dependencies":{"@accesslint/core":"0.9.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"jest":"^29.7.0","expect":"^29.7.0","tsdown":"^0.21.9","ts-jest":"^29.2.5","typescript":"^5.7.0","@types/jest":"^29.5.14","@jest/globals":"^29.7.0","jest-environment-jsdom":"^29.7.0","@accesslint/matchers-internal":"0.0.0"},"peerDependencies":{"jest":">=28"},"_npmOperationalInternal":{"tmp":"tmp/jest_0.1.1_1776477725323_0.7147087305211419","host":"s3://npm-registry-packages-npm-production"}},"0.1.2":{"name":"@accesslint/jest","version":"0.1.2","keywords":["jest","accessibility","a11y","wcag","aria","accesslint","matcher","testing","jest-axe-alternative","react-testing-library","testing-library","jsdom"],"license":"MIT","_id":"@accesslint/jest@0.1.2","maintainers":[{"name":"ckundo","email":"cameron@accesslint.com"}],"homepage":"https://github.com/AccessLint/accesslint#readme","bugs":{"url":"https://github.com/AccessLint/accesslint/issues"},"dist":{"shasum":"51da07ee79b3ebdec4748f300fa493bb1863513d","tarball":"https://registry.npmjs.org/@accesslint/jest/-/jest-0.1.2.tgz","fileCount":7,"integrity":"sha512-kbj9gswMKVKtkahGC1xOuposBhYAnJLCE/dsxyDXRQPoONqCwP9OtKbdxuIpx7adIea41AZj3zD4szTy+DA/Ig==","signatures":[{"sig":"MEUCIQCzyX8clxiANVCHtXj4FfiHTQP/vvRqDSMxpgzheUm9VAIgW+QfwOtZJueoIQXvsnD287LI9UDBNRtN8id8Ljv/pZM=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@accesslint%2fjest@0.1.2","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":41059},"main":"dist/index.cjs","type":"module","types":"dist/index.d.ts","module":"dist/index.js","exports":{".":{"import":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"require":{"types":"./dist/index.d.cts","default":"./dist/index.cjs"}}},"gitHead":"f07c9244e90e6c58f630ff08d2eebda3fe9a32a2","scripts":{"test":"jest","build":"tsdown","typecheck":"tsc --noEmit","prepublishOnly":"bun run build"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:b98d679a-2d5d-4f3f-84fa-901d3c6cbc3e"}},"repository":{"url":"git+https://github.com/AccessLint/accesslint.git","type":"git","directory":"jest"},"_npmVersion":"11.11.0","description":"Accessibility assertions for Jest — toBeAccessible() matcher powered by AccessLint","directories":{},"_nodeVersion":"24.14.1","dependencies":{"@accesslint/core":"0.9.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"jest":"^29.7.0","expect":"^29.7.0","tsdown":"^0.21.9","ts-jest":"^29.2.5","typescript":"^5.7.0","@types/jest":"^29.5.14","@jest/globals":"^29.7.0","jest-environment-jsdom":"^29.7.0","@accesslint/matchers-internal":"0.0.0"},"peerDependencies":{"jest":">=28"},"_npmOperationalInternal":{"tmp":"tmp/jest_0.1.2_1776478141831_0.5424830558847307","host":"s3://npm-registry-packages-npm-production"}},"0.1.3":{"name":"@accesslint/jest","version":"0.1.3","description":"Accessibility assertions for Jest — toBeAccessible() matcher powered by AccessLint","license":"MIT","publishConfig":{"access":"public"},"repository":{"type":"git","url":"git+https://github.com/AccessLint/accesslint.git","directory":"jest"},"bugs":{"url":"https://github.com/AccessLint/accesslint/issues"},"type":"module","exports":{".":{"import":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"require":{"types":"./dist/index.d.cts","default":"./dist/index.cjs"}}},"main":"dist/index.cjs","module":"dist/index.js","types":"dist/index.d.ts","scripts":{"build":"tsdown","test":"jest","typecheck":"tsc --noEmit","prepublishOnly":"bun run build"},"dependencies":{"@accesslint/core":"0.16.0"},"devDependencies":{"@accesslint/matchers-internal":"0.1.0","@jest/globals":"^29.7.0","@types/jest":"^29.5.14","expect":"^29.7.0","jest":"^29.7.0","jest-environment-jsdom":"^29.7.0","ts-jest":"^29.2.5","tsdown":"^0.21.9","typescript":"^5.7.0"},"peerDependencies":{"jest":">=28"},"keywords":["jest","accessibility","a11y","wcag","aria","accesslint","matcher","testing","jest-axe-alternative","react-testing-library","testing-library","jsdom"],"gitHead":"d8b6c8d4ca0140344b9e3d71e296b850dc9ff2a5","_id":"@accesslint/jest@0.1.3","homepage":"https://github.com/AccessLint/accesslint#readme","_nodeVersion":"24.18.0","_npmVersion":"11.16.0","dist":{"integrity":"sha512-wFW/8HMkpwnzzGWhmv+mC7yEm4PoA77/v1ye7C3izUmDzmXc7A5JcHnQtWngv6XcKdx9YAUd9nlaEO6s/MF16g==","shasum":"bc6f54eb25c87e5628dde4ace4d22c0f26231b93","tarball":"https://registry.npmjs.org/@accesslint/jest/-/jest-0.1.3.tgz","fileCount":7,"unpackedSize":83295,"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@accesslint%2fjest@0.1.3","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQDrEwmQUDBHdabU+SwGjFoB0Nd3AusTnevCY9GjSVzVBwIhAJ6pl9LLPAoUGhUTdwOG1eBcG4Iif5TwGktfLCmqpuJ2"}]},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:b98d679a-2d5d-4f3f-84fa-901d3c6cbc3e"}},"directories":{},"maintainers":[{"name":"ckundo","email":"cameron@accesslint.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/jest_0.1.3_1785108915031_0.05716606582918082"},"_hasShrinkwrap":false}},"time":{"created":"2026-04-18T01:58:41.242Z","modified":"2026-07-26T23:35:15.466Z","0.1.0":"2026-04-18T01:58:41.457Z","0.1.1":"2026-04-18T02:02:05.552Z","0.1.2":"2026-04-18T02:09:02.271Z","0.1.3":"2026-07-26T23:35:15.161Z"},"bugs":{"url":"https://github.com/AccessLint/accesslint/issues"},"license":"MIT","homepage":"https://github.com/AccessLint/accesslint#readme","keywords":["jest","accessibility","a11y","wcag","aria","accesslint","matcher","testing","jest-axe-alternative","react-testing-library","testing-library","jsdom"],"repository":{"type":"git","url":"git+https://github.com/AccessLint/accesslint.git","directory":"jest"},"description":"Accessibility assertions for Jest — toBeAccessible() matcher powered by AccessLint","maintainers":[{"name":"ckundo","email":"cameron@accesslint.com"}],"readme":"# @accesslint/jest\n\n[![npm version](https://img.shields.io/npm/v/@accesslint/jest)](https://www.npmjs.com/package/@accesslint/jest)\n[![license](https://img.shields.io/npm/l/@accesslint/jest)](https://github.com/AccessLint/accesslint/blob/main/jest/LICENSE)\n\nAccessibility assertions for Jest. Adds a synchronous `toBeAccessible()` matcher powered by [AccessLint](https://www.accesslint.com?ref=readme_jest) that checks for WCAG 2.2 Level A and AA violations and runs under jsdom and happy-dom.\n\n## Installation\n\n```sh\nnpm install --save-dev @accesslint/jest\n```\n\n`jest` >= 28 is required as a peer dependency.\n\n## Setup\n\nRegister the matcher with Jest via `setupFilesAfterEnv` in your config:\n\n```js\n// jest.config.js\nmodule.exports = {\n  testEnvironment: \"jsdom\",\n  setupFilesAfterEnv: [\"@accesslint/jest\"],\n};\n```\n\nOr import it once in an existing setup file:\n\n```js\n// jest.setup.js\nimport \"@accesslint/jest\";\n```\n\nThat single import auto-registers `toBeAccessible()` on both the modern `expect` from `@jest/globals` and the legacy global `expect` used with `@types/jest`.\n\n## Usage\n\nPass any DOM `Element` to `expect()` and call `toBeAccessible()`:\n\n```ts\nconst container = document.createElement(\"div\");\ncontainer.innerHTML = '<img src=\"photo.jpg\" alt=\"A photo\">';\n\nexpect(container).toBeAccessible();\n```\n\nViolations are scoped to descendants of the element you pass, so you can test components in isolation. When the element is not the document root, page-level rules (`html-has-lang`, `document-title`, landmarks, etc.) are skipped automatically — override with `componentMode: false` if you want them back.\n\n## Framework recipes\n\nWorks with any DOM produced in a jsdom environment.\n\n### React — `@testing-library/react`\n\n```tsx\nimport { render } from \"@testing-library/react\";\nimport { LoginForm } from \"./LoginForm\";\n\ntest(\"LoginForm is accessible\", () => {\n  const { container } = render(<LoginForm />);\n  expect(container).toBeAccessible();\n});\n```\n\n### Vue — `@testing-library/vue`\n\n```ts\nimport { render } from \"@testing-library/vue\";\nimport LoginForm from \"./LoginForm.vue\";\n\ntest(\"LoginForm is accessible\", () => {\n  const { container } = render(LoginForm);\n  expect(container).toBeAccessible();\n});\n```\n\n### Svelte — `@testing-library/svelte`\n\n```ts\nimport { render } from \"@testing-library/svelte\";\nimport LoginForm from \"./LoginForm.svelte\";\n\ntest(\"LoginForm is accessible\", () => {\n  const { container } = render(LoginForm);\n  expect(container).toBeAccessible();\n});\n```\n\n### Angular — `@testing-library/angular`\n\n```ts\nimport { render } from \"@testing-library/angular\";\nimport { LoginFormComponent } from \"./login-form.component\";\n\ntest(\"LoginForm is accessible\", async () => {\n  const { container } = await render(LoginFormComponent);\n  expect(container).toBeAccessible();\n});\n```\n\nThe matcher accepts anything that's an `Element` — `container`, `screen.getByRole('form')`, a plain `document.createElement(...)`, or `document.body` for a full-page audit.\n\n## Options\n\n```ts\nexpect(container).toBeAccessible({\n  /** Rule IDs to disable for this assertion. */\n  disabledRules: [\"distinguishable/color-contrast\"],\n\n  /** Additional rules to run on top of the built-in set. */\n  additionalRules: [myCompiledDeclarativeRule],\n\n  /** Include AAA-level rules (excluded by default). */\n  includeAAA: true,\n\n  /** Skip page-level rules — defaults to true for non-root elements. */\n  componentMode: true,\n\n  /** Translated rule messages and guidance (e.g. \"en\", \"es\"). */\n  locale: \"es\",\n\n  /** Minimum impact that causes failure. \"minor\" (default) fails on anything. */\n  failOn: \"serious\",\n\n  /** Compare against a baseline instead of asserting zero violations. */\n  snapshot: \"login-form\",\n\n  /** Where to store snapshot files. Defaults to {cwd}/accessibility-snapshots/. */\n  snapshotDir: \"./test/a11y-snapshots\",\n});\n```\n\n### Failure messages\n\nFailures include impact, WCAG criterion, level, selector, optional context, suggested fix, and remediation guidance:\n\n```\nExpected element to have no accessibility violations, but found 2:\n\n  [critical] text-alternatives/img-alt (WCAG 1.1.1, A) — Images must have alternate text\n    selector: img\n    fix: add-attribute alt=\"\"\n    guidance: Decorative images should have alt=\"\"; informative images should describe content.\n\n  [serious] distinguishable/color-contrast (WCAG 1.4.3, AA) — Text must have sufficient color contrast\n    selector: p.subtitle\n```\n\n## Snapshot baselines\n\nLock in the current accessibility state of a component and fail only on **new** violations. Useful when adopting AccessLint in a legacy codebase.\n\n```ts\nexpect(container).toBeAccessible({ snapshot: \"login-form\" });\n```\n\n- **First run** creates `accessibility-snapshots/login-form.json` and passes.\n- **Subsequent runs** fail if any new violation appears beyond the baseline.\n- **Ratchet-down** — when only fixed violations are detected (none added), the baseline updates automatically.\n- **Force refresh** the baseline with `ACCESSLINT_UPDATE=1`.\n\nViolation identity starts at `ruleId + selector` and falls back through a tiered multi-signal matcher powered by [`@accesslint/heal-diff`](../heal-diff):\n\n1. Exact selector match (fast path).\n2. Anchor attribute (`data-testid`, `id`, `name`, `href`, `for`, `aria-label`).\n3. Computed ARIA role + accessible name.\n4. HTML fingerprint (normalized outerHTML hash).\n5. Relative location (nearest landmark trail), uniqueness-gated.\n\nWhen a non-exact tier matches the baseline's selector auto-heals to the current one, the snapshot is rewritten, and a `\"healed\"` event is logged to `.history.ndjson`. The test still passes. When no tier matches but weaker signals overlap, the failure message attaches a `likely moved from:` hint so you can tell \"same issue, different selector\" from \"genuinely new issue\" at a glance.\n\n### Trend reports\n\nEvery create / ratchet-down / force-update event appends a record to `accessibility-snapshots/.history.ndjson` alongside the baseline JSON files. Generate a trend report from that history with [`@accesslint/report`](../report):\n\n```sh\nnpx @accesslint/report --format md > a11y-report.md\nnpx @accesslint/report --format html --out a11y-report.html\n```\n\nThe report shows a stacked chart of total violations per snapshot over time, plus a per-rule movement table that joins in WCAG metadata from `@accesslint/core`. The sidecar file is append-only and safe to commit; merge conflicts on it resolve trivially by concatenating both sides.\n\n## Migrating from `jest-axe`\n\n```diff\n- import { toHaveNoViolations, axe } from \"jest-axe\";\n- expect.extend(toHaveNoViolations);\n+ import \"@accesslint/jest\";\n\n  test(\"form is accessible\", async () => {\n    const { container } = render(<Form />);\n-   const results = await axe(container);\n-   expect(results).toHaveNoViolations();\n+   expect(container).toBeAccessible();\n  });\n```\n\n### What's different\n\nAccessLint and `jest-axe` are independent implementations of WCAG rule-checking; they make different tradeoffs. Some practical differences when running under Jest with jsdom:\n\n- **Synchronous API** — `toBeAccessible()` returns immediately; no `await` per assertion.\n- **Color contrast in virtual DOMs** — AccessLint computes color contrast from the style cascade directly, so contrast violations are detected under jsdom and happy-dom without additional configuration.\n- **Independent rule engine** — rules in AccessLint are implemented from the WCAG criteria and validated against the [W3C ACT-R fixture corpus](https://act-rules.github.io/); there is no intermediate dependency on `axe-core`.\n- **Built-in `failOn` impact threshold** and snapshot baselines with auto-ratchet, which have no direct equivalent in `jest-axe`.\n\nSee the [feature parity table](#feature-parity) below for a per-feature mapping.\n\n### Feature parity\n\n| `jest-axe`                                            | `@accesslint/jest`                                              |\n| ----------------------------------------------------- | --------------------------------------------------------------- |\n| `expect.extend(toHaveNoViolations)`                   | `import \"@accesslint/jest\"` (auto-register)                     |\n| `await axe(container)` + `toHaveNoViolations()`       | `expect(container).toBeAccessible()`                            |\n| `configureAxe({ rules: { id: { enabled: false } } })` | `toBeAccessible({ disabledRules: [id] })` — per-call, no global |\n| Custom rules via axe's `checks`/`rules` config        | `toBeAccessible({ additionalRules: [...] })`                    |\n| Filter `results.violations` manually by impact        | `failOn: \"serious\"` (built-in)                                  |\n| (no built-in baseline)                                | `snapshot: \"name\"` baselines with auto-ratchet                  |\n\nThere is no global `configureAxe` equivalent — all options are per-call. If you always want the same set of disabled rules, wrap the matcher in a project helper.\n\n<details>\n<summary>Rule ID mapping (10 most common)</summary>\n\n`disabledRules` lists migrate from axe IDs to AccessLint's namespaced IDs.\n\n| axe-core ID (jest-axe) | AccessLint ID                    | WCAG  |\n| ---------------------- | -------------------------------- | ----- |\n| `image-alt`            | `text-alternatives/img-alt`      | 1.1.1 |\n| `color-contrast`       | `distinguishable/color-contrast` | 1.4.3 |\n| `label`                | `labels-and-names/form-label`    | 4.1.2 |\n| `button-name`          | `labels-and-names/button-name`   | 4.1.2 |\n| `link-name`            | `navigable/link-name`            | 2.4.4 |\n| `aria-required-attr`   | `aria/aria-required-attr`        | 4.1.2 |\n| `aria-valid-attr`      | `aria/aria-valid-attr`           | 4.1.2 |\n| `document-title`       | `navigable/document-title`       | 2.4.2 |\n| `html-has-lang`        | `readable/html-has-lang`         | 3.1.1 |\n| `list`                 | `adaptable/list-children`        | 1.3.1 |\n\nFull rule list: [@accesslint/core README](../core/README.md#rules).\n\n</details>\n\n### Violation shape\n\n`jest-axe` returns axe-core's `Result` objects (nested `nodes[]` per rule). `@accesslint/jest` reports one `Violation` per offending element with a flat shape: `ruleId`, `selector`, `html`, `impact`, `message`, `context?`, `fix?`. If you relied on axe's `helpUrl` field, use AccessLint's `rule.guidance` via `getRuleById()`.\n\n## TypeScript\n\nTypes are included. Importing the package augments both the modern `expect.Matchers` interface from `@jest/globals` and the legacy global `jest.Matchers` namespace used with `@types/jest`, so `expect(el).toBeAccessible(...)` type-checks under either setup.\n\n## What it checks\n\nWCAG 2.2 Level A and AA rules via [@accesslint/core](../core), covering images, forms, ARIA attributes, color contrast, landmarks, links, tables, document language, and more. See the [core rules table](../core/README.md#rules) for the full list.\n\n## License\n\nMIT\n","readmeFilename":"README.md"}