@stackoverflow/stacks 1.10.1 → 1.10.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/dist/css/stacks.css +3 -1
  2. package/dist/css/stacks.min.css +1 -1
  3. package/dist/js/stacks.js +266 -110
  4. package/dist/js/stacks.min.js +1 -1
  5. package/lib/components/activity-indicator/activity-indicator.a11y.test.ts +7 -5
  6. package/lib/components/anchor/anchor.a11y.test.ts +10 -3
  7. package/lib/components/badge/badge.a11y.test.ts +160 -0
  8. package/lib/components/badge/badge.visual.test.ts +150 -0
  9. package/lib/components/banner/banner.a11y.test.ts +14 -0
  10. package/lib/components/block-link/block-link.a11y.test.ts +9 -2
  11. package/lib/components/breadcrumbs/breadcrumbs.a11y.test.ts +2 -0
  12. package/lib/components/button/button.a11y.test.ts +132 -1
  13. package/lib/components/card/card.a11y.test.ts +6 -0
  14. package/lib/components/check-control/check-control.a11y.test.ts +48 -0
  15. package/lib/components/check-control/check-control.visual.test.ts +38 -0
  16. package/lib/components/check-group/check-group.a11y.test.ts +51 -0
  17. package/lib/components/check-group/check-group.visual.test.ts +58 -0
  18. package/lib/components/checkbox_radio/checkbox_radio.a11y.test.ts +39 -0
  19. package/lib/components/checkbox_radio/checkbox_radio.visual.test.ts +35 -0
  20. package/lib/components/description/description.a11y.test.ts +34 -0
  21. package/lib/components/description/description.visual.test.ts +30 -0
  22. package/lib/components/link/link.a11y.test.ts +19 -6
  23. package/lib/components/toggle-switch/toggle-switch.a11y.test.ts +76 -0
  24. package/lib/components/toggle-switch/toggle-switch.less +2 -1
  25. package/lib/components/toggle-switch/toggle-switch.visual.test.ts +74 -0
  26. package/lib/components/uploader/uploader.ts +1 -0
  27. package/lib/test/axe-apca/README.md +34 -0
  28. package/lib/test/axe-apca/index.ts +3 -0
  29. package/lib/test/axe-apca/package.wip.json +30 -0
  30. package/lib/test/axe-apca/src/apca-w3.d.ts +3 -0
  31. package/lib/test/axe-apca/src/axe-apca.test.ts +155 -0
  32. package/lib/test/axe-apca/src/axe-apca.ts +212 -0
  33. package/lib/test/test-utils.ts +18 -1
  34. package/lib/tsconfig.json +1 -0
  35. package/package.json +18 -17
