@markuplint/ml-spec 3.11.0 → 4.0.0-alpha.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 (83) hide show
  1. package/lib/constant/aria-version.js +2 -5
  2. package/lib/dom-traverse/accname-computation.js +4 -7
  3. package/lib/dom-traverse/get-attr-specs.d.ts +2 -2
  4. package/lib/dom-traverse/get-attr-specs.js +3 -7
  5. package/lib/dom-traverse/get-computed-aria-props.d.ts +1 -1
  6. package/lib/dom-traverse/get-computed-aria-props.js +7 -12
  7. package/lib/dom-traverse/get-computed-role.d.ts +1 -1
  8. package/lib/dom-traverse/get-computed-role.js +28 -32
  9. package/lib/dom-traverse/get-content-model.d.ts +2 -2
  10. package/lib/dom-traverse/get-content-model.js +5 -10
  11. package/lib/dom-traverse/get-explicit-role.d.ts +1 -1
  12. package/lib/dom-traverse/get-explicit-role.js +9 -14
  13. package/lib/dom-traverse/get-implicit-role.d.ts +2 -2
  14. package/lib/dom-traverse/get-implicit-role.js +8 -13
  15. package/lib/dom-traverse/get-non-presentational-ancestor.d.ts +2 -2
  16. package/lib/dom-traverse/get-non-presentational-ancestor.js +5 -10
  17. package/lib/dom-traverse/get-permitted-roles.d.ts +1 -1
  18. package/lib/dom-traverse/get-permitted-roles.js +3 -7
  19. package/lib/dom-traverse/get-spec.d.ts +1 -1
  20. package/lib/dom-traverse/get-spec.js +3 -7
  21. package/lib/dom-traverse/has-required-owned-elements.d.ts +1 -1
  22. package/lib/dom-traverse/has-required-owned-elements.js +12 -19
  23. package/lib/dom-traverse/is-exposed.d.ts +1 -1
  24. package/lib/dom-traverse/is-exposed.js +15 -22
  25. package/lib/dom-traverse/matches-context-role.d.ts +1 -1
  26. package/lib/dom-traverse/matches-context-role.js +4 -8
  27. package/lib/dom-traverse/may-be-focusable.d.ts +1 -1
  28. package/lib/dom-traverse/may-be-focusable.js +3 -7
  29. package/lib/index.d.ts +28 -28
  30. package/lib/index.js +28 -33
  31. package/lib/specs/aria-specs.d.ts +4 -4
  32. package/lib/specs/aria-specs.js +1 -5
  33. package/lib/specs/content-model-category-to-tag-names.d.ts +2 -2
  34. package/lib/specs/content-model-category-to-tag-names.js +1 -5
  35. package/lib/specs/get-aria.d.ts +2 -2
  36. package/lib/specs/get-aria.js +10 -16
  37. package/lib/specs/get-attr-specs.d.ts +1 -1
  38. package/lib/specs/get-attr-specs.js +4 -9
  39. package/lib/specs/get-implicit-role.d.ts +2 -2
  40. package/lib/specs/get-implicit-role.js +3 -7
  41. package/lib/specs/get-permitted-roles.d.ts +1 -1
  42. package/lib/specs/get-permitted-roles.js +14 -17
  43. package/lib/specs/get-role-spec.d.ts +1 -1
  44. package/lib/specs/get-role-spec.js +10 -14
  45. package/lib/specs/get-selectors-by-content-model-category.d.ts +2 -2
  46. package/lib/specs/get-selectors-by-content-model-category.js +2 -6
  47. package/lib/specs/get-spec-by-tag-name.d.ts +1 -1
  48. package/lib/specs/get-spec-by-tag-name.js +4 -9
  49. package/lib/specs/is-nothing-content-model.js +3 -7
  50. package/lib/specs/is-palpable-elements.d.ts +1 -1
  51. package/lib/specs/is-palpable-elements.js +5 -10
  52. package/lib/specs/is-presentational.js +1 -5
  53. package/lib/specs/is-void-element.js +1 -5
  54. package/lib/specs/resolve-version.d.ts +2 -2
  55. package/lib/specs/resolve-version.js +7 -12
  56. package/lib/specs/schema-to-spec.d.ts +3 -3
  57. package/lib/specs/schema-to-spec.js +18 -23
  58. package/lib/types/aria.js +1 -2
  59. package/lib/types/attributes.js +1 -2
  60. package/lib/types/index.d.ts +4 -4
  61. package/lib/types/index.js +1 -2
  62. package/lib/types/permitted-structures.js +1 -2
  63. package/lib/utils/get-ns.js +1 -5
  64. package/lib/utils/merge-array.js +1 -5
  65. package/lib/utils/resolve-namespace.js +4 -9
  66. package/lib/utils/validateAriaVersion.d.ts +1 -1
  67. package/lib/utils/validateAriaVersion.js +3 -7
  68. package/package.json +13 -8
  69. package/test/dom-traverse/accname-computation.spec.js +0 -69
  70. package/test/dom-traverse/get-computed-aria-props.spec.js +0 -758
  71. package/test/dom-traverse/get-computed-role.spec.js +0 -315
  72. package/test/dom-traverse/get-implicit-role.spec.js +0 -40
  73. package/test/dom-traverse/has-required-owned-elements.spec.js +0 -34
  74. package/test/dom-traverse/is-exposed.spec.js +0 -70
  75. package/test/dom-traverse/matches-context-role.spec.js +0 -60
  76. package/test/specs/get-attr-specs.spec.js +0 -41
  77. package/test/specs/get-implicit-role.spec.js +0 -79
  78. package/test/specs/get-permitted-roles.spec.js +0 -418
  79. package/test/specs/get-role-spec.spec.js +0 -67
  80. package/test/specs/get-spec-by-tag-name.spec.js +0 -68
  81. package/test/specs/resolve-version.spec.js +0 -34
  82. package/test/specs/schema-to-spec.spec.js +0 -61
  83. package/test/utils/resolve-namespace.spec.js +0 -37
