diff --git a/CHANGELOG.md b/CHANGELOG.md
index a72e28b..2afc605 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,8 @@
## Unreleased
+- [new] Add parameter for Axe `context` [#98](https://github.com/chanzuckerberg/axe-storybook-testing/pull/98)
+
## 8.1.0
- [new] Add `--port` option [#97](https://github.com/chanzuckerberg/axe-storybook-testing/pull/97)
diff --git a/README.md b/README.md
index e3ac6a2..f9c77ba 100644
--- a/README.md
+++ b/README.md
@@ -17,6 +17,8 @@ If there are any violations, information about them will be printed, and the com
- [disabledRules](#disabledrules)
- [mode](#mode)
- [runOptions](#runoptions)
+ - [context](#context)
+ - [config](#config)
- [skip](#skip)
- [timeout](#timeout)
- [waitForSelector](#waitforselector) (deprecated)
@@ -153,7 +155,6 @@ export const parameters = {
Allows use of any of the available [`axe.run`](https://www.deque.com/axe/core-documentation/api-documentation/#options-parameter) options. See the link for more details. When using `runOptions.rules` in combination with `disabledRules`, **`disabledRules` will always take precedent.**
```jsx
-
export const SomeStory = {
parameters: {
axe: {
@@ -167,6 +168,22 @@ export const SomeStory = {
}
```
+### context
+
+[Axe context](https://www.deque.com/axe/core-documentation/api-documentation/#context-parameter), which is passed to `axe.run`. Useful for including or excluding elements from the tests.
+
+```jsx
+export const SomeStory = {
+ parameters: {
+ axe: {
+ context: {
+ exclude: '.foo',
+ },
+ }
+ }
+}
+```
+
### config
Axe configuration, which is passed to [axe.configure](https://www.deque.com/axe/core-documentation/api-documentation/#api-name-axeconfigure).
diff --git a/demo/src/advanced.stories.jsx b/demo/src/advanced.stories.jsx
index 72194ce..b9deb7f 100644
--- a/demo/src/advanced.stories.jsx
+++ b/demo/src/advanced.stories.jsx
@@ -21,3 +21,26 @@ export const branding = {
},
},
};
+
+// Test out passing context to `axe.run`.
+export const multipleParts = {
+ render: () => (
+
+
+
+
+
+
+
+
+ ),
+ parameters: {
+ axe: {
+ context: '#a',
+ },
+ },
+};
diff --git a/index.d.ts b/index.d.ts
index 940a213..22ff468 100644
--- a/index.d.ts
+++ b/index.d.ts
@@ -1,4 +1,9 @@
-import type {RunOptions, Spec} from 'axe-core';
+import type {
+ RunOptions,
+ SerialContextObject,
+ SerialFrameSelector,
+ Spec,
+} from 'axe-core';
export declare type AxeParams = {
/**
@@ -26,6 +31,11 @@ export declare type AxeParams = {
* @see https://www.deque.com/axe/core-documentation/api-documentation/#options-parameter
*/
runOptions?: RunOptions;
+ /**
+ * Context passed to `axe.run`.
+ * @see https://www.deque.com/axe/core-documentation/api-documentation/#context-parameter
+ */
+ context?: SerialFrameSelector | SerialFrameSelector[] | SerialContextObject;
/**
* Config passed to `axe.configure`.
*/
diff --git a/src/ProcessedStory.ts b/src/ProcessedStory.ts
index d844cbd..75775d9 100644
--- a/src/ProcessedStory.ts
+++ b/src/ProcessedStory.ts
@@ -1,11 +1,13 @@
import type {RunOptions, Spec} from 'axe-core';
import {z as zod} from 'zod';
+import type {Context} from './browser/AxePage';
import type {StorybookStory} from './browser/StorybookPage';
type Params = {
disabledRules: string[];
mode: 'off' | 'warn' | 'error';
runOptions?: RunOptions;
+ context?: Context;
config?: Spec;
skip: boolean;
timeout: number;
@@ -42,6 +44,9 @@ export default class ProcessedStory {
rawStory.parameters?.axe?.runOptions,
rawStory,
),
+ context: normalizeContext(rawStory.parameters?.axe?.context, rawStory) as
+ | Context
+ | undefined,
config: normalizeConfig(rawStory.parameters?.axe?.config, rawStory),
};
}
@@ -75,6 +80,14 @@ export default class ProcessedStory {
return this.parameters.runOptions;
}
+ /**
+ * Context passed to `axe.run`.
+ * @see https://www.deque.com/axe/core-documentation/api-documentation/#context-parameter
+ */
+ get context() {
+ return this.parameters.context;
+ }
+
/**
* All optional config used to configure axe-core. Passed to `axe.configure`.
* @see https://www.deque.com/axe/core-documentation/api-documentation/#api-name-axeconfigure
@@ -138,6 +151,14 @@ const runOptionsSchema = zod.optional(
}),
);
+const contextSchema = zod
+ .union([
+ zod.string(),
+ zod.array(zod.string()),
+ zod.record(zod.string(), zod.any()),
+ ])
+ .optional();
+
const configSchema = zod.object({}).passthrough().optional();
function normalizeSkip(skip: unknown, rawStory: StorybookStory) {
@@ -175,6 +196,14 @@ function normalizeRunOptions(runOptions: unknown, rawStory: StorybookStory) {
);
}
+function normalizeContext(config: unknown, rawStory: StorybookStory) {
+ return parseWithFriendlyError(
+ () => contextSchema.parse(config),
+ rawStory,
+ 'context',
+ );
+}
+
function normalizeConfig(config: unknown, rawStory: StorybookStory) {
return parseWithFriendlyError(
() => configSchema.parse(config),
diff --git a/src/Result.ts b/src/Result.ts
index 5addd57..54b4a40 100644
--- a/src/Result.ts
+++ b/src/Result.ts
@@ -29,6 +29,7 @@ export default class Result {
page,
disabledRules,
story.runOptions,
+ story.context,
story.config,
);
return new Result(axeResults.violations);
diff --git a/src/browser/AxePage.ts b/src/browser/AxePage.ts
index 5eb578f..be0398c 100644
--- a/src/browser/AxePage.ts
+++ b/src/browser/AxePage.ts
@@ -1,6 +1,18 @@
-import type {AxeResults, RuleObject, RunOptions, Spec} from 'axe-core';
+import type {
+ AxeResults,
+ SerialContextObject,
+ SerialFrameSelector,
+ RuleObject,
+ RunOptions,
+ Spec,
+} from 'axe-core';
import type {Page} from 'playwright';
+export type Context =
+ | SerialFrameSelector
+ | SerialFrameSelector[]
+ | SerialContextObject;
+
/**
* Prepare a page for running axe on it.
*/
@@ -17,20 +29,24 @@ export function analyze(
page: Page,
disabledRules: string[] = [],
runOptions: RunOptions = {},
+ context?: Context,
config?: Spec,
): Promise {
return page.evaluate(runAxe, {
options: getRunOptions(runOptions, disabledRules),
config,
+ context,
});
}
function runAxe({
- options,
config,
+ context,
+ options,
}: {
- options: RunOptions;
config?: Spec;
+ context?: Context;
+ options: RunOptions;
}): Promise {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore This function executes in a browser context.
@@ -49,7 +65,7 @@ function runAxe({
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore This function executes in a browser context.
- return window.axe.run(document, options);
+ return window.axe.run(context || document, options);
});
}
diff --git a/tests/integration/__snapshots__/integration.test.ts.snap b/tests/integration/__snapshots__/integration.test.ts.snap
index 540cab6..5ffa9d7 100644
--- a/tests/integration/__snapshots__/integration.test.ts.snap
+++ b/tests/integration/__snapshots__/integration.test.ts.snap
@@ -10,23 +10,24 @@ Serving up 🍕 static storybook build at: http://127.0.0.1:8111
[chromium] accessibility
advanced
1) Branding
+ 2) Multiple Parts
autoTitles
✔ No Failures
delays
✔ Short Delay And Pass
- 2) Short Delay And Fail
+ 3) Short Delay And Fail
✔ Medium Delay And Pass
- 3) Medium Delay And Fail
- 4) Medium Delay And Short Timeout Fail
- 5) Long Delay And Timeout
+ 4) Medium Delay And Fail
+ 5) Medium Delay And Short Timeout Fail
+ 6) Long Delay And Timeout
simple
✔ No Failures
- 6) Failure No Discernible Text
- 7) Failure Color Contrast
- 8) Failure No Discernible Text And Invalid Role
+ 7) Failure No Discernible Text
+ 8) Failure Color Contrast
+ 9) Failure No Discernible Text And Invalid Role
- Failure Color Contrast Skipped
- No Failures Warn
- Failure Color Contrast Warn
@@ -34,7 +35,7 @@ Serving up 🍕 static storybook build at: http://127.0.0.1:8111
- Failure Color Contrast Off
- Failure No Discernible Text And Invalid Role Skipped
✔ Failure Color Contrast Disabled Rule
- 9) Failure No Discernible Text And Invalid Role Disabled One Rule
+ 10) Failure No Discernible Text And Invalid Role Disabled One Rule
✔ Failure No Discernible Text And Invalid Role Disabled Rules
2 violations were detected in stories with "mode" set to "warn", so did not fail the test suite:
@@ -69,7 +70,7 @@ Error: simple / Failure No Discernible Text Warn / Detected the following access
6 passing
6 pending
- 9 failing
+ 10 failing
1) advanced
Branding:
@@ -86,7 +87,22 @@ Error: simple / Failure No Discernible Text Warn / Detected the following access
Element has insufficient color contrast of 1.51 (foreground color: #ff69b4, background color: #ff0000, font size: 10.0pt (13.3333px), font weight: normal). Expected contrast ratio of 4.5:1
- 2) delays
+ 2) advanced
+ Multiple Parts:
+ Detected the following accessibility violations!
+
+ 1. color-contrast (Elements must meet minimum color contrast ratio thresholds)
+
+ For more info, visit https://dequeuniversity.com/rules/axe/4.9/color-contrast?application=axeAPI.
+
+ Check these nodes:
+
+ - html:
+ summary: Fix any of the following:
+ Element has insufficient color contrast of 1.51 (foreground color: #ff69b4, background color: #ff0000, font size: 10.0pt (13.3333px), font weight: normal). Expected contrast ratio of 4.5:1
+
+
+ 3) delays
Short Delay And Fail:
Detected the following accessibility violations!
@@ -101,7 +117,7 @@ Error: simple / Failure No Discernible Text Warn / Detected the following access
Role must be one of the valid ARIA roles: wut-the-wut
- 3) delays
+ 4) delays
Medium Delay And Fail:
Detected the following accessibility violations!
@@ -116,19 +132,19 @@ Error: simple / Failure No Discernible Text Warn / Detected the following access
Role must be one of the valid ARIA roles: wut-the-wut
- 4) delays
+ 5) delays
Medium Delay And Short Timeout Fail:
Error: Timeout of 100ms exceeded. For async tests and hooks, ensure "done()" is called; if returning a Promise, ensure it resolves.
at listOnTimeout (node:internal/timers)
at processTimers (node:internal/timers)
- 5) delays
+ 6) delays
Long Delay And Timeout:
Error: Timeout of 2000ms exceeded. For async tests and hooks, ensure "done()" is called; if returning a Promise, ensure it resolves.
at listOnTimeout (node:internal/timers)
at processTimers (node:internal/timers)
- 6) simple
+ 7) simple
Failure No Discernible Text:
Detected the following accessibility violations!
@@ -147,7 +163,7 @@ Error: simple / Failure No Discernible Text Warn / Detected the following access
Element's default semantics were not overridden with role="none" or role="presentation"
- 7) simple
+ 8) simple
Failure Color Contrast:
Detected the following accessibility violations!
@@ -162,7 +178,7 @@ Error: simple / Failure No Discernible Text Warn / Detected the following access
Element has insufficient color contrast of 1.51 (foreground color: #ff69b4, background color: #ff0000, font size: 10.0pt (13.3333px), font weight: normal). Expected contrast ratio of 4.5:1
- 8) simple
+ 9) simple
Failure No Discernible Text And Invalid Role:
Detected the following accessibility violations!
@@ -191,7 +207,7 @@ Error: simple / Failure No Discernible Text Warn / Detected the following access
Element's default semantics were not overridden with role="none" or role="presentation"
- 9) simple
+ 10) simple
Failure No Discernible Text And Invalid Role Disabled One Rule:
Detected the following accessibility violations!
@@ -225,6 +241,7 @@ Serving up 🍕 static storybook build at: http://127.0.0.1:8000
[chromium] accessibility
advanced
✔ Branding
+ ✔ Multiple Parts
autoTitles
✔ No Failures
@@ -270,7 +287,7 @@ Serving up 🍕 static storybook build at: http://127.0.0.1:8000
Element has no title attribute
Element's default semantics were not overridden with role="none" or role="presentation"
- 8 passing
+ 9 passing
6 pending
7 failing
@@ -398,6 +415,7 @@ Serving up 🍕 static storybook build at: http://127.0.0.1:8000
[chromium] accessibility
advanced
- Branding
+ - Multiple Parts
autoTitles
- No Failures
@@ -456,7 +474,7 @@ Error: simple / Failure No Discernible Text Warn / Detected the following access
Element's default semantics were not overridden with role="none" or role="presentation"
3 passing
- 14 pending
+ 15 pending
4 failing
1) simple
@@ -556,23 +574,24 @@ Serving up 🍕 static storybook build at: http://127.0.0.1:8000
[chromium] accessibility
advanced
1) Branding
+ 2) Multiple Parts
autoTitles
✔ No Failures
delays
✔ Short Delay And Pass
- 2) Short Delay And Fail
+ 3) Short Delay And Fail
✔ Medium Delay And Pass
- 3) Medium Delay And Fail
- 4) Medium Delay And Short Timeout Fail
- 5) Long Delay And Timeout
+ 4) Medium Delay And Fail
+ 5) Medium Delay And Short Timeout Fail
+ 6) Long Delay And Timeout
simple
✔ No Failures
- 6) Failure No Discernible Text
- 7) Failure Color Contrast
- 8) Failure No Discernible Text And Invalid Role
+ 7) Failure No Discernible Text
+ 8) Failure Color Contrast
+ 9) Failure No Discernible Text And Invalid Role
- Failure Color Contrast Skipped
- No Failures Warn
- Failure Color Contrast Warn
@@ -580,7 +599,7 @@ Serving up 🍕 static storybook build at: http://127.0.0.1:8000
- Failure Color Contrast Off
- Failure No Discernible Text And Invalid Role Skipped
✔ Failure Color Contrast Disabled Rule
- 9) Failure No Discernible Text And Invalid Role Disabled One Rule
+ 10) Failure No Discernible Text And Invalid Role Disabled One Rule
✔ Failure No Discernible Text And Invalid Role Disabled Rules
2 violations were detected in stories with "mode" set to "warn", so did not fail the test suite:
@@ -615,7 +634,7 @@ Error: simple / Failure No Discernible Text Warn / Detected the following access
6 passing
6 pending
- 9 failing
+ 10 failing
1) advanced
Branding:
@@ -632,7 +651,22 @@ Error: simple / Failure No Discernible Text Warn / Detected the following access
Element has insufficient color contrast of 1.51 (foreground color: #ff69b4, background color: #ff0000, font size: 10.0pt (13.3333px), font weight: normal). Expected contrast ratio of 4.5:1
- 2) delays
+ 2) advanced
+ Multiple Parts:
+ Detected the following accessibility violations!
+
+ 1. color-contrast (Elements must meet minimum color contrast ratio thresholds)
+
+ For more info, visit https://dequeuniversity.com/rules/axe/4.9/color-contrast?application=axeAPI.
+
+ Check these nodes:
+
+ - html:
+ summary: Fix any of the following:
+ Element has insufficient color contrast of 1.51 (foreground color: #ff69b4, background color: #ff0000, font size: 10.0pt (13.3333px), font weight: normal). Expected contrast ratio of 4.5:1
+
+
+ 3) delays
Short Delay And Fail:
Detected the following accessibility violations!
@@ -647,7 +681,7 @@ Error: simple / Failure No Discernible Text Warn / Detected the following access
Role must be one of the valid ARIA roles: wut-the-wut
- 3) delays
+ 4) delays
Medium Delay And Fail:
Detected the following accessibility violations!
@@ -662,19 +696,19 @@ Error: simple / Failure No Discernible Text Warn / Detected the following access
Role must be one of the valid ARIA roles: wut-the-wut
- 4) delays
+ 5) delays
Medium Delay And Short Timeout Fail:
Error: Timeout of 100ms exceeded. For async tests and hooks, ensure "done()" is called; if returning a Promise, ensure it resolves.
at listOnTimeout (node:internal/timers)
at processTimers (node:internal/timers)
- 5) delays
+ 6) delays
Long Delay And Timeout:
Error: Timeout of 2000ms exceeded. For async tests and hooks, ensure "done()" is called; if returning a Promise, ensure it resolves.
at listOnTimeout (node:internal/timers)
at processTimers (node:internal/timers)
- 6) simple
+ 7) simple
Failure No Discernible Text:
Detected the following accessibility violations!
@@ -693,7 +727,7 @@ Error: simple / Failure No Discernible Text Warn / Detected the following access
Element's default semantics were not overridden with role="none" or role="presentation"
- 7) simple
+ 8) simple
Failure Color Contrast:
Detected the following accessibility violations!
@@ -708,7 +742,7 @@ Error: simple / Failure No Discernible Text Warn / Detected the following access
Element has insufficient color contrast of 1.51 (foreground color: #ff69b4, background color: #ff0000, font size: 10.0pt (13.3333px), font weight: normal). Expected contrast ratio of 4.5:1
- 8) simple
+ 9) simple
Failure No Discernible Text And Invalid Role:
Detected the following accessibility violations!
@@ -737,7 +771,7 @@ Error: simple / Failure No Discernible Text Warn / Detected the following access
Element's default semantics were not overridden with role="none" or role="presentation"
- 9) simple
+ 10) simple
Failure No Discernible Text And Invalid Role Disabled One Rule:
Detected the following accessibility violations!