testaro 12.2.7 → 12.4.0

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 (43) hide show
  1. package/README.md +7 -6
  2. package/actSpecs.js +12 -0
  3. package/dupAtt/temp.html +19 -0
  4. package/package.json +2 -1
  5. package/run.js +10 -6
  6. package/tests/attVal.js +2 -2
  7. package/tests/autocomplete.js +75 -0
  8. package/tests/dupAtt.js +54 -0
  9. package/validation/tests/jobs/allHidden.json +1 -1
  10. package/validation/tests/jobs/attVal.json +60 -0
  11. package/validation/tests/jobs/autocomplete.json +51 -0
  12. package/validation/tests/jobs/bulk.json +1 -1
  13. package/validation/tests/jobs/docType.json +1 -1
  14. package/validation/tests/jobs/dupAtt.json +51 -0
  15. package/validation/tests/jobs/elements.json +1 -1
  16. package/validation/tests/jobs/embAc.json +1 -1
  17. package/validation/tests/jobs/filter.json +1 -1
  18. package/validation/tests/jobs/focAll.json +1 -1
  19. package/validation/tests/jobs/focInd.json +1 -1
  20. package/validation/tests/jobs/focOp.json +1 -1
  21. package/validation/tests/jobs/focVis.json +1 -1
  22. package/validation/tests/jobs/hover.json +1 -1
  23. package/validation/tests/jobs/labClash.json +1 -1
  24. package/validation/tests/jobs/linkTo.json +1 -1
  25. package/validation/tests/jobs/linkUl.json +1 -1
  26. package/validation/tests/jobs/menuNav.json +1 -1
  27. package/validation/tests/jobs/miniText.json +1 -1
  28. package/validation/tests/jobs/motion.json +1 -1
  29. package/validation/tests/jobs/nonTable.json +1 -1
  30. package/validation/tests/jobs/radioSet.json +1 -1
  31. package/validation/tests/jobs/role.json +1 -1
  32. package/validation/tests/jobs/styleDiff.json +1 -1
  33. package/validation/tests/jobs/tabNav.json +1 -1
  34. package/validation/tests/jobs/textNodes.json +1 -1
  35. package/validation/tests/jobs/title.json +1 -1
  36. package/validation/tests/jobs/titledEl.json +1 -1
  37. package/validation/tests/jobs/zIndex.json +1 -1
  38. package/validation/tests/targets/attVal/bad.html +15 -0
  39. package/validation/tests/targets/attVal/good.html +15 -0
  40. package/validation/tests/targets/autocomplete/bad.html +20 -0
  41. package/validation/tests/targets/autocomplete/good.html +22 -0
  42. package/validation/tests/targets/dupAtt/bad.html +19 -0
  43. package/validation/tests/targets/dupAtt/good.html +16 -0
