accented 0.0.2 → 1.0.1

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 (217) hide show
  1. package/NOTICE +14 -0
  2. package/README.md +44 -187
  3. package/dist/accented.d.ts +8 -8
  4. package/dist/accented.d.ts.map +1 -1
  5. package/dist/accented.js +37 -30
  6. package/dist/accented.js.map +1 -1
  7. package/dist/common/strings.d.ts +2 -0
  8. package/dist/common/strings.d.ts.map +1 -0
  9. package/dist/common/strings.js +2 -0
  10. package/dist/common/strings.js.map +1 -0
  11. package/dist/common/tokens.d.ts +7 -0
  12. package/dist/common/tokens.d.ts.map +1 -0
  13. package/dist/common/tokens.js +8 -0
  14. package/dist/common/tokens.js.map +1 -0
  15. package/dist/constants.d.ts +2 -1
  16. package/dist/constants.d.ts.map +1 -1
  17. package/dist/constants.js +2 -1
  18. package/dist/constants.js.map +1 -1
  19. package/dist/dom-updater.d.ts +1 -1
  20. package/dist/dom-updater.d.ts.map +1 -1
  21. package/dist/dom-updater.js +73 -31
  22. package/dist/dom-updater.js.map +1 -1
  23. package/dist/elements/accented-dialog.d.ts +18 -10
  24. package/dist/elements/accented-dialog.d.ts.map +1 -1
  25. package/dist/elements/accented-dialog.js +116 -95
  26. package/dist/elements/accented-dialog.js.map +1 -1
  27. package/dist/elements/accented-trigger.d.ts +14 -9
  28. package/dist/elements/accented-trigger.d.ts.map +1 -1
  29. package/dist/elements/accented-trigger.js +83 -24
  30. package/dist/elements/accented-trigger.js.map +1 -1
  31. package/dist/fullscreen-listener.d.ts +2 -0
  32. package/dist/fullscreen-listener.d.ts.map +1 -0
  33. package/dist/fullscreen-listener.js +17 -0
  34. package/dist/fullscreen-listener.js.map +1 -0
  35. package/dist/intersection-observer.d.ts +1 -1
  36. package/dist/intersection-observer.d.ts.map +1 -1
  37. package/dist/intersection-observer.js +12 -6
  38. package/dist/intersection-observer.js.map +1 -1
  39. package/dist/log-and-rethrow.d.ts +1 -1
  40. package/dist/log-and-rethrow.d.ts.map +1 -1
  41. package/dist/log-and-rethrow.js +2 -3
  42. package/dist/log-and-rethrow.js.map +1 -1
  43. package/dist/logger.d.ts +4 -1
  44. package/dist/logger.d.ts.map +1 -1
  45. package/dist/logger.js +6 -3
  46. package/dist/logger.js.map +1 -1
  47. package/dist/register-elements.d.ts +1 -1
  48. package/dist/register-elements.d.ts.map +1 -1
  49. package/dist/register-elements.js +6 -7
  50. package/dist/register-elements.js.map +1 -1
  51. package/dist/resize-listener.d.ts +1 -1
  52. package/dist/resize-listener.d.ts.map +1 -1
  53. package/dist/resize-listener.js +3 -4
  54. package/dist/resize-listener.js.map +1 -1
  55. package/dist/scanner.d.ts +2 -2
  56. package/dist/scanner.d.ts.map +1 -1
  57. package/dist/scanner.js +76 -43
  58. package/dist/scanner.js.map +1 -1
  59. package/dist/scroll-listeners.d.ts +1 -1
  60. package/dist/scroll-listeners.d.ts.map +1 -1
  61. package/dist/scroll-listeners.js +3 -4
  62. package/dist/scroll-listeners.js.map +1 -1
  63. package/dist/state.d.ts +3 -2
  64. package/dist/state.d.ts.map +1 -1
  65. package/dist/state.js +5 -3
  66. package/dist/state.js.map +1 -1
  67. package/dist/task-queue.d.ts +4 -4
  68. package/dist/task-queue.d.ts.map +1 -1
  69. package/dist/task-queue.js +3 -2
  70. package/dist/task-queue.js.map +1 -1
  71. package/dist/types.d.ts +140 -49
  72. package/dist/types.d.ts.map +1 -1
  73. package/dist/types.js.map +1 -1
  74. package/dist/utils/are-elements-with-issues-equal.d.ts +3 -0
  75. package/dist/utils/are-elements-with-issues-equal.d.ts.map +1 -0
  76. package/dist/utils/are-elements-with-issues-equal.js +5 -0
  77. package/dist/utils/are-elements-with-issues-equal.js.map +1 -0
  78. package/dist/utils/are-issue-sets-equal.d.ts +2 -2
  79. package/dist/utils/are-issue-sets-equal.d.ts.map +1 -1
  80. package/dist/utils/are-issue-sets-equal.js +3 -3
  81. package/dist/utils/are-issue-sets-equal.js.map +1 -1
  82. package/dist/utils/containing-blocks.d.ts +3 -0
  83. package/dist/utils/containing-blocks.d.ts.map +1 -0
  84. package/dist/utils/containing-blocks.js +46 -0
  85. package/dist/utils/containing-blocks.js.map +1 -0
  86. package/dist/utils/contains.d.ts +2 -0
  87. package/dist/utils/contains.d.ts.map +1 -0
  88. package/dist/utils/contains.js +19 -0
  89. package/dist/utils/contains.js.map +1 -0
  90. package/dist/utils/deduplicate-nodes.d.ts +2 -0
  91. package/dist/utils/deduplicate-nodes.d.ts.map +1 -0
  92. package/dist/utils/deduplicate-nodes.js +4 -0
  93. package/dist/utils/deduplicate-nodes.js.map +1 -0
  94. package/dist/utils/deep-merge.d.ts +1 -1
  95. package/dist/utils/deep-merge.d.ts.map +1 -1
  96. package/dist/utils/deep-merge.js +8 -5
  97. package/dist/utils/deep-merge.js.map +1 -1
  98. package/dist/utils/dom-helpers.d.ts +9 -0
  99. package/dist/utils/dom-helpers.d.ts.map +1 -0
  100. package/dist/utils/dom-helpers.js +34 -0
  101. package/dist/utils/dom-helpers.js.map +1 -0
  102. package/dist/utils/ensure-non-empty.d.ts +2 -0
  103. package/dist/utils/ensure-non-empty.d.ts.map +1 -0
  104. package/dist/utils/ensure-non-empty.js +7 -0
  105. package/dist/utils/ensure-non-empty.js.map +1 -0
  106. package/dist/utils/get-element-html.d.ts +1 -1
  107. package/dist/utils/get-element-html.d.ts.map +1 -1
  108. package/dist/utils/get-element-html.js +4 -2
  109. package/dist/utils/get-element-html.js.map +1 -1
  110. package/dist/utils/get-element-position.d.ts +10 -2
  111. package/dist/utils/get-element-position.d.ts.map +1 -1
  112. package/dist/utils/get-element-position.js +64 -16
  113. package/dist/utils/get-element-position.js.map +1 -1
  114. package/dist/utils/get-parent.d.ts +2 -0
  115. package/dist/utils/get-parent.d.ts.map +1 -0
  116. package/dist/utils/get-parent.js +12 -0
  117. package/dist/utils/get-parent.js.map +1 -0
  118. package/dist/utils/get-scan-context.d.ts +3 -0
  119. package/dist/utils/get-scan-context.d.ts.map +1 -0
  120. package/dist/utils/get-scan-context.js +28 -0
  121. package/dist/utils/get-scan-context.js.map +1 -0
  122. package/dist/utils/get-scrollable-ancestors.d.ts +1 -1
  123. package/dist/utils/get-scrollable-ancestors.d.ts.map +1 -1
  124. package/dist/utils/get-scrollable-ancestors.js +10 -6
  125. package/dist/utils/get-scrollable-ancestors.js.map +1 -1
  126. package/dist/utils/is-node-in-scan-context.d.ts +3 -0
  127. package/dist/utils/is-node-in-scan-context.d.ts.map +1 -0
  128. package/dist/utils/is-node-in-scan-context.js +26 -0
  129. package/dist/utils/is-node-in-scan-context.js.map +1 -0
  130. package/dist/utils/is-non-empty.d.ts +2 -0
  131. package/dist/utils/is-non-empty.d.ts.map +1 -0
  132. package/dist/utils/is-non-empty.js +4 -0
  133. package/dist/utils/is-non-empty.js.map +1 -0
  134. package/dist/utils/normalize-context.d.ts +3 -0
  135. package/dist/utils/normalize-context.d.ts.map +1 -0
  136. package/dist/utils/normalize-context.js +59 -0
  137. package/dist/utils/normalize-context.js.map +1 -0
  138. package/dist/utils/recalculate-positions.d.ts +1 -1
  139. package/dist/utils/recalculate-positions.d.ts.map +1 -1
  140. package/dist/utils/recalculate-positions.js +5 -5
  141. package/dist/utils/recalculate-positions.js.map +1 -1
  142. package/dist/utils/recalculate-scrollable-ancestors.d.ts +1 -1
  143. package/dist/utils/recalculate-scrollable-ancestors.d.ts.map +1 -1
  144. package/dist/utils/recalculate-scrollable-ancestors.js +4 -4
  145. package/dist/utils/recalculate-scrollable-ancestors.js.map +1 -1
  146. package/dist/utils/shadow-dom-aware-mutation-observer.d.ts +10 -0
  147. package/dist/utils/shadow-dom-aware-mutation-observer.d.ts.map +1 -0
  148. package/dist/utils/shadow-dom-aware-mutation-observer.js +61 -0
  149. package/dist/utils/shadow-dom-aware-mutation-observer.js.map +1 -0
  150. package/dist/utils/supports-anchor-positioning.d.ts +1 -1
  151. package/dist/utils/supports-anchor-positioning.d.ts.map +1 -1
  152. package/dist/utils/supports-anchor-positioning.js +15 -2
  153. package/dist/utils/supports-anchor-positioning.js.map +1 -1
  154. package/dist/utils/transform-violations.d.ts +2 -2
  155. package/dist/utils/transform-violations.d.ts.map +1 -1
  156. package/dist/utils/transform-violations.js +25 -10
  157. package/dist/utils/transform-violations.js.map +1 -1
  158. package/dist/utils/update-elements-with-issues.d.ts +11 -5
  159. package/dist/utils/update-elements-with-issues.d.ts.map +1 -1
  160. package/dist/utils/update-elements-with-issues.js +56 -24
  161. package/dist/utils/update-elements-with-issues.js.map +1 -1
  162. package/dist/validate-options.d.ts +2 -2
  163. package/dist/validate-options.d.ts.map +1 -1
  164. package/dist/validate-options.js +91 -4
  165. package/dist/validate-options.js.map +1 -1
  166. package/package.json +16 -8
  167. package/src/accented.test.ts +2 -2
  168. package/src/accented.ts +45 -34
  169. package/src/common/strings.ts +2 -0
  170. package/src/common/tokens.ts +10 -0
  171. package/src/constants.ts +2 -1
  172. package/src/dom-updater.ts +87 -34
  173. package/src/elements/accented-dialog.ts +163 -123
  174. package/src/elements/accented-trigger.ts +128 -50
  175. package/src/fullscreen-listener.ts +21 -0
  176. package/src/intersection-observer.ts +27 -16
  177. package/src/log-and-rethrow.ts +2 -3
  178. package/src/logger.ts +14 -4
  179. package/src/register-elements.ts +7 -7
  180. package/src/resize-listener.ts +15 -11
  181. package/src/scanner.ts +113 -57
  182. package/src/scroll-listeners.ts +27 -19
  183. package/src/state.ts +27 -16
  184. package/src/task-queue.test.ts +5 -4
  185. package/src/task-queue.ts +8 -6
  186. package/src/types.ts +179 -76
  187. package/src/utils/are-elements-with-issues-equal.ts +11 -0
  188. package/src/utils/are-issue-sets-equal.test.ts +6 -7
  189. package/src/utils/are-issue-sets-equal.ts +8 -6
  190. package/src/utils/containing-blocks.ts +60 -0
  191. package/src/utils/contains.test.ts +54 -0
  192. package/src/utils/contains.ts +19 -0
  193. package/src/utils/deduplicate-nodes.ts +3 -0
  194. package/src/utils/deep-merge.test.ts +8 -1
  195. package/src/utils/deep-merge.ts +14 -8
  196. package/src/utils/dom-helpers.ts +42 -0
  197. package/src/utils/ensure-non-empty.ts +6 -0
  198. package/src/utils/get-element-html.ts +4 -2
  199. package/src/utils/get-element-position.ts +84 -16
  200. package/src/utils/get-parent.ts +14 -0
  201. package/src/utils/get-scan-context.test.ts +85 -0
  202. package/src/utils/get-scan-context.ts +36 -0
  203. package/src/utils/get-scrollable-ancestors.ts +15 -7
  204. package/src/utils/is-node-in-scan-context.test.ts +70 -0
  205. package/src/utils/is-node-in-scan-context.ts +29 -0
  206. package/src/utils/is-non-empty.ts +3 -0
  207. package/src/utils/normalize-context.test.ts +105 -0
  208. package/src/utils/normalize-context.ts +65 -0
  209. package/src/utils/recalculate-positions.ts +5 -5
  210. package/src/utils/recalculate-scrollable-ancestors.ts +4 -4
  211. package/src/utils/shadow-dom-aware-mutation-observer.ts +75 -0
  212. package/src/utils/supports-anchor-positioning.ts +19 -3
  213. package/src/utils/transform-violations.test.ts +29 -25
  214. package/src/utils/transform-violations.ts +32 -12
  215. package/src/utils/update-elements-with-issues.test.ts +145 -53
  216. package/src/utils/update-elements-with-issues.ts +123 -54
  217. package/src/validate-options.ts +154 -14