@@ -0,0 +1,58 @@
1
+ import { defaultOptions, runComponentTests } from "../../test/test-utils";
2
+ import "../../index";
3
+
4
+ type CheckGroup = "checkbox" | "radio";
5
+ const checkTypes: CheckGroup[] = ["checkbox", "radio"];
6
+
7
+ // Account for horizontal variant
8
+ [true, false].forEach((isHorizontal) => {
9
+ checkTypes.forEach((type) => {
10
+ describe("s-check-group", () => {
11
+ const checkEls: {
12
+ type: CheckGroup;
13
+ id: string;
14
+ state?: "checked" | "unchecked" | "indeterminate";
15
+ }[] = [
16
+ { type, id: `test-${type}1`, state: "checked" },
17
+ { type, id: `test-${type}2` },
18
+ ];
19
+ runComponentTests({
20
+ type: "visual",
21
+ tag: "fieldset",
22
+ baseClass: "s-check-group",
23
+ attributes: {
24
+ class: isHorizontal ? "hs1 ws3 p8" : "hs2 ws2 p8",
25
+ },
26
+ variants: isHorizontal ? ["horizontal"] : [],
27
+ children: {
28
+ default: `
29
+ <legend class="s-label">${type} group</legend>
30
+ ${checkEls
31
+ .map(
32
+ ({ type, state, id }, index) => `
33
+ <div class="s-check-control">
34
+ <input
35
+ class="s-${type}"
36
+ type="${type}"
37
+ id="${id}-${index}"
38
+ name=""
39
+ ${state === "checked" ? "checked" : ""}/>
40
+ <label class="s-label" for="${id}-${index}">
41
+ ${type} label ${index}
42
+ <p class="s-input-message">Description</p>
43
+ </label>
44
+ </div>
45
+ `
46
+ )
47
+ .join("")}
48
+ `,
49
+ },
50
+ options: {
51
+ ...defaultOptions,
52
+ includeNullVariant: !isHorizontal,
53
+ testidSuffix: type,
54
+ },
55
+ });
56
+ });
57
+ });
58
+ });
@@ -0,0 +1,39 @@
1
+ import { html } from "@open-wc/testing";
2
+ import { defaultOptions, runComponentTests } from "../../test/test-utils";
3
+ import "../../index";
4
+
5
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
6
+ const checkboxTemplate = ({ component, testid, id }: any) =>
7
+ html` <div class="s-check-control" data-testid="${testid}">
8
+ ${component}
9
+ <label class="s-label" for="${id}">Label</label>
10
+ </div>`;
11
+
12
+ ["checkbox", "radio"].forEach((type) => {
13
+ describe(type, () => {
14
+ // TODO include indeterminate
15
+ ["checked", "unchecked"].forEach((state) => {
16
+ runComponentTests({
17
+ type: "a11y",
18
+ tag: "input",
19
+ baseClass: `s-${type}`,
20
+ attributes: {
21
+ name: "test-name",
22
+ id: "test-id",
23
+ type,
24
+ ...(state === "checked" ? { checked: "checked" } : {}),
25
+ },
26
+ template: ({ component, testid }) =>
27
+ checkboxTemplate({
28
+ component,
29
+ testid,
30
+ id: "test-id",
31
+ }),
32
+ options: {
33
+ ...defaultOptions,
34
+ testidSuffix: state,
35
+ },
36
+ });
37
+ });
38
+ });
39
+ });
@@ -0,0 +1,35 @@
1
+ import { html } from "@open-wc/testing";
2
+ import { defaultOptions, runComponentTests } from "../../test/test-utils";
3
+ import "../../index";
4
+
5
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
6
+ const checkboxTemplate = ({ component, testid }: any) =>
7
+ html`<div
8
+ class="d-inline-flex ai-center jc-center bg-black-100 hs1 ws1 p8"
9
+ data-testid="${testid}"
10
+ >
11
+ ${component}
12
+ </div>`;
13
+
14
+ ["checkbox", "radio"].forEach((type) => {
15
+ describe(type, () => {
16
+ // TODO include indeterminate
17
+ ["checked", "unchecked"].forEach((state) => {
18
+ runComponentTests({
19
+ type: "visual",
20
+ tag: "input",
21
+ baseClass: `s-${type}`,
22
+ attributes: {
23
+ type,
24
+ ...(state === "checked" ? { checked: "checked" } : {}),
25
+ },
26
+ template: ({ component, testid }) =>
27
+ checkboxTemplate({ component, testid }),
28
+ options: {
29
+ ...defaultOptions,
30
+ testidSuffix: state,
31
+ },
32
+ });
33
+ });
34
+ });
35
+ });
@@ -0,0 +1,34 @@
1
+ import { html } from "@open-wc/testing";
2
+ import { defaultOptions, runComponentTests } from "../../test/test-utils";
3
+ import "../../index";
4
+
5
+ // account for parent with `.is-disabled` class
6
+ [true, false].forEach((isDisabled) => {
7
+ describe("description", () => {
8
+ runComponentTests({
9
+ type: "a11y",
10
+ tag: "p",
11
+ baseClass: "s-description",
12
+ children: {
13
+ default: `Describes the site in the product, emails, integrations, and logs.`,
14
+ },
15
+ options: {
16
+ ...defaultOptions,
17
+ testidSuffix: isDisabled ? "is-disabled" : "",
18
+ },
19
+ template: ({ component, testid }) => html`
20
+ <div
21
+ class="${isDisabled ? "is-disabled" : ""}"
22
+ data-testid="${testid}"
23
+ >
24
+ ${component}
25
+ </div>
26
+ `,
27
+ // TODO: Most of those skipped tests should be fixed by the new Stacks 2.0 palette
28
+ skippedTestids: [
29
+ /^.*-is-disabled$/, // TODO: should these the disabled tests be excluded all together instead of skipped?
30
+ "s-description-dark",
31
+ ],
32
+ });
33
+ });
34
+ });
@@ -0,0 +1,30 @@
1
+ import { html } from "@open-wc/testing";
2
+ import { defaultOptions, runComponentTests } from "../../test/test-utils";
3
+ import "../../index";
4
+
5
+ // account for parent with `.is-disabled` class
6
+ [true, false].forEach((isDisabled) => {
7
+ describe("description", () => {
8
+ runComponentTests({
9
+ type: "visual",
10
+ tag: "p",
11
+ baseClass: "s-description",
12
+ children: {
13
+ default: `Describes the site in the product, emails, integrations, and logs.`,
14
+ },
15
+ options: {
16
+ ...defaultOptions,
17
+ testidSuffix: isDisabled ? "is-disabled" : "",
18
+ },
19
+ template: ({ component, testid }) => html`
20
+ <div
21
+ class="bg-black-100 d-inline-flex ai-center jc-center hs1 ws2 p8
22
+ ${isDisabled ? "is-disabled" : ""}"
23
+ data-testid="${testid}"
24
+ >
25
+ ${component}
26
+ </div>
27
+ `,
28
+ });
29
+ });
30
+ });
@@ -24,13 +24,26 @@ describe("link", () => {
24
24
  attributes: {
25
25
  href: "#",
26
26
  },
27
+ // TODO: Most of those skipped tests should be fixed by the new Stacks 2.0 palette
27
28
  skippedTestids: [
28
- "s-link-dark", // TODO fix contrast issue
29
- "s-link-dark-dropdown", // TODO fix contrast issue
30
- "s-link-dark-danger", // TODO fix contrast issue
31
- "s-link-dark-danger-dropdown", // TODO fix contrast issue
32
- "s-link-dark-underlined", // TODO fix contrast issue
33
- "s-link-dark-underlined-dropdown", // TODO fix contrast issue
29
+ "s-link-dark",
30
+ "s-link-dark-dropdown",
31
+ "s-link-dark-danger",
32
+ "s-link-dark-danger-dropdown",
33
+ "s-link-dark-underlined",
34
+ "s-link-dark-underlined-dropdown",
35
+ "s-link-dark-muted",
36
+ "s-link-dark-muted-dropdown",
37
+ "s-link-dark-visited",
38
+ "s-link-dark-visited-dropdown",
39
+ "s-link-light",
40
+ "s-link-light-danger",
41
+ "s-link-light-danger-dropdown",
42
+ "s-link-light-dropdown",
43
+ "s-link-light-muted",
44
+ "s-link-light-muted-dropdown",
45
+ "s-link-light-underlined",
46
+ "s-link-light-underlined-dropdown",
34
47
  ],
35
48
  });
