testaro 5.5.10 → 5.6.2
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.
- package/README.md +3 -1
- package/continuum/AccessEngine.community.js +791 -0
- package/continuum/Continuum.community.js +2697 -0
- package/continuum/continuum.conf.js +19 -0
- package/package.json +1 -1
- package/run.js +17 -1
- package/samples/scripts/tp13.json +163 -0
- package/samples/scripts/tp14.json +168 -0
- package/tests/continuum.js +60 -0
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/* eslint-disable semi */
|
|
2
|
+
/* eslint-disable quotes */
|
|
3
|
+
window.LevelAccess_AccessContinuumConfiguration = {
|
|
4
|
+
"accessEngineType": "community",
|
|
5
|
+
"ampInstanceUrl": "https://amp.levelaccess.net",
|
|
6
|
+
"defaultStandardIds": [
|
|
7
|
+
610, /* WCAG 2.0 Level A */
|
|
8
|
+
611, /* WCAG 2.0 Level AA */
|
|
9
|
+
612, /* WCAG 2.0 Level AAA */
|
|
10
|
+
1387, /* WCAG 2.1 Level A */
|
|
11
|
+
1388, /* WCAG 2.1 Level AA */
|
|
12
|
+
1389, /* WCAG 2.1 Level AAA */
|
|
13
|
+
1140, /* Section 508 and 255 (Revised 2017) */
|
|
14
|
+
1471 /* WCAG 2.0 Level A & AA Baseline */
|
|
15
|
+
],
|
|
16
|
+
// includePotentialAccessibilityConcerns may be true only in the Professional Edition.
|
|
17
|
+
"includePotentialAccessibilityConcerns": false,
|
|
18
|
+
"ampApiToken": null
|
|
19
|
+
}
|
package/package.json
CHANGED
package/run.js
CHANGED
|
@@ -32,6 +32,7 @@ const tests = {
|
|
|
32
32
|
alfa: 'alfa',
|
|
33
33
|
axe: 'Axe',
|
|
34
34
|
bulk: 'count of visible elements',
|
|
35
|
+
continuum: 'Level Access Continuum, community edition',
|
|
35
36
|
embAc: 'active elements embedded in links or buttons',
|
|
36
37
|
focAll: 'focusable and Tab-focused elements',
|
|
37
38
|
focInd: 'focus indicators',
|
|
@@ -53,7 +54,7 @@ const tests = {
|
|
|
53
54
|
};
|
|
54
55
|
// Tests that may change the DOM.
|
|
55
56
|
const domChangers = new Set([
|
|
56
|
-
'axe', 'focAll', 'focInd', 'focOp', 'hover', 'htmlcs', 'ibm', 'menuNav', 'wave'
|
|
57
|
+
'axe', 'continuum', 'focAll', 'focInd', 'focOp', 'hover', 'htmlcs', 'ibm', 'menuNav', 'wave'
|
|
57
58
|
]);
|
|
58
59
|
// Browser types available in PlayWright.
|
|
59
60
|
const browserTypeNames = {
|
|
@@ -74,12 +75,14 @@ const errorWords = [
|
|
|
74
75
|
'deprecated',
|
|
75
76
|
'error',
|
|
76
77
|
'failed',
|
|
78
|
+
'invalid',
|
|
77
79
|
'missing',
|
|
78
80
|
'but not used',
|
|
79
81
|
'refused',
|
|
80
82
|
'requires',
|
|
81
83
|
'suspicious',
|
|
82
84
|
'unrecognized',
|
|
85
|
+
'violates',
|
|
83
86
|
'warning'
|
|
84
87
|
];
|
|
85
88
|
|
|
@@ -500,6 +503,7 @@ const goto = async (page, url, timeout, waitUntil, isStrict) => {
|
|
|
500
503
|
if (url.startsWith('file://.')) {
|
|
501
504
|
url = url.replace('file://', `file://${__dirname}/`);
|
|
502
505
|
}
|
|
506
|
+
// Visit the URL.
|
|
503
507
|
const response = await page.goto(url, {
|
|
504
508
|
timeout,
|
|
505
509
|
waitUntil
|
|
@@ -509,25 +513,37 @@ const goto = async (page, url, timeout, waitUntil, isStrict) => {
|
|
|
509
513
|
visitTimeoutCount++;
|
|
510
514
|
return 'error';
|
|
511
515
|
});
|
|
516
|
+
// If the visit succeeded:
|
|
512
517
|
if (typeof response !== 'string') {
|
|
513
518
|
const httpStatus = response.status();
|
|
519
|
+
// If the response status was normal:
|
|
514
520
|
if ([200, 304].includes(httpStatus) || url.startsWith('file:')) {
|
|
521
|
+
// If the browser was redirected in violation of a strictness requirement.
|
|
515
522
|
const actualURL = page.url();
|
|
516
523
|
if (isStrict && deSlash(actualURL) !== deSlash(url)) {
|
|
524
|
+
// Return an error.
|
|
517
525
|
console.log(`ERROR: Visit to ${url} redirected to ${actualURL}`);
|
|
518
526
|
return 'redirection';
|
|
519
527
|
}
|
|
528
|
+
// Otherwise, i.e. if no prohibited redirection occurred:
|
|
520
529
|
else {
|
|
530
|
+
// Press the Escape key to dismiss any modal dialog.
|
|
531
|
+
await page.keyboard.press('Escape');
|
|
532
|
+
// Return the response.
|
|
521
533
|
return response;
|
|
522
534
|
}
|
|
523
535
|
}
|
|
536
|
+
// Otherwise, i.e. if the response status was abnormal:
|
|
524
537
|
else {
|
|
538
|
+
// Return an error.
|
|
525
539
|
console.log(`ERROR: Visit to ${url} got status ${httpStatus}`);
|
|
526
540
|
visitRejectionCount++;
|
|
527
541
|
return 'error';
|
|
528
542
|
}
|
|
529
543
|
}
|
|
544
|
+
// Otherwise, i.e. if the visit failed:
|
|
530
545
|
else {
|
|
546
|
+
// Return an error.
|
|
531
547
|
return 'error';
|
|
532
548
|
}
|
|
533
549
|
};
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "tp12",
|
|
3
|
+
"what": "Alfa, Axe, HTML CodeSniffer, IBM, Tenon, WAVE, and 16 custom tests",
|
|
4
|
+
"strict": true,
|
|
5
|
+
"timeLimit": 250,
|
|
6
|
+
"commands": [
|
|
7
|
+
{
|
|
8
|
+
"type": "launch",
|
|
9
|
+
"which": "webkit",
|
|
10
|
+
"what": "Webkit browser"
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
"type": "url",
|
|
14
|
+
"which": "https://*",
|
|
15
|
+
"what": "any page"
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"type": "tenonRequest",
|
|
19
|
+
"id": "a",
|
|
20
|
+
"withNewContent": true,
|
|
21
|
+
"what": "Tenon API version 2 test request"
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
"type": "test",
|
|
25
|
+
"which": "motion",
|
|
26
|
+
"what": "spontaneous change of content; requires webkit",
|
|
27
|
+
"delay": 2500,
|
|
28
|
+
"interval": 2500,
|
|
29
|
+
"count": 5
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
"type": "launch",
|
|
33
|
+
"which": "chromium",
|
|
34
|
+
"what": "Chromium browser"
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
"type": "url",
|
|
38
|
+
"which": "https://*",
|
|
39
|
+
"what": "any page"
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
"type": "test",
|
|
43
|
+
"which": "bulk",
|
|
44
|
+
"what": "count of visible elements"
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
"type": "test",
|
|
48
|
+
"which": "embAc",
|
|
49
|
+
"withItems": true,
|
|
50
|
+
"what": "active elements incorrectly embedded in each other"
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
"type": "test",
|
|
54
|
+
"which": "focAll",
|
|
55
|
+
"what": "Tab-focusability"
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
"type": "test",
|
|
59
|
+
"which": "focInd",
|
|
60
|
+
"revealAll": false,
|
|
61
|
+
"allowedDelay": 250,
|
|
62
|
+
"withItems": true,
|
|
63
|
+
"what": "focus indicators"
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
"type": "test",
|
|
67
|
+
"which": "focOp",
|
|
68
|
+
"withItems": true,
|
|
69
|
+
"what": "focusability and operability of elements"
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
"type": "test",
|
|
73
|
+
"which": "hover",
|
|
74
|
+
"headSize": 40,
|
|
75
|
+
"headSampleSize": 20,
|
|
76
|
+
"tailSampleSize": 15,
|
|
77
|
+
"withItems": true,
|
|
78
|
+
"what": "hover impacts"
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
"type": "test",
|
|
82
|
+
"which": "labClash",
|
|
83
|
+
"withItems": true,
|
|
84
|
+
"what": "unlabeled and mislabeled form controls"
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
"type": "test",
|
|
88
|
+
"which": "linkUl",
|
|
89
|
+
"withItems": true,
|
|
90
|
+
"what": "underlining of inline links"
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
"type": "test",
|
|
94
|
+
"which": "menuNav",
|
|
95
|
+
"withItems": true,
|
|
96
|
+
"what": "keyboard navigation within true-focus menus"
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
"type": "test",
|
|
100
|
+
"which": "radioSet",
|
|
101
|
+
"withItems": true,
|
|
102
|
+
"what": "grouping of radio buttons in fieldsets"
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
"type": "test",
|
|
106
|
+
"which": "role",
|
|
107
|
+
"what": "validity and necessity of role assignments"
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
"type": "test",
|
|
111
|
+
"which": "styleDiff",
|
|
112
|
+
"withItems": true,
|
|
113
|
+
"what": "style consistency of headings, buttons, and links"
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
"type": "test",
|
|
117
|
+
"which": "tabNav",
|
|
118
|
+
"withItems": true,
|
|
119
|
+
"what": "keyboard navigation within tab lists"
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
"type": "test",
|
|
123
|
+
"which": "zIndex",
|
|
124
|
+
"withItems": true,
|
|
125
|
+
"what": "elements with non-auto z indexes"
|
|
126
|
+
},
|
|
127
|
+
{
|
|
128
|
+
"type": "test",
|
|
129
|
+
"which": "alfa",
|
|
130
|
+
"what": "Siteimprove alfa"
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
"type": "test",
|
|
134
|
+
"which": "axe",
|
|
135
|
+
"detailLevel": 2,
|
|
136
|
+
"rules": [],
|
|
137
|
+
"what": "Axe core, all rules"
|
|
138
|
+
},
|
|
139
|
+
{
|
|
140
|
+
"type": "test",
|
|
141
|
+
"which": "htmlcs",
|
|
142
|
+
"what": "HTML CodeSniffer"
|
|
143
|
+
},
|
|
144
|
+
{
|
|
145
|
+
"type": "test",
|
|
146
|
+
"which": "ibm",
|
|
147
|
+
"withItems": true,
|
|
148
|
+
"what": "IBM Accessibility Checker, with page content and again with URL"
|
|
149
|
+
},
|
|
150
|
+
{
|
|
151
|
+
"type": "test",
|
|
152
|
+
"which": "wave",
|
|
153
|
+
"reportType": 4,
|
|
154
|
+
"what": "WAVE, report-type 4"
|
|
155
|
+
},
|
|
156
|
+
{
|
|
157
|
+
"type": "test",
|
|
158
|
+
"which": "tenon",
|
|
159
|
+
"id": "a",
|
|
160
|
+
"what": "Tenon API version 2 result retrieval"
|
|
161
|
+
}
|
|
162
|
+
]
|
|
163
|
+
}
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "tp12",
|
|
3
|
+
"what": "Alfa, Axe, Continuum, HTML CodeSniffer, IBM, Tenon, WAVE, and 16 custom tests",
|
|
4
|
+
"strict": true,
|
|
5
|
+
"timeLimit": 300,
|
|
6
|
+
"commands": [
|
|
7
|
+
{
|
|
8
|
+
"type": "launch",
|
|
9
|
+
"which": "webkit",
|
|
10
|
+
"what": "Webkit browser"
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
"type": "url",
|
|
14
|
+
"which": "https://*",
|
|
15
|
+
"what": "any page"
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"type": "tenonRequest",
|
|
19
|
+
"id": "a",
|
|
20
|
+
"withNewContent": true,
|
|
21
|
+
"what": "Tenon API version 2 test request"
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
"type": "test",
|
|
25
|
+
"which": "motion",
|
|
26
|
+
"what": "spontaneous change of content; requires webkit",
|
|
27
|
+
"delay": 2500,
|
|
28
|
+
"interval": 2500,
|
|
29
|
+
"count": 5
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
"type": "launch",
|
|
33
|
+
"which": "chromium",
|
|
34
|
+
"what": "Chromium browser"
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
"type": "url",
|
|
38
|
+
"which": "https://*",
|
|
39
|
+
"what": "any page"
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
"type": "test",
|
|
43
|
+
"which": "bulk",
|
|
44
|
+
"what": "count of visible elements"
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
"type": "test",
|
|
48
|
+
"which": "embAc",
|
|
49
|
+
"withItems": true,
|
|
50
|
+
"what": "active elements incorrectly embedded in each other"
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
"type": "test",
|
|
54
|
+
"which": "focAll",
|
|
55
|
+
"what": "Tab-focusability"
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
"type": "test",
|
|
59
|
+
"which": "focInd",
|
|
60
|
+
"revealAll": false,
|
|
61
|
+
"allowedDelay": 250,
|
|
62
|
+
"withItems": true,
|
|
63
|
+
"what": "focus indicators"
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
"type": "test",
|
|
67
|
+
"which": "focOp",
|
|
68
|
+
"withItems": true,
|
|
69
|
+
"what": "focusability and operability of elements"
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
"type": "test",
|
|
73
|
+
"which": "hover",
|
|
74
|
+
"headSize": 40,
|
|
75
|
+
"headSampleSize": 20,
|
|
76
|
+
"tailSampleSize": 15,
|
|
77
|
+
"withItems": true,
|
|
78
|
+
"what": "hover impacts"
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
"type": "test",
|
|
82
|
+
"which": "labClash",
|
|
83
|
+
"withItems": true,
|
|
84
|
+
"what": "unlabeled and mislabeled form controls"
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
"type": "test",
|
|
88
|
+
"which": "linkUl",
|
|
89
|
+
"withItems": true,
|
|
90
|
+
"what": "underlining of inline links"
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
"type": "test",
|
|
94
|
+
"which": "menuNav",
|
|
95
|
+
"withItems": true,
|
|
96
|
+
"what": "keyboard navigation within true-focus menus"
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
"type": "test",
|
|
100
|
+
"which": "radioSet",
|
|
101
|
+
"withItems": true,
|
|
102
|
+
"what": "grouping of radio buttons in fieldsets"
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
"type": "test",
|
|
106
|
+
"which": "role",
|
|
107
|
+
"what": "validity and necessity of role assignments"
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
"type": "test",
|
|
111
|
+
"which": "styleDiff",
|
|
112
|
+
"withItems": true,
|
|
113
|
+
"what": "style consistency of headings, buttons, and links"
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
"type": "test",
|
|
117
|
+
"which": "tabNav",
|
|
118
|
+
"withItems": true,
|
|
119
|
+
"what": "keyboard navigation within tab lists"
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
"type": "test",
|
|
123
|
+
"which": "zIndex",
|
|
124
|
+
"withItems": true,
|
|
125
|
+
"what": "elements with non-auto z indexes"
|
|
126
|
+
},
|
|
127
|
+
{
|
|
128
|
+
"type": "test",
|
|
129
|
+
"which": "alfa",
|
|
130
|
+
"what": "Siteimprove alfa"
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
"type": "test",
|
|
134
|
+
"which": "axe",
|
|
135
|
+
"detailLevel": 2,
|
|
136
|
+
"rules": [],
|
|
137
|
+
"what": "Axe core, all rules"
|
|
138
|
+
},
|
|
139
|
+
{
|
|
140
|
+
"type": "test",
|
|
141
|
+
"which": "continuum",
|
|
142
|
+
"what": "Continuum"
|
|
143
|
+
},
|
|
144
|
+
{
|
|
145
|
+
"type": "test",
|
|
146
|
+
"which": "htmlcs",
|
|
147
|
+
"what": "HTML CodeSniffer"
|
|
148
|
+
},
|
|
149
|
+
{
|
|
150
|
+
"type": "test",
|
|
151
|
+
"which": "ibm",
|
|
152
|
+
"withItems": true,
|
|
153
|
+
"what": "IBM Accessibility Checker, with page content and again with URL"
|
|
154
|
+
},
|
|
155
|
+
{
|
|
156
|
+
"type": "test",
|
|
157
|
+
"which": "wave",
|
|
158
|
+
"reportType": 4,
|
|
159
|
+
"what": "WAVE, report-type 4"
|
|
160
|
+
},
|
|
161
|
+
{
|
|
162
|
+
"type": "test",
|
|
163
|
+
"which": "tenon",
|
|
164
|
+
"id": "a",
|
|
165
|
+
"what": "Tenon API version 2 result retrieval"
|
|
166
|
+
}
|
|
167
|
+
]
|
|
168
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/* eslint-disable no-undef */
|
|
2
|
+
/*
|
|
3
|
+
continuum
|
|
4
|
+
This test implements the Continuum ruleset.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
// FUNCTIONS
|
|
8
|
+
// Runs Continuum on the page.
|
|
9
|
+
exports.reporter = async page => {
|
|
10
|
+
let result = {};
|
|
11
|
+
// Inject the continuum scripts into the page, exposing the continuum object.
|
|
12
|
+
for (const fileName of ['continuum.conf', 'AccessEngine.community', 'Continuum.community']) {
|
|
13
|
+
if (! result.prevented) {
|
|
14
|
+
await page.addScriptTag({
|
|
15
|
+
path: `${__dirname}/../continuum/${fileName}.js`
|
|
16
|
+
})
|
|
17
|
+
.catch(error => {
|
|
18
|
+
console.log(`ERROR adding the ${fileName} script to the page (${error.message})`);
|
|
19
|
+
result.prevented = true;
|
|
20
|
+
result.error = `ERROR adding the ${fileName} script to the page`;
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
if (! result.prevented) {
|
|
25
|
+
// Run the Continuum ruleset and get the result, failing if none within 20 seconds.
|
|
26
|
+
result = await page.evaluate(async () => {
|
|
27
|
+
continuum.setUp(null, null, window);
|
|
28
|
+
const bigResultPromise = continuum.runAllTests();
|
|
29
|
+
const deadlinePromise = new Promise(resolve => {
|
|
30
|
+
setTimeout(() => {
|
|
31
|
+
resolve('timeout');
|
|
32
|
+
}, 20000);
|
|
33
|
+
});
|
|
34
|
+
const bigResult = await Promise.race([bigResultPromise, deadlinePromise]);
|
|
35
|
+
if (Array.isArray(bigResult)) {
|
|
36
|
+
return bigResult.map(bigItem => {
|
|
37
|
+
const item = bigItem._rawEngineJsonObject;
|
|
38
|
+
delete item.fingerprint.encoding;
|
|
39
|
+
if (item.element.length > 200) {
|
|
40
|
+
item.element = `${item.element.slice(0, 100)} ... ${item.element.slice(-100)}`;
|
|
41
|
+
}
|
|
42
|
+
return item;
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
else if (bigResult === 'timeout') {
|
|
46
|
+
return {
|
|
47
|
+
prevented: true,
|
|
48
|
+
error: 'ERROR: Running all tests timed out'
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
return {
|
|
53
|
+
prevented: true,
|
|
54
|
+
error: 'ERROR: Invalid result'
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
return {result};
|
|
60
|
+
};
|