@@ -1,7 +1,23 @@
1
1
  type WindowWithCSS = Window & {
2
- CSS: typeof CSS
2
+ CSS: typeof CSS;
3
+ };
4
+
5
+ /**
6
+ * We have to do browser sniffing now and explicitly turn off Anchor positioning in Safari
7
+ * since anchor positioning is not working correctly in Safari 26 Technology Preview.
8
+ */
9
+ function isWebKit(win: Window) {
10
+ const ua = win.navigator.userAgent;
11
+ return (/AppleWebKit/.test(ua) && !/Chrome/.test(ua)) || /\b(iPad|iPhone|iPod)\b/.test(ua);
3
12
  }
4
13
 
5
- export default function supportsAnchorPositioning(win: WindowWithCSS) {
6
- return win.CSS.supports('anchor-name: --foo') && win.CSS.supports('position-anchor: --foo');
14
+ // ATTENTION: sync with the implementation in end-to-end tests.
15
+ // I didn't find a way to sync this with automatically with the implementation of supportsAnchorPositioning
16
+ // in end-to-end tests, so it has to be synced manually.
17
+ export function supportsAnchorPositioning(win: WindowWithCSS) {
18
+ return (
19
+ win.CSS.supports('anchor-name: --foo') &&
20
+ win.CSS.supports('position-anchor: --foo') &&
21
+ !isWebKit(win)
22
+ );
7
23
  }
@@ -1,8 +1,8 @@
1
1
  import assert from 'node:assert/strict';
2
- import {suite, test} from 'node:test';
3
- import transformViolations from './transform-violations';
4
-
2
+ import { suite, test } from 'node:test';
5
3
  import type { AxeResults } from 'axe-core';
4
+ import { transformViolations } from './transform-violations';
5
+
6
6
  type Violation = AxeResults['violations'][number];
7
7
  type Node = Violation['nodes'][number];
8
8
 
@@ -12,7 +12,7 @@ const commonViolationProps1: Omit<Violation, 'nodes'> = {
12
12
  helpUrl: 'http://example.com',
13
13
  description: 'description1',
14
14
  tags: [],
15
- impact: 'serious'
15
+ impact: 'serious',
16
16
  };
17
17
 
18
18
  const commonViolationProps2: Omit<Violation, 'nodes'> = {
@@ -21,51 +21,53 @@ const commonViolationProps2: Omit<Violation, 'nodes'> = {
21
21
  helpUrl: 'http://example.com',
22
22
  description: 'description2',
23
23
  tags: [],
24
- impact: 'serious'
24
+ impact: 'serious',
25
25
  };
26
26
 
27
+ const getRootNode = (): Node => ({}) as Node;
28
+
27
29
  // @ts-expect-error element is not HTMLElement
28
- const element1: HTMLElement = {};
30
+ const element1: HTMLElement = { getRootNode };
29
31
  // @ts-expect-error element is not HTMLElement
30
- const element2: HTMLElement = {};
32
+ const element2: HTMLElement = { getRootNode };
31
33
  // @ts-expect-error element is not HTMLElement
32
- const element3: HTMLElement = {};
34
+ const element3: HTMLElement = { getRootNode };
33
35
 
34
36
  const commonNodeProps = {
35
37
  html: '<div></div>',
36
38
  any: [],
37
39
  all: [],
38
- none: []
40
+ none: [],
39
41
  };
40
42
 
41
43
  const node1: Node = {
42
44
  ...commonNodeProps,
43
45
  element: element1,
44
46
  target: ['div'],
45
- failureSummary: 'summary1'
47
+ failureSummary: 'summary1',
46
48
  };
47
49
 
48
50
  const node2: Node = {
49
51
  ...commonNodeProps,
50
52
  element: element2,
51
53
  target: ['div'],
52
- failureSummary: 'summary2'
54
+ failureSummary: 'summary2',
53
55
  };
54
56
 
55
57
  const node3: Node = {
56
58
  ...commonNodeProps,
57
59
  element: element3,
58
60
  target: ['div'],
59
- failureSummary: 'summary3'
61
+ failureSummary: 'summary3',
60
62
  };
61
63
 
62
64
  suite('transformViolations', () => {
63
65
  test('one violation, one element', () => {
64
66
  const violation: Violation = {
65
67
  ...commonViolationProps1,
66
- nodes: [node1]
68
+ nodes: [node1],
67
69
  };
68
- const elementsWithIssues = transformViolations([violation]);
70
+ const elementsWithIssues = transformViolations([violation], 'accented');
69
71
  assert.equal(elementsWithIssues.length, 1);
70
72
  assert.equal(elementsWithIssues[0]?.element, element1);
71
73
  assert.equal(elementsWithIssues[0].issues.length, 1);
@@ -76,15 +78,17 @@ suite('transformViolations', () => {
76
78
  test('two violations, two elements each', () => {
77
79
  const violation1: Violation = {
78
80
  ...commonViolationProps1,
79
- nodes: [node1, node2]
81
+ nodes: [node1, node2],
80
82
  };
81
83
  const violation2: Violation = {
82
84
  ...commonViolationProps2,
83
- nodes: [node1, node3]
85
+ nodes: [node1, node3],
84
86
  };
85
- const elementsWithIssues = transformViolations([violation1, violation2]);
87
+ const elementsWithIssues = transformViolations([violation1, violation2], 'accented');
86
88
  assert.equal(elementsWithIssues.length, 3);
87
- const elementWithTwoIssues = elementsWithIssues.find(elementWithIssues => elementWithIssues.element === element1);
89
+ const elementWithTwoIssues = elementsWithIssues.find(
90
+ (elementWithIssues) => elementWithIssues.element === element1,
91
+ );
88
92
  assert.equal(elementWithTwoIssues?.issues.length, 2);
89
93
  });
90
94
 
@@ -94,14 +98,14 @@ suite('transformViolations', () => {
94
98
  element: element1,
95
99
  // A target array whose length is > 1 signifies an element in an iframe
96
100
  target: ['iframe', 'div'],
97
- failureSummary: 'summary1'
101
+ failureSummary: 'summary1',
98
102
  };
99
103
  const violation: Violation = {
100
104
  ...commonViolationProps1,
101
- nodes: [node]
105
+ nodes: [node],
102
106
  };
103
107
 
104
- const elementsWithIssues = transformViolations([violation]);
108
+ const elementsWithIssues = transformViolations([violation], 'accented');
105
109
  assert.equal(elementsWithIssues.length, 0);
106
110
  });
107
111
 
@@ -111,14 +115,14 @@ suite('transformViolations', () => {
111
115
  element: element1,
112
116
  // A target that contains an array within the outer array signifies an element in shadow DOM
113
117
  target: [['div', 'div']],
114
- failureSummary: 'summary1'
118
+ failureSummary: 'summary1',
115
119
  };
116
120
  const violation: Violation = {
117
121
  ...commonViolationProps1,
118
- nodes: [node]
122
+ nodes: [node],
119
123
  };
120
124
 
121
- const elementsWithIssues = transformViolations([violation]);
122
- assert.equal(elementsWithIssues.length, 0);
125
+ const elementsWithIssues = transformViolations([violation], 'accented');
126
+ assert.equal(elementsWithIssues.length, 1);
123
127
  });
124
128
  });
@@ -1,12 +1,31 @@
1
1
  import type { AxeResults, ImpactValue } from 'axe-core';
2
- import type { Issue, ElementWithIssues } from '../types';
2
+ import type { ElementWithIssues, Issue } from '../types.ts';
3
+
4
+ // This is a list of axe-core violations (their ids) that may be flagged by axe-core
5
+ // as false positives if an Accented trigger is a descendant of the element with the issue.
6
+ const violationsAffectedByAccentedTriggers = [
7
+ 'aria-hidden-focus',
8
+ 'aria-text',
9
+ 'definition-list',
10
+ 'label-content-name-mismatch',
11
+ 'list',
12
+ 'nested-interactive',
13
+ 'scrollable-region-focusable', // The Accented trigger might make the content grow such that scrolling is required.
14
+ ];
15
+
16
+ function maybeCausedByAccented(violationId: string, element: HTMLElement, name: string) {
17
+ return (
18
+ violationsAffectedByAccentedTriggers.includes(violationId) &&
19
+ Boolean(element.querySelector(`${name}-trigger`))
20
+ );
21
+ }
3
22
 
4
23
  function impactCompare(a: ImpactValue, b: ImpactValue) {
5
24
  const impactOrder = [null, 'minor', 'moderate', 'serious', 'critical'];
6
25
  return impactOrder.indexOf(a) - impactOrder.indexOf(b);
7
26
  }
8
27
 
9
- export default function transformViolations(violations: typeof AxeResults.violations) {
28
+ export function transformViolations(violations: typeof AxeResults.violations, name: string) {
10
29
  const elementsWithIssues: Array<ElementWithIssues> = [];
11
30
 
12
31
  for (const violation of violations) {
@@ -21,26 +40,27 @@ export default function transformViolations(violations: typeof AxeResults.violat
21
40
  // A consumer of Accented can instead scan the iframed document by calling Accented initialization from that document.
22
41
  const isInIframe = target.length > 1;
23
42
 
24
- // Highlighting elements in shadow DOM is not yet supported, see https://github.com/pomerantsev/accented/issues/25
25
- // Until then, we don’t want such elements to be added to the set.
26
- const isInShadowDOM = Array.isArray(target[0]);
27
-
28
- if (element && !isInIframe && !isInShadowDOM) {
43
+ if (element && !isInIframe && !maybeCausedByAccented(violation.id, element, name)) {
29
44
  const issue: Issue = {
30
45
  id: violation.id,
31
46
  title: violation.help,
47
+ // See https://github.com/pomerantsev/accented/issues/203
32
48
  description: node.failureSummary ?? violation.description,
33
49
  url: violation.helpUrl,
34
- impact: violation.impact ?? null
50
+ // See https://github.com/pomerantsev/accented/issues/203
51
+ impact: violation.impact ?? null,
35
52
  };
36
- const existingElementIndex = elementsWithIssues.findIndex(elementWithIssues => elementWithIssues.element === element);
37
- if (existingElementIndex === -1) {
53
+ const existingElement = elementsWithIssues.find(
54
+ (elementWithIssues) => elementWithIssues.element === element,
55
+ );
56
+ if (existingElement === undefined) {
38
57
  elementsWithIssues.push({
39
58
  element,
40
- issues: [issue]
59
+ rootNode: element.getRootNode(),
60
+ issues: [issue],
41
61
  });
42
62
  } else {
43
- elementsWithIssues[existingElementIndex]!.issues.push(issue);
63
+ existingElement.issues.push(issue);
44
64
  }
45
65
  }
46
66
  }
@@ -1,51 +1,72 @@
1
- import {suite, test} from 'node:test';
2
1
  import assert from 'node:assert/strict';
2
+ import { suite, test } from 'node:test';
3
3
  import type { Signal } from '@preact/signals-core';
4
4
  import { signal } from '@preact/signals-core';
5
- import type { ExtendedElementWithIssues, Issue } from '../types';
6
- import updateElementsWithIssues from './update-elements-with-issues';
7
-
8
5
  import type { AxeResults, ImpactValue } from 'axe-core';
9
6
  import type { AccentedTrigger } from '../elements/accented-trigger';
7
+ import type { ExtendedElementWithIssues, Issue } from '../types';
8
+ import { updateElementsWithIssues } from './update-elements-with-issues';
9
+
10
10
  type Violation = AxeResults['violations'][number];
11
- type Node = Violation['nodes'][number];
11
+ type AxeNode = Violation['nodes'][number];
12
12
 
13
13
  const win: Window & { CSS: typeof CSS } = {
14
14
  document: {
15
15
  // @ts-expect-error the return value is of incorrect type.
16
16
  createElement: () => ({
17
17
  style: {
18
- setProperty: () => {}
18
+ setProperty: () => {},
19
19
  },
20
- dataset: {}
21
- })
20
+ dataset: {},
21
+ }),
22
+ contains: () => true,
22
23
  },
23
24
  // @ts-expect-error we're missing a lot of properties
24
25
  getComputedStyle: () => ({
25
26
  zIndex: '',
26
- direction: 'ltr'
27
+ direction: 'ltr',
28
+ getPropertyValue: () => 'none',
27
29
  }),
28
30
  // @ts-expect-error we're missing a lot of properties
29
31
  CSS: {
30
- supports: () => true
31
- }
32
- }
32
+ supports: () => true,
33
+ },
34
+ // @ts-expect-error we're missing a lot of properties
35
+ navigator: {
36
+ userAgent: '',
37
+ },
38
+ };
33
39
 
34
40
  const getBoundingClientRect = () => ({});
35
41
 
42
+ const getRootNode = (): Node => ({}) as Node;
43
+
44
+ const baseElement = {
45
+ getBoundingClientRect,
46
+ getRootNode,
47
+ style: {
48
+ getPropertyValue: () => '',
49
+ },
50
+ closest: () => null,
51
+ };
52
+
36
53
  // @ts-expect-error element is not HTMLElement
37
- const element1: HTMLElement = {getBoundingClientRect, isConnected: true};
54
+ const element1: HTMLElement = { ...baseElement, isConnected: true };
38
55
  // @ts-expect-error element is not HTMLElement
39
- const element2: HTMLElement = {getBoundingClientRect, isConnected: true};
56
+ const element2: HTMLElement = { ...baseElement, isConnected: true };
40
57
  // @ts-expect-error element is not HTMLElement
41
- const element3: HTMLElement = {getBoundingClientRect, isConnected: false};
58
+ const element3: HTMLElement = { ...baseElement, isConnected: false };
59
+
60
+ // @ts-expect-error rootNode is not Node
61
+ const rootNode: Node = {};
42
62
 
43
63
  const trigger = win.document.createElement('accented-trigger') as AccentedTrigger;
44
64
 
45
65
  const position = signal({
46
- inlineEndLeft: 0,
47
- blockStartTop: 0,
48
- direction: 'ltr' as const
66
+ left: 0,
67
+ width: 100,
68
+ top: 0,
69
+ height: 100,
49
70
  });
50
71
 
51
72
  const visible = signal(true);
@@ -57,20 +78,20 @@ const commonNodeProps = {
57
78
  any: [],
58
79
  all: [],
59
80
  none: [],
60
- target: ['div']
81
+ target: ['div'],
61
82
  };
62
83
 
63
- const node1: Node = {
84
+ const node1: AxeNode = {
64
85
  ...commonNodeProps,
65
86
  element: element1,
66
87
  };
67
88
 
68
- const node2: Node = {
89
+ const node2: AxeNode = {
69
90
  ...commonNodeProps,
70
91
  element: element2,
71
92
  };
72
93
 
73
- const node3: Node = {
94
+ const node3: AxeNode = {
74
95
  ...commonNodeProps,
75
96
  element: element3,
76
97
  };
@@ -80,53 +101,58 @@ const commonViolationProps = {
80
101
  helpUrl: 'http://example.com',
81
102
  description: 'description',
82
103
  tags: [],
83
- impact: 'serious' as ImpactValue
104
+ impact: 'serious' as ImpactValue,
84
105
  };
85
106
 
86
107
  const violation1: Violation = {
87
108
  ...commonViolationProps,
88
109
  id: 'id1',
89
- nodes: [node1]
110
+ nodes: [node1],
90
111
  };
91
112
 
92
113
  const violation2: Violation = {
93
114
  ...commonViolationProps,
94
115
  id: 'id2',
95
- nodes: [node2]
116
+ nodes: [node2],
96
117
  };
97
118
 
98
119
  const violation3: Violation = {
99
120
  ...commonViolationProps,
100
121
  id: 'id3',
101
- nodes: [node2]
122
+ nodes: [node2],
102
123
  };
103
124
 
104
125
  const violation4: Violation = {
105
126
  ...commonViolationProps,
106
127
  id: 'id4',
107
- nodes: [node3]
128
+ nodes: [node3],
108
129
  };
109
130
 
110
131
  const commonIssueProps = {
111
132
  title: 'help',
112
133
  description: 'description',
113
134
  url: 'http://example.com',
114
- impact: 'serious'
135
+ impact: 'serious',
115
136
  } as const;
116
137
 
117
138
  const issue1: Issue = {
118
139
  id: 'id1',
119
- ...commonIssueProps
140
+ ...commonIssueProps,
120
141
  };
121
142
 
122
143
  const issue2: Issue = {
123
144
  id: 'id2',
124
- ...commonIssueProps
145
+ ...commonIssueProps,
125
146
  };
126
147
 
127
148
  const issue3: Issue = {
128
149
  id: 'id3',
129
- ...commonIssueProps
150
+ ...commonIssueProps,
151
+ };
152
+
153
+ const scanContext = {
154
+ include: [win.document],
155
+ exclude: [],
130
156
  };
131
157
 
132
158
  suite('updateElementsWithIssues', () => {
@@ -135,23 +161,35 @@ suite('updateElementsWithIssues', () => {
135
161
  {
136
162
  id: 1,
137
163
  element: element1,
164
+ rootNode,
165
+ skipRender: false,
138
166
  position,
139
167
  visible,
140
168
  trigger,
169
+ anchorNameValue: 'none',
141
170
  scrollableAncestors,
142
- issues: signal([issue1])
171
+ issues: signal([issue1]),
143
172
  },
144
173
  {
145
174
  id: 2,
146
175
  element: element2,
176
+ rootNode,
177
+ skipRender: false,
147
178
  position,
148
179
  visible,
149
180
  trigger,
181
+ anchorNameValue: 'none',
150
182
  scrollableAncestors,
151
- issues: signal([issue2])
152
- }
183
+ issues: signal([issue2]),
184
+ },
153
185
  ]);
154
- updateElementsWithIssues(extendedElementsWithIssues, [violation1, violation2], win, 'accented');
186
+ updateElementsWithIssues({
187
+ extendedElementsWithIssues,
188
+ scanContext,
189
+ violations: [violation1, violation2],
190
+ win,
191
+ name: 'accented',
192
+ });
155
193
  assert.equal(extendedElementsWithIssues.value.length, 2);
156
194
  assert.equal(extendedElementsWithIssues.value[0]?.element, element1);
157
195
  assert.equal(extendedElementsWithIssues.value[0]?.issues.value.length, 1);
@@ -164,23 +202,35 @@ suite('updateElementsWithIssues', () => {
164
202
  {
165
203
  id: 1,
166
204
  element: element1,
205
+ rootNode,
206
+ skipRender: false,
167
207
  position,
168
208
  visible,
169
209
  trigger,
210
+ anchorNameValue: 'none',
170
211
  scrollableAncestors,
171
- issues: signal([issue1])
212
+ issues: signal([issue1]),
172
213
  },
173
214
  {
174
215
  id: 2,
175
216
  element: element2,
217
+ rootNode,
218
+ skipRender: false,
176
219
  position,
177
220
  visible,
178
221
  trigger,
222
+ anchorNameValue: 'none',
179
223
  scrollableAncestors,
180
- issues: signal([issue2])
181
- }
224
+ issues: signal([issue2]),
225
+ },
182
226
  ]);
183
- updateElementsWithIssues(extendedElementsWithIssues, [violation1, violation2, violation3], win, 'accented');
227
+ updateElementsWithIssues({
228
+ extendedElementsWithIssues,
229
+ scanContext,
230
+ violations: [violation1, violation2, violation3],
231
+ win,
232
+ name: 'accented',
233
+ });
184
234
  assert.equal(extendedElementsWithIssues.value.length, 2);
185
235
  assert.equal(extendedElementsWithIssues.value[0]?.element, element1);
186
236
  assert.equal(extendedElementsWithIssues.value[0]?.issues.value.length, 1);
@@ -193,23 +243,35 @@ suite('updateElementsWithIssues', () => {
193
243
  {
194
244
  id: 1,
195
245
  element: element1,
246
+ rootNode,
247
+ skipRender: false,
196
248
  position,
197
249
  visible,
198
250
  trigger,
251
+ anchorNameValue: 'none',
199
252
  scrollableAncestors,
200
- issues: signal([issue1])
253
+ issues: signal([issue1]),
201
254
  },
202
255
  {
203
256
  id: 2,
204
257
  element: element2,
258
+ rootNode,
259
+ skipRender: false,
205
260
  position,
206
261
  visible,
207
262
  trigger,
263
+ anchorNameValue: 'none',
208
264
  scrollableAncestors,
209
- issues: signal([issue2, issue3])
210
- }
265
+ issues: signal([issue2, issue3]),
266
+ },
211
267
  ]);
212
- updateElementsWithIssues(extendedElementsWithIssues, [violation1, violation2], win, 'accented');
268
+ updateElementsWithIssues({
269
+ extendedElementsWithIssues,
270
+ scanContext,
271
+ violations: [violation1, violation2],
272
+ win,
273
+ name: 'accented',
274
+ });
213
275
  assert.equal(extendedElementsWithIssues.value.length, 2);
214
276
  assert.equal(extendedElementsWithIssues.value[0]?.element, element1);
215
277
  assert.equal(extendedElementsWithIssues.value[0]?.issues.value.length, 1);
@@ -222,14 +284,23 @@ suite('updateElementsWithIssues', () => {
222
284
  {
223
285
  id: 1,
224
286
  element: element1,
287
+ rootNode,
288
+ skipRender: false,
225
289
  position,
226
290
  visible,
227
291
  trigger,
292
+ anchorNameValue: 'none',
228
293
  scrollableAncestors,
229
- issues: signal([issue1])
230
- }
294
+ issues: signal([issue1]),
295
+ },
231
296
  ]);
232
- updateElementsWithIssues(extendedElementsWithIssues, [violation1, violation2], win, 'accented');
297
+ updateElementsWithIssues({
298
+ extendedElementsWithIssues,
299
+ scanContext,
300
+ violations: [violation1, violation2],
301
+ win,
302
+ name: 'accented',
303
+ });
233
304
  assert.equal(extendedElementsWithIssues.value.length, 2);
234
305
  assert.equal(extendedElementsWithIssues.value[0]?.element, element1);
235
306
  assert.equal(extendedElementsWithIssues.value[0]?.issues.value.length, 1);
@@ -242,14 +313,23 @@ suite('updateElementsWithIssues', () => {
242
313
  {
243
314
  id: 1,
244
315
  element: element1,
316
+ rootNode,
317
+ skipRender: false,
245
318
  position,
246
319
  visible,
247
320
  trigger,
321
+ anchorNameValue: 'none',
248
322
  scrollableAncestors,
249
- issues: signal([issue1])
250
- }
323
+ issues: signal([issue1]),
324
+ },
251
325
  ]);
252
- updateElementsWithIssues(extendedElementsWithIssues, [violation1, violation4], win, 'accented');
326
+ updateElementsWithIssues({
327
+ extendedElementsWithIssues,
328
+ scanContext,
329
+ violations: [violation1, violation4],
330
+ win,
331
+ name: 'accented',
332
+ });
253
333
  assert.equal(extendedElementsWithIssues.value.length, 1);
254
334
  assert.equal(extendedElementsWithIssues.value[0]?.element, element1);
255
335
  });
@@ -259,23 +339,35 @@ suite('updateElementsWithIssues', () => {
259
339
  {
260
340
  id: 1,
261
341
  element: element1,
342
+ rootNode,
343
+ skipRender: false,
262
344
  position,
263
345
  visible,
264
346
  trigger,
347
+ anchorNameValue: 'none',
265
348
  scrollableAncestors,
266
- issues: signal([issue1])
349
+ issues: signal([issue1]),
267
350
  },
268
351
  {
269
352
  id: 2,
270
353
  element: element2,
354
+ rootNode,
355
+ skipRender: false,
271
356
  position,
272
357
  visible,
273
358
  trigger,
359
+ anchorNameValue: 'none',
274
360
  scrollableAncestors,
275
- issues: signal([issue2])
276
- }
361
+ issues: signal([issue2]),
362
+ },
277
363
  ]);
278
- updateElementsWithIssues(extendedElementsWithIssues, [violation1], win, 'accented');
364
+ updateElementsWithIssues({
365
+ extendedElementsWithIssues,
366
+ scanContext,
367
+ violations: [violation1],
368
+ win,
369
+ name: 'accented',
370
+ });
279
371
  assert.equal(extendedElementsWithIssues.value.length, 1);
280
372
  assert.equal(extendedElementsWithIssues.value[0]?.element, element1);
281
373
  assert.equal(extendedElementsWithIssues.value[0]?.issues.value.length, 1);