36
49
  });
@@ -0,0 +1,76 @@
1
+ import { html } from "@open-wc/testing";
2
+ import { defaultOptions, runComponentTests } from "../../test/test-utils";
3
+ import "../../index";
4
+
5
+ describe("toggle-switch", () => {
6
+ // Single toggle switch
7
+ [true, false].forEach((checked) => {
8
+ [true, false].forEach((disabled) => {
9
+ const idSuffix = `${checked ? "-checked" : ""}${
10
+ disabled ? "-disabled" : ""
11
+ }`;
12
+ const id = `toggle-switch${idSuffix}`;
13
+
14
+ runComponentTests({
15
+ type: "a11y",
16
+ baseClass: "s-toggle-switch",
17
+ modifiers: {
18
+ global: idSuffix ? [idSuffix.substring(1)] : [], // for proper testid generation
19
+ },
20
+ tag: "input",
21
+ attributes: {
22
+ id,
23
+ type: "checkbox",
24
+ ...(checked ? { checked: "" } : {}),
25
+ ...(disabled ? { disabled: "" } : {}),
26
+ },
27
+ template: ({ component, testid }) => html`
28
+ <div data-testid="${testid}">
29
+ <label for="${id}">toggle</label>
30
+ ${component}
31
+ </div>
32
+ `,
33
+ });
34
+ });
35
+ });
36
+
37
+ // Multiple toggle switch variant
38
+ [true, false].forEach((offChecked) => {
39
+ runComponentTests({
40
+ type: "a11y",
41
+ baseClass: "s-toggle-switch",
42
+ variants: ["multiple"],
43
+ modifiers: {
44
+ global: offChecked ? ["off"] : [], // for proper testid generation
45
+ },
46
+ children: {
47
+ default: `
48
+ <input type="radio" name="group" id="four" ${
49
+ offChecked ? 'checked=""' : ""
50
+ }>
51
+ <label for="four" class="s-toggle-switch--label-off">Off</label>
52
+ <input type="radio" name="group" id="one" ${
53
+ !offChecked ? 'checked=""' : ""
54
+ }>
55
+ <label for="one">one</label>
56
+ <input type="radio" name="group" id="two">
57
+ <label for="two">two</label>
58
+ `,
59
+ },
60
+ options: {
61
+ ...defaultOptions,
62
+ includeNullVariant: false,
63
+ },
64
+ template: ({ component, testid }) => html`
65
+ <div data-testid="${testid}">${component}</div>
66
+ `,
67
+ // TODO: Most of those skipped tests should be fixed by the new Stacks 2.0 palette
68
+ skippedTestids: [
69
+ "s-toggle-switch-dark-multiple",
70
+ "s-toggle-switch-light-multiple",
71
+ "s-toggle-switch-dark-multiple-off",
72
+ "s-toggle-switch-light-multiple-off",
73
+ ],
74
+ });
75
+ });
76
+ });
@@ -5,7 +5,8 @@
5
5
  --_ts-multiple-bg: unset;