@@ -1,315 +0,0 @@
1
- const specs = require('@markuplint/html-spec');
2
- const { createSelector } = require('@markuplint/selector');
3
- const { createJSDOMElement } = require('@markuplint/test-tools');
4
-
5
- const { getComputedRole } = require('../../lib/dom-traverse/get-computed-role');
6
-
7
- function _(html, selector) {
8
- return createJSDOMElement(html, selector, function (selector) {
9
- // JSDOM supports no level 4 selectors yet.
10
- return createSelector(selector, specs).match(this) !== false;
11
- });
12
- }
13
-
14
- function c(html, version, selector) {
15
- return getComputedRole(specs, _(html, selector), version);
16
- }
17
-
18
- function tree(html, version) {
19
- const el = _(html);
20
- const tree = [];
21
- let current = el;
22
- // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
23
- while (current) {
24
- const role = getComputedRole(specs, current, version);
25
- const result = [current.localName, role.role?.name ?? null];
26
- if (role.errorType) {
27
- result.push(role.errorType);
28
- }
29
- tree.push(result);
30
- current = current.children.item(0);
31
- }
32
- return tree;
33
- }
34
-
35
- describe('1.2', () => {
36
- test('the a element', () => {
37
- expect(c('<a></a>', '1.2').role?.name).toBe(undefined);
38
- expect(c('<a href></a>', '1.2').role?.name).toBe('link');
39
- expect(c('<a role="button"></a>', '1.2').role?.name).toBe('button');
40
- expect(c('<a role="button" href></a>', '1.2').role?.name).toBe('button');
41
- expect(c('<a role="foo" href></a>', '1.2').role?.name).toBe('link');
42
- });
43
-
44
- test('the heading role', () => {
45
- expect(c('<h1></h1>', '1.2').role?.name).toBe('heading');
46
- expect(c('<h1></h1>', '1.2').role?.isImplicit).toBe(true);
47
- expect(c('<div role="heading"></div>', '1.2').role?.name).toBe('heading');
48
- expect(c('<div role="heading"></div>', '1.2').role?.isImplicit).toBe(false);
49
- });
50
-
51
- test('multiple', () => {
52
- expect(c('<div role="presentation heading"></div>', '1.2').role?.name).toBe('presentation');
53
- expect(c('<div role="roletype heading"></div>', '1.2').role?.name).toBe('heading');
54
- expect(c('<img alt="alt" role="banner button"/>', '1.2').role?.name).toBe('button');
55
- expect(c('<img alt="alt" role="foo button"/>', '1.2').role?.name).toBe('button');
56
- expect(c('<img alt="alt" role="graphics-symbol button"/>', '1.2').role?.name).toBe('button');
57
- });
58
-
59
- test('svg', () => {
60
- expect(c('<svg><rect role="graphics-symbol img"></rect></svg>', '1.2', 'rect').role?.name).toBe(
61
- 'graphics-symbol',
62
- );
63
- expect(c('<svg><rect role="roletype img" aria-label="accname"></rect></svg>', '1.2', 'rect').role?.name).toBe(
64
- 'img',
65
- );
66
- expect(c('<svg><rect role="roletype" aria-label="accname"></rect></svg>', '1.2', 'rect').role?.name).toBe(
67
- 'graphics-symbol',
68
- );
69
- });
70
-
71
- test('landmark', () => {
72
- expect(c('<div role="region"></div>', '1.2').role?.name).toBe('generic');
73
- expect(c('<div role="region" aria-label="foo"></div>', '1.2').role?.name).toBe('region');
74
- expect(c('<div role="form"></div>', '1.2').role?.name).toBe('generic');
75
- expect(c('<div role="form" aria-label="foo"></div>', '1.2').role?.name).toBe('form');
76
- expect(c('<div role="navigation"></div>', '1.2').role?.name).toBe('navigation');
77
- expect(c('<div role="navigation" aria-label="foo"></div>', '1.2').role?.name).toBe('navigation');
78
- });
79
-
80
- test('Presentational Roles Conflict Resolution (1) Interactive Elements', () => {
81
- expect(c('<a href="path/to"></a>', '1.2').role?.name).toBe('link');
82
- expect(c('<a role="none" href="path/to"></a>', '1.2').role?.name).toBe('link'); // No permitted role
83
- expect(c('<a></a>', '1.2').role?.name).toBe(undefined);
84
- expect(c('<a role="none"></a>', '1.2').role?.name).toBe('none');
85
- expect(c('<a role="none" href="path/to" disabled></a>', '1.2').role?.name).toBe('link'); // No permitted role
86
- expect(c('<button></button>', '1.2').role?.name).toBe('button');
87
- expect(c('<button disabled></button>', '1.2').role?.name).toBe('button');
88
- expect(c('<button role="none"></button>', '1.2').role?.name).toBe('button'); // No permitted role
89
- expect(c('<button role="none" disabled></button>', '1.2').role?.name).toBe('button'); // No permitted role
90
- expect(c('<div></div>', '1.2').role?.name).toBe('generic');
91
- expect(c('<div role="none"></div>', '1.2').role?.name).toBe('none');
92
- expect(c('<div tabindex="0"></div>', '1.2').role?.name).toBe('generic');
93
- expect(c('<div tabindex="0" role="none"></div>', '1.2').role?.name).toBe('generic');
94
- expect(c('<div><span></span></div>', '1.2', 'span').role?.name).toBe('generic');
95
- expect(c('<div><span role="none"></span></div>', '1.2', 'span').role?.name).toBe('none');
96
- expect(c('<div><span tabindex="0"></span></div>', '1.2', 'span').role?.name).toBe('generic');
97
- expect(c('<div><span tabindex="0" role="none"></span></div>', '1.2', 'span').role?.name).toBe('generic');
98
- expect(c('<div hidden><span></span></div>', '1.2', 'span').role?.name).toBe('generic');
99
- expect(c('<div hidden><span role="none"></span></div>', '1.2', 'span').role?.name).toBe('none');
100
- expect(c('<div hidden><span tabindex="0"></span></div>', '1.2', 'span').role?.name).toBe('generic');
101
- expect(c('<div hidden><span tabindex="0" role="none"></span></div>', '1.2', 'span').role?.name).toBe('none');
102
- });
103
-
104
- test('Presentational Roles Conflict Resolution (2-1) Required Owned Elements', () => {
105
- expect(c('<table><tr><td>foo</td></tr></table>', '1.2', 'td').role?.name).toBe('cell');
106
- expect(c('<table><tr><td role="none">foo</td></tr></table>', '1.2', 'td').role?.name).toBe('cell');
107
- expect(c('<table><tbody role="none"><tr><td>foo</td></tr></tbody></table>', '1.2', 'tbody').role?.name).toBe(
108
- 'rowgroup',
109
- );
110
- expect(c('<ul><li></li></ul>', '1.2', 'li').role?.name).toBe('listitem');
111
- expect(c('<ul><li role="presentation"></li></ul>', '1.2', 'li').role?.name).toBe('listitem');
112
- });
113
-
114
- test('Presentational Roles Conflict Resolution (2-2) the accessibility tree to be malformed', () => {
115
- expect(c('<table><tr><td>foo</td></tr></table>', '1.2', 'td').role?.name).toBe('cell');
116
- expect(c('<table role="none"><tr><td>foo</td></tr></table>', '1.2', 'td').role?.name).toBe(undefined);
117
- expect(tree('<table><tr><td>foo</td></tr></table>', '1.2')).toStrictEqual([
118
- ['table', 'table'],
119
- ['tbody', 'rowgroup'],
120
- ['tr', 'row'],
121
- ['td', 'cell'],
122
- ]);
123
- expect(tree('<table role="none"><tr><td>foo</td></tr></table>', '1.2')).toStrictEqual([
124
- ['table', 'none'],
125
- ['tbody', null, 'NO_OWNER'],
126
- ['tr', null, 'NO_OWNER'],
127
- ['td', null /* NOT MATCHING THE CONDITIONS */],
128
- ]);
129
- expect(
130
- tree(
131
- '<table role="table"><tbody role="rowgroup"><tr role="row"><td role="gridcell"></td></tr></tbody></table>',
132
- '1.2',
133
- ),
134
- ).toStrictEqual([
135
- ['table', 'table'],
136
- ['tbody', 'rowgroup'],
137
- ['tr', 'row'],
138
- ['td', 'cell', 'NO_PERMITTED'],
139
- ]);
140
- expect(
141
- tree(
142
- '<table role="grid"><tbody role="rowgroup"><tr role="row"><td role="gridcell"></td></tr></tbody></table>',
143
- '1.2',
144
- ),
145
- ).toStrictEqual([
146
- ['table', 'grid'],
147
- ['tbody', 'rowgroup'],
148
- ['tr', 'row'],
149
- ['td', 'gridcell'],
150
- ]);
151
- });
152
-
153
- test('Presentational Roles Conflict Resolution (3) Global Props', () => {
154
- /**
155
- * @see https://w3c.github.io/aria/#example-41
156
- */
157
- expect(c('<h1 role="presentation" aria-describedby="comment-1"> Sample Content </h1>', '1.2').role?.name).toBe(
158
- 'heading',
159
- );
160
- expect(c('<h1 role="presentation" aria-level="2"> Sample Content </h1>', '1.2').role?.name).toBe(
161
- 'presentation',
162
- );
163
- });
164
- });
165
-
166
- describe('1.3', () => {
167
- test('the a element', () => {
168
- expect(c('<a></a>', '1.3').role?.name).toBe(undefined);
169
- expect(c('<a href></a>', '1.3').role?.name).toBe('link');
170
- expect(c('<a role="button"></a>', '1.3').role?.name).toBe('button');
171
- expect(c('<a role="button" href></a>', '1.3').role?.name).toBe('button');
172
- expect(c('<a role="foo" href></a>', '1.3').role?.name).toBe('link');
173
- });
174
-
175
- test('the heading role', () => {
176
- expect(c('<h1></h1>', '1.3').role?.name).toBe('heading');
177
- expect(c('<h1></h1>', '1.3').role?.isImplicit).toBe(true);
178
- expect(c('<div role="heading"></div>', '1.3').role?.name).toBe('heading');
179
- expect(c('<div role="heading"></div>', '1.3').role?.isImplicit).toBe(false);
180
- });
181
-
182
- test('multiple', () => {
183
- expect(c('<div role="presentation heading"></div>', '1.3').role?.name).toBe('presentation');
184
- expect(c('<div role="roletype heading"></div>', '1.3').role?.name).toBe('heading');
185
- expect(c('<img alt="alt" role="banner button"/>', '1.3').role?.name).toBe('button');
186
- expect(c('<img alt="alt" role="foo button"/>', '1.3').role?.name).toBe('button');
187
- expect(c('<img alt="alt" role="graphics-symbol button"/>', '1.3').role?.name).toBe('button');
188
- });
189
-
190
- test('svg', () => {
191
- expect(c('<svg><rect role="graphics-symbol img"></rect></svg>', '1.3', 'rect').role?.name).toBe(
192
- 'graphics-symbol',
193
- );
194
- expect(c('<svg><rect role="roletype img" aria-label="accname"></rect></svg>', '1.3', 'rect').role?.name).toBe(
195
- 'img',
196
- );
197
- expect(c('<svg><rect role="roletype" aria-label="accname"></rect></svg>', '1.3', 'rect').role?.name).toBe(
198
- 'graphics-symbol',
199
- );
200
- });
201
-
202
- test('landmark', () => {
203
- expect(c('<div role="region"></div>', '1.3').role?.name).toBe('generic');
204
- expect(c('<div role="region" aria-label="foo"></div>', '1.3').role?.name).toBe('region');
205
- expect(c('<div role="form"></div>', '1.3').role?.name).toBe('generic');
206
- expect(c('<div role="form" aria-label="foo"></div>', '1.3').role?.name).toBe('form');
207
- expect(c('<div role="navigation"></div>', '1.3').role?.name).toBe('navigation');
208
- expect(c('<div role="navigation" aria-label="foo"></div>', '1.3').role?.name).toBe('navigation');
209
- });
210
-
211
- test('Presentational Roles Conflict Resolution (1) Interactive Elements', () => {
212
- expect(c('<a href="path/to"></a>', '1.3').role?.name).toBe('link');
213
- expect(c('<a role="none" href="path/to"></a>', '1.3').role?.name).toBe('link'); // No permitted role
214
- expect(c('<a></a>', '1.3').role?.name).toBe(undefined);
215
- expect(c('<a role="none"></a>', '1.3').role?.name).toBe('none');
216
- expect(c('<a role="none" href="path/to" disabled></a>', '1.3').role?.name).toBe('link'); // No permitted role
217
- expect(c('<button></button>', '1.3').role?.name).toBe('button');
218
- expect(c('<button disabled></button>', '1.3').role?.name).toBe('button');
219
- expect(c('<button role="none"></button>', '1.3').role?.name).toBe('button'); // No permitted role
220
- expect(c('<button role="none" disabled></button>', '1.3').role?.name).toBe('button'); // No permitted role
221
- expect(c('<div></div>', '1.3').role?.name).toBe('generic');
222
- expect(c('<div role="none"></div>', '1.3').role?.name).toBe('none');
223
- expect(c('<div tabindex="0"></div>', '1.3').role?.name).toBe('generic');
224
- expect(c('<div tabindex="0" role="none"></div>', '1.3').role?.name).toBe('generic');
225
- expect(c('<div><span></span></div>', '1.3', 'span').role?.name).toBe('generic');
226
- expect(c('<div><span role="none"></span></div>', '1.3', 'span').role?.name).toBe('none');
227
- expect(c('<div><span tabindex="0"></span></div>', '1.3', 'span').role?.name).toBe('generic');
228
- expect(c('<div><span tabindex="0" role="none"></span></div>', '1.3', 'span').role?.name).toBe('generic');
229
- expect(c('<div hidden><span></span></div>', '1.3', 'span').role?.name).toBe('generic');
230
- expect(c('<div hidden><span role="none"></span></div>', '1.3', 'span').role?.name).toBe('none');
231
- expect(c('<div hidden><span tabindex="0"></span></div>', '1.3', 'span').role?.name).toBe('generic');
232
- expect(c('<div hidden><span tabindex="0" role="none"></span></div>', '1.3', 'span').role?.name).toBe('none');
233
- });
234
-
235
- test('Presentational Roles Conflict Resolution (2-1) Required Owned Elements', () => {
236
- expect(c('<table><tr><td>foo</td></tr></table>', '1.3', 'td').role?.name).toBe('cell');
237
- expect(c('<table><tr><td role="none">foo</td></tr></table>', '1.3', 'td').role?.name).toBe('cell');
238
- expect(c('<table><tbody role="none"><tr><td>foo</td></tr></tbody></table>', '1.3', 'tbody').role?.name).toBe(
239
- 'rowgroup',
240
- );
241
- expect(c('<ul><li></li></ul>', '1.3', 'li').role?.name).toBe('listitem');
242
- expect(c('<ul><li role="presentation"></li></ul>', '1.3', 'li').role?.name).toBe('listitem');
243
- });
244
-
245
- test('Presentational Roles Conflict Resolution (2-2) the accessibility tree to be malformed', () => {
246
- expect(c('<table><tr><td>foo</td></tr></table>', '1.3', 'td').role?.name).toBe('cell');
247
- expect(c('<table role="none"><tr><td>foo</td></tr></table>', '1.3', 'td').role?.name).toBe(undefined);
248
- expect(tree('<table><tr><td>foo</td></tr></table>', '1.3')).toStrictEqual([
249
- ['table', 'table'],
250
- ['tbody', 'rowgroup'],
251
- ['tr', 'row'],
252
- ['td', 'cell'],
253
- ]);
254
- expect(tree('<table role="none"><tr><td>foo</td></tr></table>', '1.3')).toStrictEqual([
255
- ['table', 'none'],
256
- ['tbody', null, 'NO_OWNER'],
257
- ['tr', null, 'INVALID_REQUIRED_CONTEXT_ROLE'],
258
- ['td', null /* NOT MATCHING THE CONDITIONS */],
259
- ]);
260
- expect(
261
- tree(
262
- '<table role="table"><tbody role="rowgroup"><tr role="row"><td role="gridcell"></td></tr></tbody></table>',
263
- '1.3',
264
- ),
265
- ).toStrictEqual([
266
- ['table', 'table'],
267
- ['tbody', 'rowgroup'],
268
- ['tr', 'row'],
269
- ['td', 'cell', 'NO_PERMITTED'],
270
- ]);
271
- expect(
272
- tree(
273
- '<table role="grid"><tbody role="rowgroup"><tr role="row"><td role="gridcell"></td></tr></tbody></table>',
274
- '1.3',
275
- ),
276
- ).toStrictEqual([
277
- ['table', 'grid'],
278
- ['tbody', 'rowgroup'],
279
- ['tr', 'row'],
280
- ['td', 'gridcell'],
281
- ]);
282
- });
283
-
284
- test('Presentational Roles Conflict Resolution (3) Global Props', () => {
285
- /**
286
- * @see https://w3c.github.io/aria/#example-41
287
- */
288
- expect(c('<h1 role="presentation" aria-describedby="comment-1"> Sample Content </h1>', '1.3').role?.name).toBe(
289
- 'heading',
290
- );
291
- expect(c('<h1 role="presentation" aria-level="2"> Sample Content </h1>', '1.3').role?.name).toBe(
292
- 'presentation',
293
- );
294
- });
295
- });
296
-
297
- describe('Issues', () => {
298
- test('#778', () => {
299
- expect(c('<td role="gridcell"></td>', '1.2').role?.name).toBe('gridcell');
300
- expect(c('<td role="gridcell"></td>', '1.3').role?.name).toBe('gridcell');
301
- });
302
-
303
- test('#1026', () => {
304
- expect(c('<svg><rect width="30" height="30" /></svg>', '1.2', 'rect').role?.name).toBe(undefined);
305
- expect(
306
- c('<svg><rect width="30" height="30"><title>Accname</title></rect></svg>', '1.2', 'rect').role?.name,
307
- ).toBe('graphics-symbol');
308
- expect(c('<svg><rect aria-label="accname" width="30" height="30" /></svg>', '1.2', 'rect').role?.name).toBe(
309
- 'graphics-symbol',
310
- );
311
- expect(
312
- c('<svg role="img"><rect aria-label="accname" width="30" height="30" /></svg>', '1.2', 'rect').role?.name,
313
- ).toBe('graphics-symbol');
314
- });
315
- });
@@ -1,40 +0,0 @@
1
- const specs = require('@markuplint/html-spec');
2
- const { createSelector } = require('@markuplint/selector');
3
- const { createJSDOMElement } = require('@markuplint/test-tools');
4
-
5
- const { getImplicitRole } = require('../../lib/dom-traverse/get-implicit-role');
6
-
7
- function _(html, selector) {
8
- return createJSDOMElement(html, selector, function (selector) {
9
- // JSDOM supports no level 4 selectors yet.
10
- return createSelector(selector, specs).match(this) !== false;
11
- });
12
- }
13
-
14
- describe('1.2', () => {
15
- test('<button>', () => {
16
- const el = _('<button></button>');
17
- const role = getImplicitRole(specs, el, '1.2');
18
- expect(role.role?.name).toBe('button');
19
- });
20
-
21
- test('<td>', () => {
22
- const el = _('<table><tr><td></td></tr></table>', 'td');
23
- const role = getImplicitRole(specs, el, '1.2');
24
- expect(role.role?.name).toBe('cell');
25
- });
26
- });
27
-
28
- describe('1.3', () => {
29
- test('<button>', () => {
30
- const el = _('<button></button>');
31
- const role = getImplicitRole(specs, el, '1.3');
32
- expect(role.role?.name).toBe('button');
33
- });
34
-
35
- test('<td>', () => {
36
- const el = _('<table><tr><td></td></tr></table>', 'td');
37
- const role = getImplicitRole(specs, el, '1.3');
38
- expect(role.role?.name).toBe('cell');
39
- });
40
- });
@@ -1,34 +0,0 @@
1
- const specs = require('@markuplint/html-spec');
2
- const { createSelector } = require('@markuplint/selector');
3
- const { createJSDOMElement } = require('@markuplint/test-tools');
4
-
5
- const { hasRequiredOwnedElement } = require('../../lib/dom-traverse/has-required-owned-elements');
6
-
7
- function _(html, selector) {
8
- return createJSDOMElement(html, selector, function (selector) {
9
- // JSDOM supports no level 4 selectors yet.
10
- return createSelector(selector, specs).match(this) !== false;
11
- });
12
- }
13
-
14
- function m(html, version, selector) {
15
- const el = _(html, selector);
16
- return hasRequiredOwnedElement(el, specs, version);
17
- }
18
-
19
- describe('matchesOwnedRole', () => {
20
- test('rowgroup > row', () => {
21
- expect(m('<table><tbody><tr><td></td></tr></tbody></table>', '1.2')).toBe(true);
22
- });
23
- test('row', () => {
24
- expect(m('<table><tr><td></td></tr></table>', '1.2', 'tr')).toBe(true);
25
- });
26
- test('list > listitem', () => {
27
- expect(m('<ul><li></li></ul>', '1.2')).toBe(true);
28
- expect(m('<ul><div><li></li></div></ul>', '1.2')).toBe(false);
29
- expect(m('<ul><div role="none"><li></li></div></ul>', '1.2')).toBe(true);
30
- expect(
31
- m('<ul><div role="none"><div role="none"><div role="none"><li></li></div></div></div></ul>', '1.2'),
32
- ).toBe(true);
33
- });
34
- });
@@ -1,70 +0,0 @@
1
- const specs = require('@markuplint/html-spec');
2
- const { createSelector } = require('@markuplint/selector');
3
- const { createJSDOMElement } = require('@markuplint/test-tools');
4
-
5
- const { isExposed } = require('../../lib/dom-traverse/is-exposed');
6
-
7
- function _(html, selector) {
8
- return createJSDOMElement(html, selector, function (selector) {
9
- // JSDOM supports no level 4 selectors yet.
10
- return createSelector(selector, specs).match(this) !== false;
11
- });
12
- }
13
-
14
- function x(html, selector, version = '1.2') {
15
- const el = _(html, selector);
16
- return isExposed(el, specs, version);
17
- }
18
-
19
- describe('isExposed', () => {
20
- test('Basic', () => {
21
- expect(x('<div></div>')).toBe(true);
22
- expect(x('<div aria-hidden="true"></div>')).toBe(false);
23
- expect(x('<div role="presentation"></div>')).toBe(false);
24
- expect(x('<div role="presentation" aria-hidden="true"></div>')).toBe(false);
25
- expect(x('<div role="presentation"><span></span></div>', 'span')).toBe(true);
26
- expect(x('<div role="presentation" aria-hidden="true"><span></span></div>', 'span')).toBe(false);
27
- expect(x('<div style="display: none;"><span></span></div>', 'span')).toBe(false);
28
- expect(x('<div hidden><span></span></div>', 'span')).toBe(false);
29
- expect(x('<div hidden="until-found"><span></span></div>', 'span')).toBe(false);
30
- expect(x('<html><body>content</body></html>', 'body')).toBe(true);
31
- expect(x('<ul><li></li></ul>', 'li')).toBe(true);
32
- });
33
-
34
- test('Children Presentational: True', () => {
35
- expect(x('<button></button>')).toBe(true);
36
- expect(x('<button hidden></button>')).toBe(false);
37
- expect(x('<button><span></span></button>', 'span')).toBe(false);
38
- expect(x('<button hidden><span></span></button>', 'span')).toBe(false);
39
- });
40
-
41
- test('Hidden elements', () => {
42
- expect(x('<input type="text">')).toBe(true);
43
- expect(x('<input type="hidden">')).toBe(false);
44
- expect(x('<meta>')).toBe(false);
45
- expect(x('<style>a{}</style>')).toBe(false);
46
- expect(x('<script>"";</script>')).toBe(false);
47
- });
48
-
49
- test('Recent element', () => {
50
- expect(x('<canvas></canvas>')).toBe(true);
51
- expect(x('<dialog></dialog>')).toBe(true);
52
- expect(x('<details></details>')).toBe(true);
53
- expect(x('<summary></summary>')).toBe(true);
54
- expect(x('<meter></meter>')).toBe(true);
55
- expect(x('<progress></progress>')).toBe(true);
56
- expect(x('<picture></picture>')).toBe(true);
57
- expect(x('<ruby></ruby>')).toBe(true);
58
- expect(x('<pt></pt>')).toBe(true);
59
- expect(x('<rp></rp>')).toBe(true);
60
- expect(x('<time></time>')).toBe(true);
61
- expect(x('<slot></slot>')).toBe(true);
62
- expect(x('<portal></portal>')).toBe(true);
63
- });
64
-
65
- test('Unknown element', () => {
66
- expect(x('<unknown></unknown>')).toBe(true);
67
- expect(x('<font></font>')).toBe(true);
68
- expect(x('<x-component></x-component>')).toBe(true);
69
- });
70
- });
@@ -1,60 +0,0 @@
1
- const specs = require('@markuplint/html-spec');
2
- const { createSelector } = require('@markuplint/selector');
3
- const { createJSDOMElement } = require('@markuplint/test-tools');
4
-
5
- const { matchesContextRole } = require('../../lib/dom-traverse/matches-context-role');
6
-
7
- function _(html, selector) {
8
- return createJSDOMElement(html, selector, function (selector) {
9
- // JSDOM supports no level 4 selectors yet.
10
- return createSelector(selector, specs).match(this) !== false;
11
- });
12
- }
13
-
14
- describe('1.2', () => {
15
- const version = '1.2';
16
-
17
- test('rowgroup', () => {
18
- const el = _('<table><tbody><tr><td></td></tr></tbody></table>', 'tr');
19
- expect(matchesContextRole(['rowgroup'], el, specs, version)).toBe(true);
20
- });
21
-
22
- test('rowgroup owned by table', () => {
23
- const el = _('<table><tbody><tr><td></td></tr></tbody></table>', 'tr');
24
- expect(matchesContextRole(['table > rowgroup'], el, specs, version)).toBe(true);
25
- });
26
-
27
- test('no rowgroup', () => {
28
- const el = _('<table><tbody><tr><td></td></tr></tbody></table>', 'tr');
29
- expect(matchesContextRole(['group'], el, specs, version)).toBe(false);
30
- });
31
-
32
- test('rowgroup owned by no table', () => {
33
- const el = _('<table><tbody><tr><td></td></tr></tbody></table>', 'tr');
34
- expect(matchesContextRole(['grid > rowgroup'], el, specs, version)).toBe(false);
35
- });
36
- });
37
-
38
- describe('1.3', () => {
39
- const version = '1.3';
40
-
41
- test('rowgroup', () => {
42
- const el = _('<table><tbody><tr><td></td></tr></tbody></table>', 'tr');
43
- expect(matchesContextRole(['rowgroup'], el, specs, version)).toBe(true);
44
- });
45
-
46
- test('rowgroup owned by table', () => {
47
- const el = _('<table><tbody><tr><td></td></tr></tbody></table>', 'tr');
48
- expect(matchesContextRole(['table > rowgroup'], el, specs, version)).toBe(true);
49
- });
50
-
51
- test('no rowgroup', () => {
52
- const el = _('<table><tbody><tr><td></td></tr></tbody></table>', 'tr');
53
- expect(matchesContextRole(['group'], el, specs, version)).toBe(false);
54
- });
55
-
56
- test('rowgroup owned by no table', () => {
57
- const el = _('<table><tbody><tr><td></td></tr></tbody></table>', 'tr');
58
- expect(matchesContextRole(['grid > rowgroup'], el, specs, version)).toBe(false);
59
- });
60
- });
@@ -1,41 +0,0 @@
1
- const htmlSpec = require('@markuplint/html-spec');
2
-
3
- const { getAttrSpecs } = require('../../lib/specs/get-attr-specs');
4
-
5
- describe('getSpec', () => {
6
- test('svg:image[x]', () => {
7
- const specs = getAttrSpecs('image', 'http://www.w3.org/2000/svg', htmlSpec);
8
- const x = specs?.find(spec => spec.name === 'x');
9
- expect(x).toStrictEqual({
10
- defaultValue: '0',
11
- name: 'x',
12
- type: ['<svg-length>', '<percentage>'],
13
- animatable: true,
14
- });
15
- });
16
-
17
- test('svg:foreignObject[x]', () => {
18
- const specs = getAttrSpecs('foreignObject', 'http://www.w3.org/2000/svg', htmlSpec);
19
- const x = specs?.find(spec => spec.name === 'x');
20
- expect(x).toStrictEqual({
21
- defaultValue: '0',
22
- description:
23
- 'The x coordinate of the foreignObject. Value type: <length>|<percentage> ; Default value: 0; Animatable: yes',
24
- name: 'x',
25
- type: ['<svg-length>', '<percentage>'],
26
- animatable: true,
27
- });
28
- });
29
-
30
- test('svg:linearGradient[xlink:href]', () => {
31
- const specs = getAttrSpecs('linearGradient', 'http://www.w3.org/2000/svg', htmlSpec);
32
- const x = specs?.find(spec => spec.name === 'xlink:href');
33
- expect(x).toStrictEqual({
34
- description:
35
- 'Deprecated: This feature is no longer recommended. Though some browsers might still support it, it may have already been removed from the relevant web standards, may be in the process of being dropped, or may only be kept for compatibility purposes. Avoid using it, and update existing code if possible; see the compatibility table at the bottom of this page to guide your decision. Be aware that this feature may cease to work at any time.An <IRI> reference to another <linearGradient> element that will be used as a template. Value type: <IRI> ; Default value: none; Animatable: yes',
36
- name: 'xlink:href',
37
- type: 'URL',
38
- deprecated: true,
39
- });
40
- });
41
- });
@@ -1,79 +0,0 @@
1
- const specs = require('@markuplint/html-spec');
2
- const { createSelector } = require('@markuplint/selector');
3
- const { createJSDOMElement } = require('@markuplint/test-tools');
4
-
5
- const { getImplicitRole } = require('../../lib/specs/get-implicit-role');
6
-
7
- function c(html, version) {
8
- const el = createJSDOMElement(html);
9
- return getImplicitRole(
10
- specs,
11
- el.localName,
12
- el.namespaceURI,
13
- version,
14
- selector => createSelector(selector, specs).match(el) !== false,
15
- );
16
- }
17
-
18
- describe('getImplicitRole', () => {
19
- test('the a element', () => {
20
- expect(c('<a></a>', '1.2')).toBe(false);
21
- expect(c('<a name="foo"></a>', '1.2')).toBe(false);
22
- expect(c('<a href></a>', '1.2')).toBe('link');
23
- expect(c('<a href=""></a>', '1.2')).toBe('link');
24
- expect(c('<a href="path/to"></a>', '1.2')).toBe('link');
25
- });
26
-
27
- test('the area element', () => {
28
- expect(c('<area />', '1.2')).toBe('generic');
29
- expect(c('<area shape="rect" />', '1.2')).toBe('generic');
30
- expect(c('<area href />', '1.2')).toBe('link');
31
- expect(c('<area href="" />', '1.2')).toBe('link');
32
- expect(c('<area href="path/to" />', '1.2')).toBe('link');
33
- });
34
-
35
- test('the article element', () => {
36
- expect(c('<article></article>', '1.2')).toBe('article');
37
- });
38
-
39
- test('the aside element', () => {
40
- expect(c('<aside></aside>', '1.2')).toBe('complementary');
41
- });
42
-
43
- test('the audio element', () => {
44
- expect(c('<audio></audio>', '1.2')).toBe(false);
45
- });
46
-
47
- test('the h1 element', () => {
48
- expect(c('<h1></h1>', '1.2')).toBe('heading');
49
- });
50
-
51
- test('the header element', () => {
52
- expect(c('<header></header>', '1.2')).toBe('banner');
53
- expect(c('<header><article></article></header>', '1.2')).toBe('generic');
54
- expect(c('<header><article></article></header>', '1.1')).toBe(false);
55
- expect(c('<header><div></div></header>', '1.2')).toBe('banner');
56
- expect(c('<header><div role="article"></div></header>', '1.2')).toBe('generic');
57
- expect(c('<header><div role="article"></div></header>', '1.1')).toBe(false);
58
- });
59
-
60
- test('the img element', () => {
61
- expect(c('<img />', '1.2')).toBe('img');
62
- expect(c('<img alt />', '1.2')).toBe('presentation');
63
- expect(c('<img alt="" />', '1.2')).toBe('presentation');
64
- expect(c('<img alt="foo" />', '1.2')).toBe('img');
65
- expect(c('<img aria-label="foo" />', '1.2')).toBe('img');
66
- });
67
-
68
- test('the form element', () => {
69
- expect(c('<form></form>', '1.2')).toBe(false);
70
- expect(c('<form></form>', '1.1')).toBe(false);
71
- expect(c('<form aria-label="foo"></form>', '1.2')).toBe('form');
72
- expect(c('<form aria-label="foo"></form>', '1.1')).toBe('form');
73
- });
74
-
75
- test('the section element', () => {
76
- expect(c('<section></section>', '1.2')).toBe(false);
77
- expect(c('<section aria-label="foo"></section>', '1.2')).toBe('region');
78
- });
79
- });