package/README.md CHANGED
@@ -31,7 +31,9 @@ Testaro uses:
31
31
  - [Playwright](https://playwright.dev/) to launch browsers, perform user actions in them, and perform tests
32
32
  - [pixelmatch](https://www.npmjs.com/package/pixelmatch) to measure motion
33
33
 
34
- Testaro includes some of its own accessibility tests. In addition, it performs the tests of these tools:
34
+ Testaro includes some of its own accessibility tests. Some of them are derived from tests performed by the [BBC Accessibility Standards Checker](https://github.com/bbc/bbc-a11y).
35
+
36
+ In addition, Testaro performs tests of these tools:
35
37
  - [accessibility-checker](https://www.npmjs.com/package/accessibility-checker) (the IBM Equal Access Accessibility Checker)
36
38
  - [alfa](https://alfa.siteimprove.com/) (Siteimprove alfa)
37
39
  - [axe-playwright](https://www.npmjs.com/package/axe-playwright) (Deque Axe-core)
@@ -42,8 +44,6 @@ Testaro includes some of its own accessibility tests. In addition, it performs t
42
44
  - [Tenon](https://tenon.io/documentation/what-tenon-tests.php) (Level Access)
43
45
  - [WAVE API](https://wave.webaim.org/api/) (WebAIM WAVE)
44
46
 
45
- Some of the Testaro tests are derived from tests performed by the [BBC Accessibility Standards Checker](https://github.com/bbc/bbc-a11y).
46
-
47
47
  As of this version, the counts of tests of the tools referenced above were:
48
48
  - Alfa: 103
49
49
  - Axe-core: 138
@@ -54,9 +54,8 @@ As of this version, the counts of tests of the tools referenced above were:
54
54
  - QualWeb core: 121
55
55
  - Tenon: 180
56
56
  - WAVE: 110
57
- - subtotal: 1327
58
- - Testaro tests: 24
59
- - grand total: 1351
57
+ - Testaro: 29
58
+ - total: 1356
60
59
 
61
60
  ## Quasi-tests
62
61
 
@@ -537,6 +536,8 @@ The third item in each array, if there are 3 items in the array, is the criterio
537
536
 
538
537
  A typical use for an `expect` property is checking the correctness of a Testaro test. Thus, the validation jobs in the `validation/tests/jobs` directory all contain `test` acts with `expect` properties. See the “Validation” section below.
539
538
 
539
+ When a `test` act has an `expect` property, the result for that act has an `expectations` property reporting whether the expectations were satisfied. The value of `expectations` is an array of objects, one object per expectation. Each object includes a `property` property identifying the expectation, and a `passed` property with `true` or `false` value reporting whether the expectation was satisfied. If applicable, it also has other properties identifying what was expected and what was actually reported.
540
+
540
541
  ## Execution
541
542
 
542
543
  ### Introduction
package/actSpecs.js CHANGED
@@ -168,6 +168,12 @@ exports.actSpecs = {
168
168
  withItems: [true, 'boolean', '', 'itemize']
169
169
  }
170
170
  ],
171
+ autocomplete: [
172
+ 'Perform an autocomplete test',
173
+ {
174
+ withItems: [true, 'boolean', '', 'itemize']
175
+ }
176
+ ],
171
177
  axe: [
172
178
  'Perform an Axe test',
173
179
  {
@@ -181,6 +187,12 @@ exports.actSpecs = {
181
187
  rules: [false, 'array', 'areNumbers', 'rule numbers (e.g., 25), if not all']
182
188
  }
183
189
  ],
190
+ dupAtt: [
191
+ 'Perform a dupAtt test',
192
+ {
193
+ withItems: [true, 'boolean', '', 'itemize']
194
+ }
195
+ ],
184
196
  elements: [
185
197
  'Perform an elements test',
186
198
  {
@@ -0,0 +1,19 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en-US">
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <title>Test page</title>
6
+ <meta name="description" content="tester">
7
+ <meta name="viewport" content="width=device-width, initial-scale=1">
8
+ </head>
9
+ <body>
10
+ <main>
11
+ <h1>Test page</h1>
12
+ <p><button id="violator" width="4rem" width="10rem">Submit</button></p>
13
+ <p
14
+ aria-label="large"
15
+ aria-label="small"
16
+ >A paragraph</p>
17
+ </main>
18
+ </body>
19
+ </html>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "testaro",
3
- "version": "12.2.7",
3
+ "version": "12.4.0",
4
4
  "description": "Automation of accessibility testing",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -35,6 +35,7 @@
35
35
  "accessibility-checker": "*",
36
36
  "axe-playwright": "*",
37
37
  "dotenv": "*",
38
+ "node-fetch": "*",
38
39
  "pixelmatch": "*",
39
40
  "playwright": "*"
40
41
  },
package/run.js CHANGED
@@ -34,10 +34,12 @@ const tests = {
34
34
  alfa: 'alfa',
35
35
  allHidden: 'page that is entirely or mostly hidden',
36
36
  attVal: 'elements with attributes having illicit values',
37
+ autocomplete: 'name and email inputs without autocomplete attributes',
37
38
  axe: 'Axe',
38
39
  bulk: 'count of visible elements',
39
40
  continuum: 'Level Access Continuum, community edition',
40
41
  docType: 'document without a doctype property',
42
+ dupAtt: 'elements with duplicate attributes',
41
43
  elements: 'data on specified elements',
42
44
  embAc: 'active elements embedded in links or buttons',
43
45
  filter: 'filter styles on elements',
@@ -264,8 +266,9 @@ const isValidReport = report => {
264
266
  if (! acts[1].which || typeof acts[1].which !== 'string' || ! isURL(acts[1].which)) {
265
267
  return 'Second act which not a URL';
266
268
  }
267
- if (acts.some(act => ! isValidAct(act))) {
268
- return 'Not all acts valid';
269
+ const invalidAct = acts.find(act => ! isValidAct(act));
270
+ if (invalidAct) {
271
+ return `Invalid act:\n${JSON.stringify(invalidAct, null, 2)}`;
269
272
  }
270
273
  if (! sources || typeof sources !== 'object') {
271
274
  return 'Bad report sources';
@@ -496,7 +499,7 @@ const isTrue = (object, specs) => {
496
499
  }
497
500
  // Otherwise, i.e. if the expectation is of a property value:
498
501
  else if (specs.length === 3) {
499
- // Determine whether the expectation was fulfilled.
502
+ // Return whether the expectation was fulfilled.
500
503
  const relation = specs[1];
501
504
  const criterion = specs[2];
502
505
  let satisfied;
@@ -516,16 +519,17 @@ const isTrue = (object, specs) => {
516
519
  satisfied = actual !== criterion;
517
520
  }
518
521
  else if (relation === 'i') {
519
- satisfied = actual.includes(criterion);
522
+ satisfied = typeof actual === 'string' && actual.includes(criterion);
520
523
  }
521
524
  else if (relation === '!i') {
522
- satisfied = ! actual.includes(criterion);
525
+ satisfied = typeof actual === 'string' && ! actual.includes(criterion);
523
526
  }
524
527
  return [actual, satisfied];
525
528
  }
526
529
  // Otherwise, i.e. if the specifications are invalid:
527
530
  else {
528
- //
531
+ // Return this.
532
+ return [null, false];
529
533
  }
530
534
  };
531
535
  // Adds a wait error result to an act.
package/tests/attVal.js CHANGED
@@ -5,13 +5,13 @@
5
5
  exports.reporter = async (page, attributeName, areLicit, values, withItems) => {
6
6
  // Identify the elements that have the specified attribute with illicit values.
7
7
  const badAttributeData = await page.evaluate(
8
- args => {
8
+ async args => {
9
9
  const attributeName = args[0];
10
10
  // Whether the values are the licit or the illicit ones.
11
11
  const areLicit = args[1];
12
12
  const values = args[2];
13
13
  // Returns the text of an element.
14
- const textOf = async (element, limit) => {
14
+ const textOf = (element, limit) => {
15
15
  let text = element.textContent;
16
16
  text = text.trim() || element.innerHTML;
17
17
  return text.replace(/\s+/sg, ' ').replace(/<>&/g, '').slice(0, limit);
@@ -0,0 +1,75 @@
1
+ /*
2
+ autocomplete
3
+ This test reports failures to equip name and email inputs with correct autocomplete attributes.
4
+ */
5
+
6
+ // ########## IMPORTS
7
+
8
+ // Returns text associated with an element.
9
+ const {allText} = require('../procs/allText');
10
+
11
+ // ########## FUNCTIONS
12
+
13
+ // Adds a failure, if any, to the data.
14
+ const addFailure = async (withItems, input, inputText, autocomplete, data) => {
15
+ // If it does not have the required autocomplete attribute:
16
+ const autoValue = await input.getAttribute('autocomplete');
17
+ if (autoValue !== autocomplete) {
18
+ // Add this to the total.
19
+ data.total++;
20
+ // If itemization is required:
21
+ if (withItems) {
22
+ // Add the item to the data.
23
+ data.items.push([autocomplete, inputText.slice(0, 100)]);
24
+ }
25
+ }
26
+ };
27
+ // Reports failures.
28
+ exports.reporter = async (page, withItems) => {
29
+ const data = {total: 0};
30
+ if (withItems) {
31
+ data.items = [];
32
+ }
33
+ // Identify the inputs.
34
+ const inputs = await page.$$('input');
35
+ // If there are any:
36
+ if (inputs.length) {
37
+ // For each one:
38
+ for (const input of inputs) {
39
+ const inputText = await allText(page, input);
40
+ // If it is a text input:
41
+ const inputType = await input.getAttribute('type');
42
+ if (inputType === 'text' || ! inputType) {
43
+ const inputTextLC = inputText.toLowerCase();
44
+ // If it requests a given name:
45
+ if (
46
+ inputTextLC === 'first'
47
+ || ['first name', 'given name'].some(phrase => inputTextLC.includes(phrase))
48
+ ) {
49
+ // Add any failure to the data.
50
+ await addFailure(withItems, input, inputText, 'given-name', data);
51
+ }
52
+ // Otherwise, if it requests a family name:
53
+ else if (
54
+ inputTextLC === 'last'
55
+ || ['last name', 'family name'].some(phrase => inputTextLC.includes(phrase))
56
+ ) {
57
+ // Add any failure to the data.
58
+ await addFailure(withItems, input, inputText, 'family-name', data);
59
+ }
60
+ // Otherwise, if it requests an email address:
61
+ else if (inputTextLC.includes('email')) {
62
+ // Add any failure to the data.
63
+ await addFailure(withItems, input, inputText, 'email', data);
64
+ }
65
+ }
66
+ // Otherwise, if it is an email input:
67
+ else if (inputType === 'email') {
68
+ // Add any failure to the data.
69
+ await addFailure(withItems, input, inputText, 'email', data);
70
+ }
71
+ }
72
+ }
73
+ // Return the data.
74
+ return {result: data};
75
+ };
@@ -0,0 +1,54 @@
1
+ /*
2
+ dupAtt.js
3
+ This test reports duplicate attributes in the source of a document.
4
+ */
5
+
6
+ // ########## IMPORTS
7
+
8
+ // Module to make HTTP requests.
9
+ const fetch = require('node-fetch');
10
+ // Module to process files.
11
+ const fs = require('fs/promises');
12
+
13
+ // ########## FUNCTIONS
14
+
15
+ // Reports failures.
16
+ exports.reporter = async (page, withItems) => {
17
+ // Initialize the data.
18
+ const data = {total: 0};
19
+ if (withItems) {
20
+ data.items = [];
21
+ }
22
+ // Get the page.
23
+ const url = page.url();
24
+ const scheme = url.replace(/:.+/, '');
25
+ let rawPage;
26
+ if (scheme === 'file') {
27
+ const filePath = url.slice(7);
28
+ rawPage = await fs.readFile(filePath, 'utf8');
29
+ }
30
+ else {
31
+ rawPage = await fetch(url);
32
+ }
33
+ // Extract its elements, in a uniform format.
34
+ const elements = rawPage
35
+ .match(/<[^/<>]+>/g)
36
+ .map(element => element.slice(1, -1).trim().replace(/\s*=\s*/g, '='))
37
+ .map(element => element.replace(/\s+/g, ' '));
38
+ // For each element:
39
+ elements.forEach(element => {
40
+ // Identify its attributes.
41
+ const attributes = element.split(' ').slice(1).map(attVal => attVal.replace(/=.+/, ''));
42
+ // If any is duplicated:
43
+ const attSet = new Set(attributes);
44
+ if (attSet.size < attributes.length) {
45
+ // Add this to the data.
46
+ data.total++;
47
+ if (withItems) {
48
+ data.items.push(element);
49
+ }
50
+ }
51
+ });
52
+ // Return the data.
53
+ return {result: data};
54
+ };
@@ -1,5 +1,5 @@
1
1
  {
2
- "id": "allHiddenVal",
2
+ "id": "allHidden",
3
3
  "what": "validation of allHidden test",
4
4
  "strict": true,
5
5
  "timeLimit": 20,
@@ -0,0 +1,60 @@
1
+ {
2
+ "id": "attVal",
3
+ "what": "validation of attVal test",
4
+ "strict": true,
5
+ "timeLimit": 20,
6
+ "acts": [
7
+ {
8
+ "type": "launch",
9
+ "which": "chromium",
10
+ "what": "usual browser"
11
+ },
12
+ {
13
+ "type": "url",
14
+ "which": "__targets__/attVal/good.html",
15
+ "what": "page with permitted attribute values"
16
+ },
17
+ {
18
+ "type": "test",
19
+ "which": "attVal",
20
+ "attributeName": "lang",
21
+ "areLicit": true,
22
+ "values": ["en-US", "de-CH"],
23
+ "what": "attribute values",
24
+ "withItems": true,
25
+ "expect": [
26
+ ["total", "=", 0],
27
+ ["items.1"]
28
+ ]
29
+ },
30
+ {
31
+ "type": "url",
32
+ "which": "__targets__/attVal/bad.html",
33
+ "what": "page with permitted attribute values"
34
+ },
35
+ {
36
+ "type": "test",
37
+ "which": "attVal",
38
+ "attributeName": "lang",
39
+ "areLicit": false,
40
+ "values": ["en", "de"],
41
+ "what": "attribute values",
42
+ "withItems": true,
43
+ "expect": [
44
+ ["total", "=", 2],
45
+ ["items.0.tagName", "=", "HTML"],
46
+ ["items.0.attributeValue", "=", "en"],
47
+ ["items.1.tagName", "=", "SPAN"],
48
+ ["items.1.attributeValue", "=", "de"],
49
+ ["items.1.textStart", "i", "Veloparkieren"]
50
+ ]
51
+ }
52
+ ],
53
+ "sources": {
54
+ "script": "",
55
+ "host": {},
56
+ "requester": ""
57
+ },
58
+ "creationTime": "2023-04-19T12:34:00",
59
+ "timeStamp": "00000"
60
+ }
@@ -0,0 +1,51 @@
1
+ {
2
+ "id": "autocomplete",
3
+ "what": "validation of autocomplete test",
4
+ "strict": true,
5
+ "timeLimit": 20,
6
+ "acts": [
7
+ {
8
+ "type": "launch",
9
+ "which": "chromium",
10
+ "what": "usual browser"
11
+ },
12
+ {
13
+ "type": "url",
14
+ "which": "__targets__/autocomplete/good.html",
15
+ "what": "page with correct autocomplete attributes"
16
+ },
17
+ {
18
+ "type": "test",
19
+ "which": "autocomplete",
20
+ "what": "autocomplete attributes for name and email",
21
+ "withItems": true,
22
+ "expect": [
23
+ ["total", "=", 0],
24
+ ["items.1"]
25
+ ]
26
+ },
27
+ {
28
+ "type": "url",
29
+ "which": "__targets__/autocomplete/bad.html",
30
+ "what": "page with incorrect autocomplete attributes"
31
+ },
32
+ {
33
+ "type": "test",
34
+ "which": "autocomplete",
35
+ "what": "autocomplete attributes for name and email",
36
+ "withItems": true,
37
+ "expect": [
38
+ ["total", "=", 4],
39
+ ["items.1.0", "=", "family-name"],
40
+ ["items.2.1", "=", "Your email address"]
41
+ ]
42
+ }
43
+ ],
44
+ "sources": {
45
+ "script": "",
46
+ "host": {},
47
+ "requester": ""
48
+ },
49
+ "creationTime": "2023-04-16T21:06:00",
50
+ "timeStamp": "00000"
51
+ }
@@ -1,5 +1,5 @@
1
1
  {
2
- "id": "bulkVal",
2
+ "id": "bulk",
3
3
  "what": "validation of bulk test",
4
4
  "strict": true,
5
5
  "timeLimit": 20,
@@ -1,5 +1,5 @@
1
1
  {
2
- "id": "docTypeVal",
2
+ "id": "docType",
3
3
  "what": "validation of docType test",
4
4
  "strict": true,
5
5
  "timeLimit": 20,
@@ -0,0 +1,51 @@
1
+ {
2
+ "id": "dupAtt",
3
+ "what": "validation of dupAtt test",
4
+ "strict": true,
5
+ "timeLimit": 20,
6
+ "acts": [
7
+ {
8
+ "type": "launch",
9
+ "which": "chromium",
10
+ "what": "usual browser"
11
+ },
12
+ {
13
+ "type": "url",
14
+ "which": "__targets__/dupAtt/good.html",
15
+ "what": "page without duplicate attributes"
16
+ },
17
+ {
18
+ "type": "test",
19
+ "which": "dupAtt",
20
+ "what": "elements with duplicate attributes",
21
+ "withItems": true,
22
+ "expect": [
23
+ ["total", "=", 0],
24
+ ["items.1"]
25
+ ]
26
+ },
27
+ {
28
+ "type": "url",
29
+ "which": "__targets__/dupAtt/bad.html",
30
+ "what": "page with duplicate attributes"
31
+ },
32
+ {
33
+ "type": "test",
34
+ "which": "dupAtt",
35
+ "what": "elements with duplicate attributes",
36
+ "withItems": true,
37
+ "expect": [
38
+ ["total", "=", 2],
39
+ ["items.0", "=", "p class=\"narrow\" id=\"daParagraph\" class=\"wide\""],
40
+ ["items.1", "i", "large"]
41
+ ]
42
+ }
43
+ ],
44
+ "sources": {
45
+ "script": "",
46
+ "host": {},
47
+ "requester": ""
48
+ },
49
+ "creationTime": "2023-04-18T11:02:00",
50
+ "timeStamp": "00000"
51
+ }
@@ -1,5 +1,5 @@
1
1
  {
2
- "id": "elementsVal",
2
+ "id": "elements",
3
3
  "what": "validation of elements test",
4
4
  "strict": true,
5
5
  "timeLimit": 20,
@@ -1,5 +1,5 @@
1
1
  {
2
- "id": "embAcVal",
2
+ "id": "embAc",
3
3
  "what": "validation of embAc test",
4
4
  "strict": true,
5
5
  "timeLimit": 20,
@@ -1,5 +1,5 @@
1
1
  {
2
- "id": "filterVal",
2
+ "id": "filter",
3
3
  "what": "validation of filter test",
4
4
  "strict": true,
5
5
  "timeLimit": 20,
@@ -1,5 +1,5 @@
1
1
  {
2
- "id": "focAllVal",
2
+ "id": "focAll",
3
3
  "what": "validation of focAll test",
4
4
  "strict": true,
5
5
  "timeLimit": 20,
@@ -1,5 +1,5 @@
1
1
  {
2
- "id": "focIndVal",
2
+ "id": "focInd",
3
3
  "what": "validation of focInd test",
4
4
  "strict": true,
5
5
  "timeLimit": 20,
@@ -1,5 +1,5 @@
1
1
  {
2
- "id": "focOpVal",
2
+ "id": "focOp",
3
3
  "what": "validation of focOp test",
4
4
  "strict": true,
5
5
  "timeLimit": 20,
@@ -1,5 +1,5 @@
1
1
  {
2
- "id": "focVisVal",
2
+ "id": "focVis",
3
3
  "what": "validation of focVis test",
4
4
  "strict": true,
5
5
  "timeLimit": 20,
@@ -1,5 +1,5 @@
1
1
  {
2
- "id": "hoverVal",
2
+ "id": "hover",
3
3
  "what": "validation of hover test",
4
4
  "strict": true,
5
5
  "timeLimit": 20,
@@ -1,5 +1,5 @@
1
1
  {
2
- "id": "labClashVal",
2
+ "id": "labClash",
3
3
  "what": "validation of labClash test",
4
4
  "strict": true,
5
5
  "timeLimit": 20,
@@ -1,5 +1,5 @@
1
1
  {
2
- "id": "linkToVal",
2
+ "id": "linkTo",
3
3
  "what": "validation of linkTo test",
4
4
  "strict": true,
5
5
  "timeLimit": 20,
@@ -1,5 +1,5 @@
1
1
  {
2
- "id": "linkUlVal",
2
+ "id": "linkUl",
3
3
  "what": "validation of linkUl test",
4
4
  "strict": true,
5
5
  "timeLimit": 20,
@@ -1,5 +1,5 @@
1
1
  {
2
- "id": "menuNavVal",
2
+ "id": "menuNav",
3
3
  "what": "validation of menuNav test",
4
4
  "strict": true,
5
5
  "timeLimit": 20,
@@ -1,5 +1,5 @@
1
1
  {
2
- "id": "miniTextVal",
2
+ "id": "miniText",
3
3
  "what": "validation of miniText test",
4
4
  "strict": true,
5
5
  "timeLimit": 20,
@@ -1,5 +1,5 @@
1
1
  {
2
- "id": "motionVal",
2
+ "id": "motion",
3
3
  "what": "validation of motion test",
4
4
  "strict": true,
5
5
  "timeLimit": 20,
@@ -1,5 +1,5 @@
1
1
  {
2
- "id": "nonTableVal",
2
+ "id": "nonTable",
3
3
  "what": "validation of nonTable test",
4
4
  "strict": true,
5
5
  "timeLimit": 20,
@@ -1,5 +1,5 @@
1
1
  {
2
- "id": "radioSetVal",
2
+ "id": "radioSet",
3
3
  "what": "validation of radioSet test",
4
4
  "strict": true,
5
5
  "timeLimit": 20,
@@ -1,5 +1,5 @@
1
1
  {
2
- "id": "roleVal",
2
+ "id": "role",
3
3
  "what": "validation of role test",
4
4
  "strict": true,
5
5
  "timeLimit": 20,
@@ -1,5 +1,5 @@
1
1
  {
2
- "id": "styleDiffVal",
2
+ "id": "styleDiff",
3
3
  "what": "validation of styleDiff test",
4
4
  "strict": true,
5
5
  "timeLimit": 20,
@@ -1,5 +1,5 @@
1
1
  {
2
- "id": "tabNavVal",
2
+ "id": "tabNav",
3
3
  "what": "validation of tabNav test",
4
4
  "strict": true,
5
5
  "timeLimit": 20,
@@ -1,5 +1,5 @@
1
1
  {
2
- "id": "elementsVal",
2
+ "id": "elements",
3
3
  "what": "validation of elements test",
4
4
  "strict": true,
5
5
  "timeLimit": 20,
@@ -1,5 +1,5 @@
1
1
  {
2
- "id": "titleVal",
2
+ "id": "title",
3
3
  "what": "validation of title test",
4
4
  "strict": true,
5
5
  "timeLimit": 20,
@@ -1,5 +1,5 @@
1
1
  {
2
- "id": "titledElVal",
2
+ "id": "titledEl",
3
3
  "what": "validation of titledEl test",
4
4
  "strict": true,
5
5
  "timeLimit": 20,
@@ -1,5 +1,5 @@
1
1
  {
2
- "id": "zIndexVal",
2
+ "id": "zIndex",
3
3
  "what": "validation of zIndex test",
4
4
  "strict": true,
5
5
  "timeLimit": 20,
@@ -0,0 +1,15 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <title>Page with illicit attribute values</title>
6
+ <meta name="description" content="tester">
7
+ <meta name="viewport" content="width=device-width, initial-scale=1">
8
+ </head>
9
+ <body>
10
+ <main>
11
+ <h1>Page with illicit attribute values</h1>
12
+ <p><q><span lang="de">Veloparkieren nicht gestattet</span></q> is Swiss German, so it should be marked up with the <code>de-ch</code> language tag.</p>
13
+ </main>
14
+ </body>
15
+ </html>
@@ -0,0 +1,15 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en-US">
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <title>Page with licit attribute values</title>
6
+ <meta name="description" content="tester">
7
+ <meta name="viewport" content="width=device-width, initial-scale=1">
8
+ </head>
9
+ <body>
10
+ <main>
11
+ <h1>Page with illicit attribute values</h1>
12
+ <p><q><span>lang="de-CH">Veloparkieren nicht gestattet</span></q> is Swiss German, so it is marked up with the <code>de-CH</code> language tag.</p>
13
+ </main>
14
+ </body>
15
+ </html>
@@ -0,0 +1,20 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en-US">
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <title>Page with incorrect autocomplete attributes</title>
6
+ <meta name="description" content="tester">
7
+ <meta name="viewport" content="width=device-width, initial-scale=1">
8
+ </head>
9
+ <body>
10
+ <main>
11
+ <h1>Page with incorrect autocomplete attributes</h1>
12
+ <p><label>Your first name <input width="40rem" autocomplete="first-name"></label></p>
13
+ <p><label>Your last name <input type="text" width="40rem"></label></p>
14
+ <p><label>Your email address <input width="40rem"></label></p>
15
+ <p><label>
16
+ Your email address again <input type="email" width="40rem" autocomplete="email-address">
17
+ </label></p>
18
+ </main>
19
+ </body>
20
+ </html>
@@ -0,0 +1,22 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en-US">
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <title>Page with correct autocomplete attributes</title>
6
+ <meta name="description" content="tester">
7
+ <meta name="viewport" content="width=device-width, initial-scale=1">
8
+ </head>
9
+ <body>
10
+ <main>
11
+ <h1>Page with correct autocomplete attributes</h1>
12
+ <p><label>Your first name <input width="40rem" autocomplete="given-name"></label></p>
13
+ <p><label>
14
+ Your last name <input type="text" width="40rem" autocomplete="family-name">
15
+ </label></p>
16
+ <p><label>Your email address <input width="40rem" autocomplete="email"></label></p>
17
+ <p><label>
18
+ Your email address again <input type="email" width="40rem" autocomplete="email">
19
+ </label></p>
20
+ </main>
21
+ </body>
22
+ </html>
@@ -0,0 +1,19 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en-US">
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <title>Page with duplicate attributes</title>
6
+ <meta name="description" content="tester">
7
+ <meta name="viewport" content="width=device-width, initial-scale=1">
8
+ </head>
9
+ <body>
10
+ <main>
11
+ <h1>Page with duplicate attributes</h1>
12
+ <p class="narrow" id="daParagraph" class="wide">Submit</p>
13
+ <p><button
14
+ aria-label="large"
15
+ aria-label="small"
16
+ >A paragraph</button></p>
17
+ </main>
18
+ </body>
19
+ </html>
@@ -0,0 +1,16 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en-US">
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <title>Page without duplicate attributes</title>
6
+ <meta name="description" content="tester">
7
+ <meta name="viewport" content="width=device-width, initial-scale=1">
8
+ </head>
9
+ <body>
10
+ <main>
11
+ <h1>Page without duplicate attributes</h1>
12
+ <p class="narrow" id="okParagraph" lang="es-US">Buscar</p>
13
+ <p><button id="p" aria-label="A body of text">A paragraph</button></p>
14
+ </main>
15
+ </body>
16
+ </html>