6
6
  --_ts-multiple-fc: var(--black-500);
7
7
 
8
- fieldset[disabled] & {
8
+ fieldset[disabled] &,
9
+ &[disabled] {
9
10
  &,
10
11
  & label {
11
12
  cursor: not-allowed;
@@ -0,0 +1,74 @@
1
+ import { html } from "@open-wc/testing";
2
+ import { defaultOptions, runComponentTests } from "../../test/test-utils";
3
+ import "../../index";
4
+
5
+ describe("toggle-switch", () => {
6
+ // Single toggle switch
7
+ [true, false].forEach((checked) => {
8
+ [true, false].forEach((disabled) => {
9
+ const testidSuffix = `${checked ? "checked" : "unchecked"}${
10
+ disabled ? "-disabled" : "-enabled"
11
+ }`;
12
+ const id = `toggle-switch-${testidSuffix}`;
13
+
14
+ runComponentTests({
15
+ type: "visual",
16
+ baseClass: "s-toggle-switch",
17
+ tag: "input",
18
+ attributes: {
19
+ id,
20
+ type: "checkbox",
21
+ ...(checked ? { checked: "" } : {}),
22
+ ...(disabled ? { disabled: "" } : {}),
23
+ },
24
+ options: {
25
+ ...defaultOptions,
26
+ includeNullModifier: false,
27
+ testidSuffix,
28
+ },
29
+ template: ({ component, testid }) => html`
30
+ <div data-testid="${testid}" class="p4 ws1">
31
+ <label class="v-visible-sr" for="${id}">toggle</label>
32
+ ${component}
33
+ </div>
34
+ `,
35
+ });
36
+ });
37
+ });
38
+
39
+ // Multiple toggle switch variant
40
+ [true, false].forEach((offChecked) => {
41
+ runComponentTests({
42
+ type: "visual",
43
+ baseClass: "s-toggle-switch",
44
+ variants: ["multiple"],
45
+ children: {
46
+ default: `
47
+ <input type="radio" name="group" id="off" ${
48
+ offChecked ? 'checked=""' : ""
49
+ }>
50
+ <label for="off" class="s-toggle-switch--label-off">Off</label>
51
+ <input type="radio" name="group" id="one" ${
52
+ !offChecked ? 'checked=""' : ""
53
+ }>
54
+ <label for="one">Weekly</label>
55
+ <input type="radio" name="group" id="two">
56
+ <label for="two">Daily</label>
57
+ <input type="radio" name="group" id="three">
58
+ <label for="three">3 hrs</label>
59
+ `,
60
+ },
61
+ options: {
62
+ ...defaultOptions,
63
+ includeNullModifier: false,
64
+ includeNullVariant: false,
65
+ testidSuffix: offChecked ? "unchecked" : "checked",
66
+ },
67
+ template: ({ component, testid }) => html`
68
+ <div data-testid="${testid}" class="d-flex ai-center g8 p4 ws2">
69
+ ${component}
70
+ </div>
71
+ `,
72
+ });
73
+ });
74
+ });
@@ -136,6 +136,7 @@ export class UploaderController extends Stacks.StacksController {
136
136
 
137
137
  if (file.type.match("image/*") && file.data) {
138
138
  thumbElement = document.createElement("img");
139
+ // eslint-disable-next-line @typescript-eslint/no-base-to-string
139
140
  thumbElement.src = file.data.toString();
140
141
  thumbElement.alt = file.name;
141
142
  } else {
@@ -0,0 +1,34 @@
1
+ # axe-apca
2
+
3
+ ⚠️ *Once this package become more mature and stable it should be extracted in its own repo (e.g. StackExchange/axe-apca) and published as an npm package. This will allow to use the rule/checks in many contexts including our Core codebase.*
4
+
5
+ This package contains custom axe rules and checks for [APCA](https://readtech.org/) Bronze and Silver+ [conformance levels](https://readtech.org/ARC/tests/visual-readability-contrast/?tn=criterion).
6
+
7
+ ## Usage
8
+
9
+ ### Installation
10
+
11
+ ⚠️ *The following command doesn't work because this package is not published on npm yet.*
12
+
13
+ ```bash
14
+ npm install --save-dev axe-core axe-apca
15
+ ```
16
+
17
+ ### Setup
18
+
19
+ ```js
20
+ import axe from "axe-core";
21
+ import { registerAxeAPCA } from 'axe-apca';
22
+
23
+ registerAxeAPCA('bronze'); // or registerAxeAPCA('silver');
24
+
25
+ // consider turning off default WCAG 2.1 AA color contrast rules when using APCA
26
+ axe.configure({
27
+ rules: [{ id: "color-contrast", enabled: false }]
28
+ })
29
+
30
+ axe.run(document, (err, results) => {
31
+ if (err) throw err;
32
+ console.log(results);
33
+ });
34
+ ```
@@ -0,0 +1,3 @@
1
+ import registerAxeAPCA from "./src/axe-apca";
2
+
3
+ export default registerAxeAPCA;
@@ -0,0 +1,30 @@
1
+ {
2
+ "name": "axe-apca",
3
+ "description": "Axe rules to check against APCA bronze and silver+ conformance levels.",
4
+ "repository": {
5
+ "type": "git",
6
+ "url": "https://github.com/StackExchange/axe-apca.git"
7
+ },
8
+ "version": "0.0.0",
9
+ "main": "TODO",
10
+ "types": "TODO",
11
+ "scripts": {
12
+ "build": "TODO: transpile ts to js",
13
+ "test": "web-test-runner"
14
+ },
15
+ "license": "MIT",
16
+ "dependencies": {
17
+ "apca-w3": "^0.1.9"
18
+ },
19
+ "peerDependencies": {
20
+ "axe-core": "^4.0.0"
21
+ },
22
+ "devDependencies": {
23
+ "@open-wc/testing": "^3.2.0",
24
+ "@web/dev-server-esbuild": "^0.4.1",
25
+ "@web/dev-server-rollup": "^0.5.2",
26
+ "@web/test-runner": "^0.16.1",
27
+ "@web/test-runner-playwright": "^0.10.1",
28
+ "typescript": "^5.1.6"
29
+ }
30
+ }
@@ -0,0 +1,3 @@
1
+ declare module "apca-w3" {
2
+ export function calcAPCA(textColor: string, bgColor: string): number;
3
+ }
@@ -0,0 +1,155 @@
1
+ import { html, fixture, expect } from "@open-wc/testing";
2
+ import axe from "axe-core";
3
+ import type { AxeResults } from "axe-core";
4
+ import registerAxeAPCA from "./axe-apca";
5
+
6
+ const runAxe = async (el: HTMLElement): Promise<AxeResults> => {
7
+ return new Promise((resolve, reject) => {
8
+ axe.run(el, (err, results) => {
9
+ if (err) reject(err);
10
+ resolve(results);
11
+ });
12
+ });
13
+ };
14
+
15
+ describe("axe-apca", () => {
16
+ describe("bronze conformance level", () => {
17
+ beforeEach(() => {
18
+ registerAxeAPCA("bronze");
19
+ });
20
+
21
+ it("should check for APCA accessibility contrast violations", async () => {
22
+ const el: HTMLElement = await fixture(
23
+ html`<p
24
+ style="background: white; color: black; font-size: 12px; font-weight: 400;"
25
+ >
26
+ Some copy
27
+ </p>`
28
+ );
29
+
30
+ const results = await runAxe(el);
31
+
32
+ const apcaPasses = results.passes.filter((violation) =>
33
+ violation.id.includes("color-contrast-apca-bronze")
34
+ );
35
+
36
+ await expect(apcaPasses.length).to.equal(1);
37
+
38
+ const passNode = apcaPasses[0].nodes[0];
39
+ expect(passNode.all[0].message).to.include(
40
+ "Element has sufficient APCA bronze level lightness contrast"
41
+ );
42
+ });
43
+
44
+ it("should detect APCA accessibility contrast violations", async () => {
45
+ const el: HTMLElement = await fixture(
46
+ html`<p
47
+ style="background: white; color: lightgray; font-size: 12px; font-weight: 400;"
48
+ >
49
+ Some copy
50
+ </p>`
51
+ );
52
+
53
+ const results = await runAxe(el);
54
+
55
+ const apcaViolations = results.violations.filter((violation) =>
56
+ violation.id.includes("color-contrast-apca-bronze")
57
+ );
58
+
59
+ await expect(apcaViolations.length).to.equal(1);
60
+
61
+ const violationNode = apcaViolations[0].nodes[0];
62
+ expect(violationNode.failureSummary).to.include(
63
+ "Element has insufficient APCA bronze level contrast"
64
+ );
65
+ });
66
+
67
+ it("should check nested nodes", async () => {
68
+ const el: HTMLElement = await fixture(
69
+ html`<div style="background: black;">
70
+ <h2>Some title</h2>
71
+ <p>Some copy</p>
72
+ <button style="background: black;">Some button</button>
73
+ </div>`
74
+ );
75
+
76
+ const results = await runAxe(el);
77
+
78
+ const apcaViolations = results.violations.filter((violation) =>
79
+ violation.id.includes("color-contrast-apca-bronze")
80
+ );
81
+
82
+ await expect(apcaViolations[0].nodes.length).to.equal(3);
83
+ });
84
+ });
85
+
86
+ describe("silver conformance level", () => {
87
+ beforeEach(() => {
88
+ registerAxeAPCA("silver");
89
+ });
90
+
91
+ it("should check for APCA accessibility contrast violations", async () => {
92
+ const el: HTMLElement = await fixture(
93
+ html`<p
94
+ style="background: white; color: black; font-size: 14px; font-weight: 400;"
95
+ >
96
+ Some copy
97
+ </p>`
98
+ );
99
+
100
+ const results = await runAxe(el);
101
+
102
+ const apcaPasses = results.passes.filter((violation) =>
103
+ violation.id.includes("color-contrast-apca-silver")
104
+ );
105
+
106
+ await expect(apcaPasses.length).to.equal(1);
107
+
108
+ const passNode = apcaPasses[0].nodes[0];
109
+ expect(passNode.all[0].message).to.include(
110
+ "Element has sufficient APCA silver level lightness contrast"
111
+ );
112
+ });
113
+
114
+ it("should detect APCA accessibility contrast violations", async () => {
115
+ const el: HTMLElement = await fixture(
116
+ html`<p
117
+ style="background: white; color: black; font-size: 12px; font-weight: 400;"
118
+ >
119
+ Some copy
120
+ </p>`
121
+ );
122
+
123
+ const results = await runAxe(el);
124
+
125
+ const apcaViolations = results.violations.filter((violation) =>
126
+ violation.id.includes("color-contrast-apca-silver")
127
+ );
128
+
129
+ await expect(apcaViolations.length).to.equal(1);
130
+
131
+ const violationNode = apcaViolations[0].nodes[0];
132
+ expect(violationNode.failureSummary).to.include(
133
+ "Element has insufficient APCA silver level contrast"
134
+ );
135
+ });
136
+
137
+ it("should check nested nodes", async () => {
138
+ const el: HTMLElement = await fixture(
139
+ html`<div style="background: black;">
140
+ <h2>Some title</h2>
141
+ <p>Some copy</p>
142
+ <button style="background: black;">Some button</button>
143
+ </div>`
144
+ );
145
+
146
+ const results = await runAxe(el);
147
+
148
+ const apcaViolations = results.violations.filter((violation) =>
149
+ violation.id.includes("color-contrast-apca-silver")
150
+ );
151
+
152
+ await expect(apcaViolations[0].nodes.length).to.equal(3);
153
+ });
154
+ });
155
+ });