testaro 32.2.0 → 32.2.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/package.json +1 -1
- package/run.js +2 -0
- package/tests/qualWeb.js +116 -104
package/package.json
CHANGED
package/run.js
CHANGED
|
@@ -422,6 +422,8 @@ const launch = async (report, typeName, url, debug, waits, isLowMotion = false)
|
|
|
422
422
|
// Open a context (i.e. browser tab), with reduced motion if specified.
|
|
423
423
|
const options = {reduceMotion: isLowMotion ? 'reduce' : 'no-preference'};
|
|
424
424
|
const browserContext = await browser.newContext(options);
|
|
425
|
+
// Prevent default timeouts, including those arising from a Playwright bug.
|
|
426
|
+
browserContext.setDefaultTimeout(0);
|
|
425
427
|
// When a page (i.e. browser tab) is added to the browser context (i.e. browser window):
|
|
426
428
|
browserContext.on('page', async page => {
|
|
427
429
|
// If it emits a message:
|
package/tests/qualWeb.js
CHANGED
|
@@ -42,6 +42,7 @@ const clusterOptions = {
|
|
|
42
42
|
exports.reporter = async (page, options) => {
|
|
43
43
|
const {withNewContent, rules} = options;
|
|
44
44
|
const data = {};
|
|
45
|
+
let result = {};
|
|
45
46
|
// Start the QualWeb core engine.
|
|
46
47
|
await qualWeb.start(clusterOptions);
|
|
47
48
|
// Specify the invariant test options.
|
|
@@ -61,143 +62,154 @@ exports.reporter = async (page, options) => {
|
|
|
61
62
|
}
|
|
62
63
|
};
|
|
63
64
|
// Specify a URL or provide the content.
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
else {
|
|
68
|
-
qualWebOptions.html = await page.content();
|
|
69
|
-
}
|
|
70
|
-
// Specify which rules to test for.
|
|
71
|
-
const actSpec = rules ? rules.find(typeRules => typeRules.startsWith('act:')) : null;
|
|
72
|
-
const wcagSpec = rules ? rules.find(typeRules => typeRules.startsWith('wcag:')) : null;
|
|
73
|
-
const bestSpec = rules ? rules.find(typeRules => typeRules.startsWith('best:')) : null;
|
|
74
|
-
if (actSpec) {
|
|
75
|
-
if (actSpec === 'act:') {
|
|
76
|
-
qualWebOptions.execute.act = false;
|
|
65
|
+
try {
|
|
66
|
+
if (withNewContent) {
|
|
67
|
+
qualWebOptions.url = page.url();
|
|
77
68
|
}
|
|
78
69
|
else {
|
|
79
|
-
|
|
80
|
-
|
|
70
|
+
qualWebOptions.html = await page.content();
|
|
71
|
+
}
|
|
72
|
+
// Specify which rules to test for.
|
|
73
|
+
const actSpec = rules ? rules.find(typeRules => typeRules.startsWith('act:')) : null;
|
|
74
|
+
const wcagSpec = rules ? rules.find(typeRules => typeRules.startsWith('wcag:')) : null;
|
|
75
|
+
const bestSpec = rules ? rules.find(typeRules => typeRules.startsWith('best:')) : null;
|
|
76
|
+
if (actSpec) {
|
|
77
|
+
if (actSpec === 'act:') {
|
|
78
|
+
qualWebOptions.execute.act = false;
|
|
79
|
+
}
|
|
80
|
+
else {
|
|
81
|
+
const actRules = actSpec.slice(4).split(',').map(num => `QW-ACT-R${num}`);
|
|
82
|
+
qualWebOptions['act-rules'] = {rules: actRules};
|
|
83
|
+
qualWebOptions.execute.act = true;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
qualWebOptions['act-rules'] = {
|
|
88
|
+
levels: ['A', 'AA', 'AAA'],
|
|
89
|
+
principles: ['Perceivable', 'Operable', 'Understandable', 'Robust']
|
|
90
|
+
};
|
|
81
91
|
qualWebOptions.execute.act = true;
|
|
82
92
|
}
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
if (wcagSpec === 'wcag:') {
|
|
93
|
-
qualWebOptions.execute.wcag = false;
|
|
93
|
+
if (wcagSpec) {
|
|
94
|
+
if (wcagSpec === 'wcag:') {
|
|
95
|
+
qualWebOptions.execute.wcag = false;
|
|
96
|
+
}
|
|
97
|
+
else {
|
|
98
|
+
const wcagTechniques = wcagSpec.slice(5).split(',').map(num => `QW-WCAG-T${num}`);
|
|
99
|
+
qualWebOptions['wcag-techniques'] = {techniques: wcagTechniques};
|
|
100
|
+
qualWebOptions.execute.wcag = true;
|
|
101
|
+
}
|
|
94
102
|
}
|
|
95
103
|
else {
|
|
96
|
-
|
|
97
|
-
|
|
104
|
+
qualWebOptions['wcag-techniques'] = {
|
|
105
|
+
levels: ['A', 'AA', 'AAA'],
|
|
106
|
+
principles: ['Perceivable', 'Operable', 'Understandable', 'Robust']
|
|
107
|
+
};
|
|
98
108
|
qualWebOptions.execute.wcag = true;
|
|
99
109
|
}
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
110
|
+
if (bestSpec) {
|
|
111
|
+
if (bestSpec === 'best:') {
|
|
112
|
+
qualWebOptions.execute.bp = false;
|
|
113
|
+
}
|
|
114
|
+
else {
|
|
115
|
+
const bestPractices = bestSpec.slice(5).split(',').map(num => `QW-BP${num}`);
|
|
116
|
+
qualWebOptions['best-practices'] = {bestPractices};
|
|
117
|
+
// qualWebOptions.execute.bp = true;
|
|
118
|
+
// Temporarily disable best practices, because they crash QualWeb.
|
|
119
|
+
qualWebOptions.execute.bp = false;
|
|
120
|
+
}
|
|
111
121
|
}
|
|
112
122
|
else {
|
|
113
|
-
const bestPractices = bestSpec.slice(5).split(',').map(num => `QW-BP${num}`);
|
|
114
|
-
qualWebOptions['best-practices'] = {bestPractices};
|
|
115
123
|
// qualWebOptions.execute.bp = true;
|
|
116
124
|
// Temporarily disable best practices, because they crash QualWeb.
|
|
117
125
|
qualWebOptions.execute.bp = false;
|
|
118
126
|
}
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
//
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
// Remove passing results.
|
|
142
|
-
const ruleAssertions = assertions[ruleID];
|
|
143
|
-
const {metadata} = ruleAssertions;
|
|
144
|
-
if (metadata) {
|
|
145
|
-
if (metadata.warning === 0 && metadata.failed === 0) {
|
|
146
|
-
delete assertions[ruleID];
|
|
147
|
-
}
|
|
148
|
-
else {
|
|
149
|
-
if (ruleAssertions.results) {
|
|
150
|
-
ruleAssertions.results = ruleAssertions.results.filter(
|
|
151
|
-
raResult => raResult.verdict !== 'passed'
|
|
152
|
-
);
|
|
127
|
+
// Get the report.
|
|
128
|
+
let actReports = await qualWeb.evaluate(qualWebOptions);
|
|
129
|
+
// Remove the copy of the DOM from it.
|
|
130
|
+
result = actReports[withNewContent ? qualWebOptions.url : 'customHtml'];
|
|
131
|
+
if (result && result.system && result.system.page && result.system.page.dom) {
|
|
132
|
+
delete result.system.page.dom;
|
|
133
|
+
// For each test section of the act report:
|
|
134
|
+
const {modules} = result;
|
|
135
|
+
if (modules) {
|
|
136
|
+
for (const section of ['act-rules', 'wcag-techniques', 'best-practices']) {
|
|
137
|
+
if (qualWebOptions[section]) {
|
|
138
|
+
if (modules[section]) {
|
|
139
|
+
const {assertions} = modules[section];
|
|
140
|
+
if (assertions) {
|
|
141
|
+
const ruleIDs = Object.keys(assertions);
|
|
142
|
+
ruleIDs.forEach(ruleID => {
|
|
143
|
+
// Remove passing results.
|
|
144
|
+
const ruleAssertions = assertions[ruleID];
|
|
145
|
+
const {metadata} = ruleAssertions;
|
|
146
|
+
if (metadata) {
|
|
147
|
+
if (metadata.warning === 0 && metadata.failed === 0) {
|
|
148
|
+
delete assertions[ruleID];
|
|
153
149
|
}
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
const {elements} = raResult;
|
|
160
|
-
if (elements && elements.length) {
|
|
161
|
-
elements.forEach(element => {
|
|
162
|
-
if (element.htmlCode && element.htmlCode.length > 700) {
|
|
163
|
-
element.htmlCode = `${element.htmlCode.slice(0, 700)} …`;
|
|
150
|
+
else {
|
|
151
|
+
if (ruleAssertions.results) {
|
|
152
|
+
ruleAssertions.results = ruleAssertions.results.filter(
|
|
153
|
+
raResult => raResult.verdict !== 'passed'
|
|
154
|
+
);
|
|
164
155
|
}
|
|
165
|
-
}
|
|
156
|
+
}
|
|
166
157
|
}
|
|
158
|
+
// Shorten long HTML codes of elements.
|
|
159
|
+
const {results} = ruleAssertions;
|
|
160
|
+
results.forEach(raResult => {
|
|
161
|
+
const {elements} = raResult;
|
|
162
|
+
if (elements && elements.length) {
|
|
163
|
+
elements.forEach(element => {
|
|
164
|
+
if (element.htmlCode && element.htmlCode.length > 700) {
|
|
165
|
+
element.htmlCode = `${element.htmlCode.slice(0, 700)} …`;
|
|
166
|
+
}
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
});
|
|
167
170
|
});
|
|
168
|
-
}
|
|
171
|
+
}
|
|
172
|
+
else {
|
|
173
|
+
data.prevented = true;
|
|
174
|
+
data.error = 'ERROR: No assertions';
|
|
175
|
+
}
|
|
169
176
|
}
|
|
170
177
|
else {
|
|
171
178
|
data.prevented = true;
|
|
172
|
-
data.error =
|
|
179
|
+
data.error = `ERROR: No ${section} section`;
|
|
173
180
|
}
|
|
174
181
|
}
|
|
175
|
-
else {
|
|
176
|
-
data.prevented = true;
|
|
177
|
-
data.error = `ERROR: No ${section} section`;
|
|
178
|
-
}
|
|
179
182
|
}
|
|
180
183
|
}
|
|
184
|
+
else {
|
|
185
|
+
data.prevented = true;
|
|
186
|
+
data.error = 'ERROR: No modules';
|
|
187
|
+
}
|
|
181
188
|
}
|
|
182
189
|
else {
|
|
183
190
|
data.prevented = true;
|
|
184
|
-
data.error = 'ERROR: No
|
|
191
|
+
data.error = 'ERROR: No DOM';
|
|
185
192
|
}
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
193
|
+
// Stop the QualWeb core engine.
|
|
194
|
+
await qualWeb.stop();
|
|
195
|
+
// Return the result.
|
|
196
|
+
try {
|
|
197
|
+
JSON.stringify(result);
|
|
198
|
+
}
|
|
199
|
+
catch(error) {
|
|
200
|
+
const message = `ERROR: qualWeb result cannot be made JSON (${error.message})`;
|
|
201
|
+
data.prevented = true;
|
|
202
|
+
data.error = message;
|
|
203
|
+
};
|
|
196
204
|
}
|
|
197
205
|
catch(error) {
|
|
198
|
-
const message =
|
|
206
|
+
const message = error.message.slice(0, 200);
|
|
199
207
|
data.prevented = true;
|
|
200
208
|
data.error = message;
|
|
209
|
+
result = {
|
|
210
|
+
prevented: true,
|
|
211
|
+
error: message
|
|
212
|
+
};
|
|
201
213
|
};
|
|
202
214
|
return {
|
|
203
215
|
data,
|