testaro 45.0.0 → 45.0.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 +1 -1
- package/package.json +1 -1
- package/procs/job.js +29 -4
- package/run.js +27 -57
- package/tests/alfa.js +81 -67
- package/tests/aslint.js +8 -7
- package/tests/axe.js +64 -54
- package/tests/ed11y.js +12 -7
- package/tests/htmlcs.js +4 -3
- package/tests/ibm.js +54 -26
- package/tests/nuVal.js +3 -2
- package/tests/qualWeb.js +68 -63
- package/tests/testaro.js +4 -3
- package/tests/wave.js +30 -31
package/README.md
CHANGED
|
@@ -250,7 +250,7 @@ When the texts of multiple elements of the same type will contain the same `whic
|
|
|
250
250
|
|
|
251
251
|
#### Navigations
|
|
252
252
|
|
|
253
|
-
An example of a **navigation** is the act of type `launch` in the job example above. That `launch` act has only a `type` property. If you want a particular `launch` act to use a different browser type or to navigate to a different target from the job defaults, the `launch` act can have a `browserID` and/or a `
|
|
253
|
+
An example of a **navigation** is the act of type `launch` in the job example above. That `launch` act has only a `type` property. If you want a particular `launch` act to use a different browser type or to navigate to a different target URL from the job defaults, the `launch` act can have a `browserID` and/or a `url` property.
|
|
254
254
|
|
|
255
255
|
If any act alters the page, you can restore the page to its original state for the next act by inserting a new `launch` act (and, if necessary, additional page-specific acts) between them.
|
|
256
256
|
|
package/package.json
CHANGED
package/procs/job.js
CHANGED
|
@@ -115,12 +115,14 @@ const hasSubtype = (variable, subtype) => {
|
|
|
115
115
|
return true;
|
|
116
116
|
}
|
|
117
117
|
};
|
|
118
|
+
// Validates a device ID.
|
|
119
|
+
const isDeviceID = exports.isDeviceID = deviceID => deviceID === 'default' || !! devices[deviceID];
|
|
118
120
|
// Validates a browser type.
|
|
119
121
|
const isBrowserID = exports.isBrowserID = type => ['chromium', 'firefox', 'webkit'].includes(type);
|
|
120
122
|
// Validates a load state.
|
|
121
123
|
const isState = string => ['loaded', 'idle'].includes(string);
|
|
122
124
|
// Validates a URL.
|
|
123
|
-
const isURL = string => /^(?:https?|file):\/\/[^\s]+$/.test(string);
|
|
125
|
+
const isURL = exports.isURL = string => /^(?:https?|file):\/\/[^\s]+$/.test(string);
|
|
124
126
|
// Validates a focusable tag name.
|
|
125
127
|
const isFocusable = string => ['a', 'button', 'input', 'select'].includes(string);
|
|
126
128
|
// Returns whether all elements of an array are numbers.
|
|
@@ -176,8 +178,6 @@ const isValidAct = exports.isValidAct = act => {
|
|
|
176
178
|
return false;
|
|
177
179
|
}
|
|
178
180
|
};
|
|
179
|
-
// Returns whether a device ID is valid.
|
|
180
|
-
const isDeviceID = deviceID => deviceID === 'default' || !! devices[deviceID];
|
|
181
181
|
// Returns blank if a job is valid, or an error message.
|
|
182
182
|
exports.isValidJob = job => {
|
|
183
183
|
// If any job was provided:
|
|
@@ -215,7 +215,7 @@ exports.isValidJob = job => {
|
|
|
215
215
|
if (typeof observe !== 'boolean') {
|
|
216
216
|
return 'Bad job observe';
|
|
217
217
|
}
|
|
218
|
-
if (
|
|
218
|
+
if (! isDeviceID(device.id)) {
|
|
219
219
|
return 'Bad job deviceID';
|
|
220
220
|
}
|
|
221
221
|
if (! isBrowserID(browserID)) {
|
|
@@ -264,3 +264,28 @@ exports.isValidJob = job => {
|
|
|
264
264
|
return 'no job';
|
|
265
265
|
}
|
|
266
266
|
};
|
|
267
|
+
// Executes an asynchronous function with a time limit.
|
|
268
|
+
exports.doBy = async function(timeLimit, obj, fnName, fnArgs, noticePrefix) {
|
|
269
|
+
let timer;
|
|
270
|
+
// Start a timer.
|
|
271
|
+
const timerPromise = new Promise(resolve => {
|
|
272
|
+
timer = setTimeout(() => {
|
|
273
|
+
console.log(`ERROR: ${noticePrefix} timed out at ${timeLimit} seconds`);
|
|
274
|
+
resolve('timedOut');
|
|
275
|
+
}, 1000 * timeLimit);
|
|
276
|
+
});
|
|
277
|
+
// Start the function execution.
|
|
278
|
+
/*
|
|
279
|
+
const fnPromise = new Promise(async resolve => {
|
|
280
|
+
resolve(await fn(... fnArgs));
|
|
281
|
+
});
|
|
282
|
+
*/
|
|
283
|
+
const fnPromise = new Promise(async function(resolve) {
|
|
284
|
+
resolve(await obj[fnName](... fnArgs));
|
|
285
|
+
});
|
|
286
|
+
// Get the timeout or the value returned by the function, whichever is first.
|
|
287
|
+
const result = await Promise.race([timerPromise, fnPromise]);
|
|
288
|
+
clearTimeout(timer);
|
|
289
|
+
// Return the result.
|
|
290
|
+
return result;
|
|
291
|
+
};
|
package/run.js
CHANGED
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
// Module to keep secrets.
|
|
31
31
|
require('dotenv').config();
|
|
32
32
|
// Module to validate jobs.
|
|
33
|
-
const {isBrowserID, isValidJob, tools} = require('./procs/job');
|
|
33
|
+
const {isBrowserID, isDeviceID, isURL, isValidJob, tools} = require('./procs/job');
|
|
34
34
|
// Module to standardize report formats.
|
|
35
35
|
const {standardize} = require('./procs/standardize');
|
|
36
36
|
// Module to identify element bounding boxes.
|
|
@@ -191,15 +191,15 @@ const browserClose = async () => {
|
|
|
191
191
|
}
|
|
192
192
|
};
|
|
193
193
|
// Launches a browser, navigates to a URL, and returns browser data.
|
|
194
|
-
const launch = async (report, debug, waits, tempBrowserID,
|
|
195
|
-
const {
|
|
196
|
-
|
|
197
|
-
browserID
|
|
198
|
-
const
|
|
199
|
-
// If the specified browser
|
|
200
|
-
if (isBrowserID(browserID)) {
|
|
194
|
+
const launch = async (report, debug, waits, tempBrowserID, tempURL) => {
|
|
195
|
+
const {device} = report;
|
|
196
|
+
const deviceID = device && device.id;
|
|
197
|
+
const browserID = tempBrowserID || report.browserID || '';
|
|
198
|
+
const url = tempURL || report.target && report.target.url || '';
|
|
199
|
+
// If the specified browser and device types and URL exist:
|
|
200
|
+
if (isBrowserID(browserID) && isDeviceID(deviceID) && isURL(url)) {
|
|
201
201
|
// Create a browser of the specified or default type.
|
|
202
|
-
const browserType = require('playwright')[
|
|
202
|
+
const browserType = require('playwright')[browserID];
|
|
203
203
|
// Close the current browser, if any.
|
|
204
204
|
await browserClose();
|
|
205
205
|
// Define browser options.
|
|
@@ -222,7 +222,7 @@ const launch = async (report, debug, waits, tempBrowserID, tempTarget) => {
|
|
|
222
222
|
error: 'Browser launch failed'
|
|
223
223
|
};
|
|
224
224
|
});
|
|
225
|
-
// Open a context (i.e. browser
|
|
225
|
+
// Open a context (i.e. browser window).
|
|
226
226
|
const browserContext = await browser.newContext(device.windowOptions);
|
|
227
227
|
// Prevent default timeouts.
|
|
228
228
|
browserContext.setDefaultTimeout(0);
|
|
@@ -325,13 +325,13 @@ const launch = async (report, debug, waits, tempBrowserID, tempTarget) => {
|
|
|
325
325
|
};
|
|
326
326
|
}
|
|
327
327
|
}
|
|
328
|
-
// Otherwise, i.e. if
|
|
328
|
+
// Otherwise, i.e. if the browser or device ID is invalid:
|
|
329
329
|
else {
|
|
330
330
|
// Return this.
|
|
331
|
-
console.log(`ERROR: Browser
|
|
331
|
+
console.log(`ERROR: Browser ${browserID}, device ${deviceID}, or URL ${url} invalid`);
|
|
332
332
|
return {
|
|
333
333
|
success: false,
|
|
334
|
-
error: `${browserID} browser launch failed`
|
|
334
|
+
error: `${browserID} browser launch with ${deviceID} device and navigation to ${url} failed`
|
|
335
335
|
};
|
|
336
336
|
}
|
|
337
337
|
};
|
|
@@ -611,8 +611,8 @@ const doActs = async (report, actIndex, page) => {
|
|
|
611
611
|
report,
|
|
612
612
|
debug,
|
|
613
613
|
waits,
|
|
614
|
-
act.browserID || report.browserID,
|
|
615
|
-
act.
|
|
614
|
+
act.browserID || report.browserID || '',
|
|
615
|
+
act.url || report.target && report.target.url || ''
|
|
616
616
|
);
|
|
617
617
|
// If the launch and navigation succeeded:
|
|
618
618
|
if (launchResult && launchResult.success) {
|
|
@@ -809,55 +809,25 @@ const doActs = async (report, actIndex, page) => {
|
|
|
809
809
|
else if (act.type === 'test') {
|
|
810
810
|
// Add a description of the tool to the act.
|
|
811
811
|
act.what = tools[act.which];
|
|
812
|
-
// Initialize the options argument.
|
|
813
|
-
const options = {
|
|
814
|
-
report,
|
|
815
|
-
act
|
|
816
|
-
};
|
|
817
|
-
// Add any specified arguments to it.
|
|
818
|
-
Object.keys(act).forEach(key => {
|
|
819
|
-
if (! ['type', 'which'].includes(key)) {
|
|
820
|
-
options[key] = act[key];
|
|
821
|
-
}
|
|
822
|
-
});
|
|
823
812
|
// Get the start time of the act.
|
|
824
813
|
const startTime = Date.now();
|
|
825
|
-
let timer;
|
|
826
814
|
try {
|
|
827
|
-
//
|
|
828
|
-
let timeoutReport = 'onTime';
|
|
815
|
+
// Get the time limit in milliseconds for the act.
|
|
829
816
|
const timeLimit = 1000 * timeLimits[act.which] || 15000;
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
// Try to perform the specified tests of the tool and get a report.
|
|
841
|
-
const actReport = require(`./tests/${act.which}`).reporter(page, options);
|
|
842
|
-
const raceReport = await Promise.race([timeoutReport, actReport]);
|
|
843
|
-
// If the act was finished without timing out:
|
|
844
|
-
if (raceReport !== 'timedOut') {
|
|
845
|
-
// Disable the timer.
|
|
846
|
-
clearTimeout(timer);
|
|
847
|
-
// Import the test results and process data into the act.
|
|
848
|
-
act.result = raceReport && raceReport.result || {};
|
|
849
|
-
act.data = raceReport && raceReport.data || {};
|
|
850
|
-
// If the page prevented the tool from operating:
|
|
851
|
-
if (act.data.prevented) {
|
|
852
|
-
// Add prevention data to the job data.
|
|
853
|
-
report.jobData.preventions[act.which] = act.data.error;
|
|
854
|
-
}
|
|
817
|
+
// Perform the specified tests of the tool.
|
|
818
|
+
const actReport = await require(`./tests/${act.which}`)
|
|
819
|
+
.reporter(page, report, actIndex, timeLimit);
|
|
820
|
+
// Add the data and result to the act.
|
|
821
|
+
act.data = actReport.data;
|
|
822
|
+
act.result = actReport.result;
|
|
823
|
+
// If the tool reported that the page prevented testing:
|
|
824
|
+
if (actReport.data.prevented) {
|
|
825
|
+
// Add prevention data to the job data.
|
|
826
|
+
report.jobData.preventions[act.which] = act.data.error;
|
|
855
827
|
}
|
|
856
828
|
}
|
|
857
|
-
// If the
|
|
829
|
+
// If the tool invocation failed:
|
|
858
830
|
catch(error) {
|
|
859
|
-
// Disable the timer.
|
|
860
|
-
clearTimeout(timer);
|
|
861
831
|
// Report the failure.
|
|
862
832
|
const message = error.message.slice(0, 400);
|
|
863
833
|
console.log(`ERROR: Test act ${act.which} failed (${message})`);
|
package/tests/alfa.js
CHANGED
|
@@ -30,19 +30,20 @@
|
|
|
30
30
|
const {Audit} = require('@siteimprove/alfa-act');
|
|
31
31
|
const {Playwright} = require('@siteimprove/alfa-playwright');
|
|
32
32
|
let alfaRules = require('@siteimprove/alfa-rules').default;
|
|
33
|
+
const {doBy} = require('../procs/job');
|
|
33
34
|
|
|
34
35
|
// FUNCTIONS
|
|
35
36
|
|
|
36
37
|
// Conducts and reports the alfa tests.
|
|
37
|
-
exports.reporter = async (page,
|
|
38
|
-
const
|
|
38
|
+
exports.reporter = async (page, report, actIndex, timeLimit) => {
|
|
39
|
+
const act = report.acts[actIndex];
|
|
39
40
|
const {rules} = act;
|
|
40
41
|
// If only some rules are to be employed:
|
|
41
42
|
if (rules && rules.length) {
|
|
42
43
|
// Remove the other rules.
|
|
43
44
|
alfaRules = alfaRules.filter(rule => rules.includes(rule.uri.replace(/^.+-/, '')));
|
|
44
45
|
}
|
|
45
|
-
//
|
|
46
|
+
// Open a page for the summaries of the alfa rules.
|
|
46
47
|
const context = page.context();
|
|
47
48
|
const rulePage = await context.newPage();
|
|
48
49
|
rulePage.on('console', msg => {
|
|
@@ -59,8 +60,12 @@ exports.reporter = async (page, options) => {
|
|
|
59
60
|
items: []
|
|
60
61
|
};
|
|
61
62
|
try {
|
|
62
|
-
|
|
63
|
+
// Get the Alfa rules.
|
|
64
|
+
const response = await rulePage.goto(
|
|
65
|
+
'https://alfa.siteimprove.com/rules', {timeout: Math.round(1000 * timeLimit / 2)}
|
|
66
|
+
);
|
|
63
67
|
let ruleData = {};
|
|
68
|
+
// If they were obtained:
|
|
64
69
|
if (response.status() === 200) {
|
|
65
70
|
// Compile data on the rule IDs and summaries.
|
|
66
71
|
ruleData = await rulePage.evaluate(() => {
|
|
@@ -86,75 +91,84 @@ exports.reporter = async (page, options) => {
|
|
|
86
91
|
const doc = await page.evaluateHandle('document');
|
|
87
92
|
const alfaPage = await Playwright.toPage(doc);
|
|
88
93
|
const audit = Audit.of(alfaPage, alfaRules);
|
|
89
|
-
const outcomes = Array.from(await audit
|
|
90
|
-
//
|
|
91
|
-
outcomes
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
const
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
codeLines.
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
codeLines.splice(1, codeLines.length - 2, '...');
|
|
109
|
-
}
|
|
110
|
-
const outcomeData = {
|
|
111
|
-
index,
|
|
112
|
-
verdict,
|
|
113
|
-
rule: {
|
|
114
|
-
ruleID,
|
|
115
|
-
ruleSummary,
|
|
116
|
-
scope: '',
|
|
117
|
-
uri,
|
|
118
|
-
requirements
|
|
119
|
-
},
|
|
120
|
-
target: {
|
|
121
|
-
type: targetJ.type,
|
|
122
|
-
tagName: targetJ.name || '',
|
|
123
|
-
path: target.path(),
|
|
124
|
-
codeLines: codeLines.map(line => line.length > 300 ? `${line.slice(0, 300)}...` : line)
|
|
94
|
+
const outcomes = Array.from(await doBy(timeLimit, audit, 'evaluate', [], 'alfa testing'));
|
|
95
|
+
// If the testing finished on time:
|
|
96
|
+
if (outcomes !== 'timedOut') {
|
|
97
|
+
// For each failure or warning:
|
|
98
|
+
outcomes.forEach((outcome, index) => {
|
|
99
|
+
const {target} = outcome;
|
|
100
|
+
if (target && ! target._members) {
|
|
101
|
+
const outcomeJ = outcome.toJSON();
|
|
102
|
+
const verdict = outcomeJ.outcome;
|
|
103
|
+
if (verdict !== 'passed') {
|
|
104
|
+
// Add to the result.
|
|
105
|
+
const {rule} = outcomeJ;
|
|
106
|
+
const {tags, uri, requirements} = rule;
|
|
107
|
+
const ruleID = uri.replace(/^.+-/, '');
|
|
108
|
+
const ruleSummary = ruleData[ruleID] || '';
|
|
109
|
+
const targetJ = outcomeJ.target;
|
|
110
|
+
const codeLines = target.toString().split('\n');
|
|
111
|
+
if (codeLines[0] === '#document') {
|
|
112
|
+
codeLines.splice(2, codeLines.length - 3, '...');
|
|
125
113
|
}
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
if (outcomeData.rule.ruleSummary === '') {
|
|
129
|
-
// If a first requirement title exists:
|
|
130
|
-
const {requirements} = outcomeData.rule;
|
|
131
|
-
if (requirements && requirements.length && requirements[0].title) {
|
|
132
|
-
// Make it the rule summary.
|
|
133
|
-
outcomeData.rule.ruleSummary = requirements[0].title;
|
|
114
|
+
else if (codeLines[0].startsWith('<html')) {
|
|
115
|
+
codeLines.splice(1, codeLines.length - 2, '...');
|
|
134
116
|
}
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
117
|
+
const outcomeData = {
|
|
118
|
+
index,
|
|
119
|
+
verdict,
|
|
120
|
+
rule: {
|
|
121
|
+
ruleID,
|
|
122
|
+
ruleSummary,
|
|
123
|
+
scope: '',
|
|
124
|
+
uri,
|
|
125
|
+
requirements
|
|
126
|
+
},
|
|
127
|
+
target: {
|
|
128
|
+
type: targetJ.type,
|
|
129
|
+
tagName: targetJ.name || '',
|
|
130
|
+
path: target.path(),
|
|
131
|
+
codeLines: codeLines.map(line => line.length > 300 ? `${line.slice(0, 300)}...` : line)
|
|
132
|
+
}
|
|
133
|
+
};
|
|
134
|
+
// If the rule summary is missing:
|
|
135
|
+
if (outcomeData.rule.ruleSummary === '') {
|
|
136
|
+
// If a first requirement title exists:
|
|
137
|
+
const {requirements} = outcomeData.rule;
|
|
138
|
+
if (requirements && requirements.length && requirements[0].title) {
|
|
139
|
+
// Make it the rule summary.
|
|
140
|
+
outcomeData.rule.ruleSummary = requirements[0].title;
|
|
141
|
+
}
|
|
140
142
|
}
|
|
141
|
-
|
|
142
|
-
|
|
143
|
+
const etcTags = [];
|
|
144
|
+
tags.forEach(tag => {
|
|
145
|
+
if (tag.type === 'scope') {
|
|
146
|
+
outcomeData.rule.scope = tag.scope;
|
|
147
|
+
}
|
|
148
|
+
else {
|
|
149
|
+
etcTags.push(tag);
|
|
150
|
+
}
|
|
151
|
+
});
|
|
152
|
+
if (etcTags.length) {
|
|
153
|
+
outcomeData.etcTags = etcTags;
|
|
143
154
|
}
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
else if (outcomeData.verdict === 'cantTell') {
|
|
152
|
-
result.totals.warnings++;
|
|
155
|
+
if (outcomeData.verdict === 'failed') {
|
|
156
|
+
result.totals.failures++;
|
|
157
|
+
}
|
|
158
|
+
else if (outcomeData.verdict === 'cantTell') {
|
|
159
|
+
result.totals.warnings++;
|
|
160
|
+
}
|
|
161
|
+
result.items.push(outcomeData);
|
|
153
162
|
}
|
|
154
|
-
result.items.push(outcomeData);
|
|
155
163
|
}
|
|
156
|
-
}
|
|
157
|
-
}
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
// Otherwise, i.e. if the testing timed out:
|
|
167
|
+
else {
|
|
168
|
+
// Report this.
|
|
169
|
+
data.prevented = true;
|
|
170
|
+
data.error = 'ERROR: Act timed out';
|
|
171
|
+
}
|
|
158
172
|
}
|
|
159
173
|
catch(error) {
|
|
160
174
|
console.log(`ERROR: navigation to URL timed out (${error})`);
|
package/tests/aslint.js
CHANGED
|
@@ -33,7 +33,7 @@ const fs = require('fs/promises');
|
|
|
33
33
|
// FUNCTIONS
|
|
34
34
|
|
|
35
35
|
// Conducts and reports the ASLint tests.
|
|
36
|
-
exports.reporter = async (page,
|
|
36
|
+
exports.reporter = async (page, report, actIndex, timeLimit) => {
|
|
37
37
|
// Initialize the act report.
|
|
38
38
|
let data = {};
|
|
39
39
|
let result = {};
|
|
@@ -43,7 +43,7 @@ exports.reporter = async (page, options) => {
|
|
|
43
43
|
`${__dirname}/../node_modules/aslint-testaro/aslint.bundle.js`, 'utf8'
|
|
44
44
|
);
|
|
45
45
|
// Get the nonce, if any.
|
|
46
|
-
const
|
|
46
|
+
const act = report.acts[actIndex];
|
|
47
47
|
const {jobData} = report;
|
|
48
48
|
const scriptNonce = jobData && jobData.lastScriptNonce;
|
|
49
49
|
// Inject the ASLint bundle and runner into the page.
|
|
@@ -73,17 +73,18 @@ exports.reporter = async (page, options) => {
|
|
|
73
73
|
data.prevented = true;
|
|
74
74
|
data.error = message;
|
|
75
75
|
});
|
|
76
|
-
// If the injection succeeded:
|
|
77
76
|
const reportLoc = page.locator('#aslintResult');
|
|
77
|
+
// If the injection succeeded:
|
|
78
78
|
if (! data.prevented) {
|
|
79
|
-
//
|
|
79
|
+
// Get the test results.
|
|
80
80
|
await reportLoc.waitFor({
|
|
81
81
|
state: 'attached',
|
|
82
|
-
timeout:
|
|
82
|
+
timeout: 1000 * timeLimit
|
|
83
83
|
})
|
|
84
84
|
.catch(error => {
|
|
85
|
-
const message
|
|
86
|
-
|
|
85
|
+
const message
|
|
86
|
+
= `aslint testing timed out at ${timeLimit} seconds (${error.message.slice(0, 400)})`;
|
|
87
|
+
console.log(`ERROR: ${message}`);
|
|
87
88
|
data.prevented = true;
|
|
88
89
|
data.error = message;
|
|
89
90
|
});
|
package/tests/axe.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*
|
|
2
|
-
© 2021–
|
|
2
|
+
© 2021–2024 CVS Health and/or one of its affiliates. All rights reserved.
|
|
3
3
|
|
|
4
4
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
5
5
|
of this software and associated documentation files (the "Software"), to deal
|
|
@@ -43,13 +43,16 @@
|
|
|
43
43
|
|
|
44
44
|
// IMPORTS
|
|
45
45
|
|
|
46
|
-
const
|
|
46
|
+
const axePlaywright = require('axe-playwright');
|
|
47
|
+
const {injectAxe} = axePlaywright;
|
|
48
|
+
const {doBy} = require('../procs/job');
|
|
47
49
|
|
|
48
50
|
// FUNCTIONS
|
|
49
51
|
|
|
50
52
|
// Conducts and reports the Axe tests.
|
|
51
|
-
exports.reporter = async (page,
|
|
52
|
-
const
|
|
53
|
+
exports.reporter = async (page, report, actIndex, timeLimit) => {
|
|
54
|
+
const act = report.acts[actIndex];
|
|
55
|
+
const {detailLevel, rules} = act;
|
|
53
56
|
// Initialize the act report.
|
|
54
57
|
let data = {};
|
|
55
58
|
let result = {};
|
|
@@ -72,62 +75,69 @@ exports.reporter = async (page, options) => {
|
|
|
72
75
|
else {
|
|
73
76
|
axeOptions.runOnly = ['experimental', 'best-practice', 'wcag2a', 'wcag2aa', 'wcag2aaa', 'wcag21a', 'wcag21aa', 'wcag21aaa'];
|
|
74
77
|
}
|
|
75
|
-
const axeReport = await
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
78
|
+
const axeReport = await doBy(
|
|
79
|
+
timeLimit, axePlaywright, 'getAxeResults', [page, null, axeOptions], 'axe testing'
|
|
80
|
+
);
|
|
81
|
+
// If the testing finished on time:
|
|
82
|
+
if (axeReport !== 'timedOut') {
|
|
83
|
+
const {inapplicable, passes, incomplete, violations} = axeReport;
|
|
84
|
+
// If the test succeeded:
|
|
85
|
+
if (violations) {
|
|
86
|
+
// Initialize the result.
|
|
87
|
+
result.totals = {
|
|
88
|
+
rulesNA: 0,
|
|
89
|
+
rulesPassed: 0,
|
|
90
|
+
rulesWarned: 0,
|
|
91
|
+
rulesViolated: 0,
|
|
92
|
+
warnings: {
|
|
93
|
+
minor: 0,
|
|
94
|
+
moderate: 0,
|
|
95
|
+
serious: 0,
|
|
96
|
+
critical: 0
|
|
97
|
+
},
|
|
98
|
+
violations: {
|
|
99
|
+
minor: 0,
|
|
100
|
+
moderate: 0,
|
|
101
|
+
serious: 0,
|
|
102
|
+
critical: 0
|
|
103
|
+
}
|
|
104
|
+
};
|
|
105
|
+
result.details = axeReport;
|
|
106
|
+
// Populate the totals.
|
|
107
|
+
const {totals} = result;
|
|
108
|
+
totals.rulesNA = inapplicable.length;
|
|
109
|
+
totals.rulesPassed = passes.length;
|
|
110
|
+
incomplete.forEach(rule => {
|
|
111
|
+
totals.rulesWarned++;
|
|
112
|
+
rule.nodes.forEach(node => {
|
|
113
|
+
totals.warnings[node.impact]++;
|
|
114
|
+
});
|
|
111
115
|
});
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
116
|
+
violations.forEach(rule => {
|
|
117
|
+
totals.rulesViolated++;
|
|
118
|
+
rule.nodes.forEach(node => {
|
|
119
|
+
totals.violations[node.impact]++;
|
|
120
|
+
});
|
|
117
121
|
});
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
}
|
|
122
|
+
// Delete irrelevant properties from the report details.
|
|
123
|
+
const irrelevants = ['inapplicable', 'passes', 'incomplete', 'violations']
|
|
124
|
+
.slice(0, 4 - detailLevel);
|
|
125
|
+
irrelevants.forEach(irrelevant => {
|
|
126
|
+
delete axeReport[irrelevant];
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
// Otherwise, i.e. if the test failed:
|
|
130
|
+
else {
|
|
131
|
+
// Report this.
|
|
132
|
+
data.prevented = true;
|
|
133
|
+
data.error = 'ERROR: Act failed';
|
|
134
|
+
}
|
|
125
135
|
}
|
|
126
|
-
// Otherwise, i.e. if the
|
|
136
|
+
// Otherwise, i.e. if the testing timed out:
|
|
127
137
|
else {
|
|
128
138
|
// Report this.
|
|
129
139
|
data.prevented = true;
|
|
130
|
-
data.error = 'ERROR: Act
|
|
140
|
+
data.error = 'ERROR: Act timed out';
|
|
131
141
|
}
|
|
132
142
|
}
|
|
133
143
|
// Return the result.
|
package/tests/ed11y.js
CHANGED
|
@@ -35,26 +35,26 @@ const {xPath} = require('playwright-dompath');
|
|
|
35
35
|
// FUNCTIONS
|
|
36
36
|
|
|
37
37
|
// Performs and reports the Editoria11y tests.
|
|
38
|
-
exports.reporter = async (page,
|
|
38
|
+
exports.reporter = async (page, report, actIndex, timeLimit) => {
|
|
39
39
|
// Get the nonce, if any.
|
|
40
|
-
const
|
|
40
|
+
const act = report.acts[actIndex];
|
|
41
41
|
const {jobData} = report;
|
|
42
42
|
const scriptNonce = jobData && jobData.lastScriptNonce;
|
|
43
43
|
// Get the tool script.
|
|
44
44
|
const script = await fs.readFile(`${__dirname}/../ed11y/editoria11y.min.js`, 'utf8');
|
|
45
45
|
// Perform the tests and get the violating elements and violation facts.
|
|
46
46
|
const reportJSHandle = await page.evaluateHandle(args => new Promise(async resolve => {
|
|
47
|
-
|
|
47
|
+
const {scriptNonce, script, rulesToTest, timeLimit} = args;
|
|
48
|
+
// If the report is incomplete after the time limit:
|
|
48
49
|
const timer = setTimeout(() => {
|
|
49
50
|
// Return this as the report.
|
|
50
51
|
resolve({
|
|
51
52
|
result: {
|
|
52
53
|
prevented: true,
|
|
53
|
-
error:
|
|
54
|
+
error: `ed11y timed out at ${timeLimit} seconds`
|
|
54
55
|
}
|
|
55
56
|
});
|
|
56
|
-
},
|
|
57
|
-
const {scriptNonce, script, rulesToTest} = args;
|
|
57
|
+
}, 1000 * timeLimit);
|
|
58
58
|
// When the script has been executed, creating data in an Ed11y object:
|
|
59
59
|
document.addEventListener('ed11yResults', () => {
|
|
60
60
|
// Initialize a report containing violating elements and violation facts.
|
|
@@ -157,7 +157,12 @@ exports.reporter = async (page, options) => {
|
|
|
157
157
|
}
|
|
158
158
|
});
|
|
159
159
|
};
|
|
160
|
-
}), {
|
|
160
|
+
}), {
|
|
161
|
+
scriptNonce,
|
|
162
|
+
script,
|
|
163
|
+
rulesToTest: act.rules,
|
|
164
|
+
timeLimit
|
|
165
|
+
});
|
|
161
166
|
// Initialize the result as the violation facts.
|
|
162
167
|
const resultJSHandle = await reportJSHandle.getProperty('facts');
|
|
163
168
|
const result = await resultJSHandle.jsonValue();
|
package/tests/htmlcs.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*
|
|
2
|
-
© 2022–
|
|
2
|
+
© 2022–2024 CVS Health and/or one of its affiliates. All rights reserved.
|
|
3
3
|
|
|
4
4
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
5
5
|
of this software and associated documentation files (the "Software"), to deal
|
|
@@ -33,8 +33,9 @@ const fs = require('fs/promises');
|
|
|
33
33
|
// FUNCTIONS
|
|
34
34
|
|
|
35
35
|
// Conducts and reports the HTML CodeSniffer tests.
|
|
36
|
-
exports.reporter = async (page,
|
|
37
|
-
const
|
|
36
|
+
exports.reporter = async (page, report, actIndex) => {
|
|
37
|
+
const act = report.acts[actIndex];
|
|
38
|
+
const {rules} = act;
|
|
38
39
|
const data = {};
|
|
39
40
|
const result = {};
|
|
40
41
|
// Get the HTMLCS script.
|
package/tests/ibm.js
CHANGED
|
@@ -36,16 +36,29 @@
|
|
|
36
36
|
|
|
37
37
|
const fs = require('fs').promises;
|
|
38
38
|
// Scanner. Importing and executing 'close' crashed the Node process.
|
|
39
|
-
const
|
|
39
|
+
const accessibilityChecker = require('accessibility-checker');
|
|
40
|
+
const {getCompliance} = accessibilityChecker;
|
|
41
|
+
// Utility module.
|
|
42
|
+
const {doBy} = require('../procs/job');
|
|
40
43
|
|
|
41
44
|
// FUNCTIONS
|
|
42
45
|
|
|
43
46
|
// Runs the IBM test and returns the result.
|
|
44
|
-
const run = async content => {
|
|
47
|
+
const run = async (content, timeLimit) => {
|
|
45
48
|
const nowLabel = (new Date()).toISOString().slice(0, 19);
|
|
46
49
|
try {
|
|
47
|
-
const ibmReport = await
|
|
48
|
-
|
|
50
|
+
const ibmReport = await doBy(
|
|
51
|
+
timeLimit, accessibilityChecker, 'getCompliance', [content, nowLabel], 'ibm getCompliance'
|
|
52
|
+
);
|
|
53
|
+
if (ibmReport !== 'timedOut') {
|
|
54
|
+
return ibmReport;
|
|
55
|
+
}
|
|
56
|
+
else {
|
|
57
|
+
return {
|
|
58
|
+
prevented: true,
|
|
59
|
+
error: `ibm getCompliance timed out at ${timeLimit} seconds`
|
|
60
|
+
};
|
|
61
|
+
}
|
|
49
62
|
}
|
|
50
63
|
catch(error) {
|
|
51
64
|
console.log('ibm getCompliance failed');
|
|
@@ -177,39 +190,54 @@ const doTest = async (content, withItems, timeLimit, rules) => {
|
|
|
177
190
|
}
|
|
178
191
|
};
|
|
179
192
|
// Conducts and reports the IBM Equal Access tests.
|
|
180
|
-
exports.reporter = async (page,
|
|
181
|
-
const
|
|
193
|
+
exports.reporter = async (page, report, actIndex, timeLimit) => {
|
|
194
|
+
const act = report.acts[actIndex];
|
|
195
|
+
const {withItems, withNewContent, rules} = act;
|
|
182
196
|
const contentType = withNewContent ? 'new' : 'existing';
|
|
183
197
|
console.log(`>>>>>> Content type: ${contentType}`);
|
|
184
|
-
const timeLimit = 25;
|
|
185
198
|
try {
|
|
186
|
-
const typeContent = contentType === 'existing' ? await page.content() :
|
|
199
|
+
const typeContent = contentType === 'existing' ? await page.content() : page.url();
|
|
200
|
+
// Perform the tests.
|
|
187
201
|
const actReport = await doTest(typeContent, withItems, timeLimit, rules);
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
//
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
202
|
+
// If the testing was finished on time:
|
|
203
|
+
if (actReport !== 'timedOut') {
|
|
204
|
+
const {data, result} = actReport;
|
|
205
|
+
// If the act was prevented:
|
|
206
|
+
if (data && data.prevented) {
|
|
207
|
+
// Report this.
|
|
208
|
+
const message = `ERROR: Act failed or timed out at ${timeLimit} seconds`;
|
|
209
|
+
console.log(message);
|
|
210
|
+
data.error = data.error ? `${data.error}; ${message}` : message;
|
|
211
|
+
// Return the failure.
|
|
212
|
+
return {
|
|
213
|
+
data,
|
|
214
|
+
result: {}
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
// Otherwise, i.e. if the act was not prevented:
|
|
218
|
+
else {
|
|
219
|
+
// Return the result.
|
|
220
|
+
return {
|
|
221
|
+
data,
|
|
222
|
+
result
|
|
223
|
+
};
|
|
224
|
+
}
|
|
200
225
|
}
|
|
201
|
-
// Otherwise, i.e. if the
|
|
226
|
+
// Otherwise, i.e. if the testing timed out:
|
|
202
227
|
else {
|
|
203
|
-
//
|
|
228
|
+
// Report this.
|
|
204
229
|
return {
|
|
205
|
-
data
|
|
206
|
-
|
|
230
|
+
data: {
|
|
231
|
+
prevented: true,
|
|
232
|
+
error: message
|
|
233
|
+
},
|
|
234
|
+
result: {}
|
|
207
235
|
};
|
|
208
236
|
}
|
|
209
237
|
}
|
|
210
238
|
catch(error) {
|
|
211
|
-
const message = `
|
|
212
|
-
console.log(message);
|
|
239
|
+
const message = `Act crashed (${error.message.slice(0, 200)})`;
|
|
240
|
+
console.log(`ERROR: ${message}`);
|
|
213
241
|
return {
|
|
214
242
|
data: {
|
|
215
243
|
prevented: true,
|
package/tests/nuVal.js
CHANGED
|
@@ -41,8 +41,9 @@ const {getSource} = require('../procs/getSource');
|
|
|
41
41
|
// FUNCTIONS
|
|
42
42
|
|
|
43
43
|
// Conducts and reports the Nu Html Checker tests.
|
|
44
|
-
exports.reporter = async (page,
|
|
45
|
-
const
|
|
44
|
+
exports.reporter = async (page, report, actIndex) => {
|
|
45
|
+
const act = report.acts[actIndex];
|
|
46
|
+
const {rules} = act;
|
|
46
47
|
// Get the browser-parsed page.
|
|
47
48
|
const pageContent = await page.content();
|
|
48
49
|
// Get the source.
|
package/tests/qualWeb.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*
|
|
2
|
-
© 2023 CVS Health and/or one of its affiliates. All rights reserved.
|
|
2
|
+
© 2023–2024 CVS Health and/or one of its affiliates. All rights reserved.
|
|
3
3
|
|
|
4
4
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
5
5
|
of this software and associated documentation files (the "Software"), to deal
|
|
@@ -28,6 +28,7 @@
|
|
|
28
28
|
// IMPORTS
|
|
29
29
|
|
|
30
30
|
const {QualWeb} = require('@qualweb/core');
|
|
31
|
+
const {doBy} = require('../procs/job');
|
|
31
32
|
|
|
32
33
|
// CONSTANTS
|
|
33
34
|
|
|
@@ -39,8 +40,9 @@ const clusterOptions = {
|
|
|
39
40
|
// FUNCTIONS
|
|
40
41
|
|
|
41
42
|
// Conducts and reports the QualWeb tests.
|
|
42
|
-
exports.reporter = async (page,
|
|
43
|
-
const
|
|
43
|
+
exports.reporter = async (page, report, actIndex, timeLimit) => {
|
|
44
|
+
const act = report.acts[actIndex];
|
|
45
|
+
const {withNewContent, rules} = act;
|
|
44
46
|
const data = {};
|
|
45
47
|
let result = {};
|
|
46
48
|
// Start the QualWeb core engine.
|
|
@@ -121,82 +123,85 @@ exports.reporter = async (page, options) => {
|
|
|
121
123
|
qualWebOptions.execute.bp = true;
|
|
122
124
|
}
|
|
123
125
|
// Get the report.
|
|
124
|
-
let actReports = await qualWeb
|
|
125
|
-
//
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
if (
|
|
137
|
-
const
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
if (ruleAssertions.results) {
|
|
148
|
-
ruleAssertions.results = ruleAssertions.results.filter(
|
|
149
|
-
raResult => raResult.verdict !== 'passed'
|
|
150
|
-
);
|
|
126
|
+
let actReports = await doBy(timeLimit, qualWeb, 'evaluate', [qualWebOptions], 'qualWeb testing');
|
|
127
|
+
// If the testing finished on time:
|
|
128
|
+
if (actReports !== 'timedOut') {
|
|
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];
|
|
151
149
|
}
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
const {elements} = raResult;
|
|
158
|
-
if (elements && elements.length) {
|
|
159
|
-
elements.forEach(element => {
|
|
160
|
-
if (element.htmlCode && element.htmlCode.length > 700) {
|
|
161
|
-
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
|
+
);
|
|
162
155
|
}
|
|
163
|
-
}
|
|
156
|
+
}
|
|
164
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
|
+
});
|
|
165
170
|
});
|
|
166
|
-
}
|
|
171
|
+
}
|
|
172
|
+
else {
|
|
173
|
+
data.prevented = true;
|
|
174
|
+
data.error = 'ERROR: No assertions';
|
|
175
|
+
}
|
|
167
176
|
}
|
|
168
177
|
else {
|
|
169
178
|
data.prevented = true;
|
|
170
|
-
data.error =
|
|
179
|
+
data.error = `ERROR: No ${section} section`;
|
|
171
180
|
}
|
|
172
181
|
}
|
|
173
|
-
else {
|
|
174
|
-
data.prevented = true;
|
|
175
|
-
data.error = `ERROR: No ${section} section`;
|
|
176
|
-
}
|
|
177
182
|
}
|
|
178
183
|
}
|
|
184
|
+
else {
|
|
185
|
+
data.prevented = true;
|
|
186
|
+
data.error = 'ERROR: No modules';
|
|
187
|
+
}
|
|
179
188
|
}
|
|
180
189
|
else {
|
|
181
190
|
data.prevented = true;
|
|
182
|
-
data.error = 'ERROR: No
|
|
191
|
+
data.error = 'ERROR: No DOM';
|
|
183
192
|
}
|
|
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
|
+
};
|
|
184
204
|
}
|
|
185
|
-
else {
|
|
186
|
-
data.prevented = true;
|
|
187
|
-
data.error = 'ERROR: No DOM';
|
|
188
|
-
}
|
|
189
|
-
// Stop the QualWeb core engine.
|
|
190
|
-
await qualWeb.stop();
|
|
191
|
-
// Return the result.
|
|
192
|
-
try {
|
|
193
|
-
JSON.stringify(result);
|
|
194
|
-
}
|
|
195
|
-
catch(error) {
|
|
196
|
-
const message = `ERROR: qualWeb result cannot be made JSON (${error.message})`;
|
|
197
|
-
data.prevented = true;
|
|
198
|
-
data.error = message;
|
|
199
|
-
};
|
|
200
205
|
}
|
|
201
206
|
catch(error) {
|
|
202
207
|
const message = error.message.slice(0, 200);
|
package/tests/testaro.js
CHANGED
|
@@ -143,10 +143,11 @@ const wait = ms => {
|
|
|
143
143
|
});
|
|
144
144
|
};
|
|
145
145
|
// Conducts and reports Testaro tests.
|
|
146
|
-
exports.reporter = async (page,
|
|
147
|
-
const
|
|
146
|
+
exports.reporter = async (page, report, actIndex) => {
|
|
147
|
+
const act = report.acts[actIndex];
|
|
148
|
+
const {args, stopOnFail, withItems} = act;
|
|
148
149
|
const argRules = args ? Object.keys(args) : null;
|
|
149
|
-
const rules =
|
|
150
|
+
const rules = act.rules || ['y', ... Object.keys(evalRules)];
|
|
150
151
|
// Initialize the act report.
|
|
151
152
|
const data = {
|
|
152
153
|
prevented: false,
|
package/tests/wave.js
CHANGED
|
@@ -35,27 +35,29 @@ const https = require('https');
|
|
|
35
35
|
// FUNCTIONS
|
|
36
36
|
|
|
37
37
|
// Conducts and reports the WAVE tests.
|
|
38
|
-
exports.reporter = async (page,
|
|
39
|
-
const
|
|
38
|
+
exports.reporter = async (page, report, actIndex) => {
|
|
39
|
+
const act = report.acts[actIndex];
|
|
40
|
+
const {reportType, rules} = act;
|
|
40
41
|
const waveKey = process.env.WAVE_KEY;
|
|
41
|
-
//
|
|
42
|
+
// Initialize the results.
|
|
42
43
|
const data = {};
|
|
43
|
-
const result =
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
response
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
44
|
+
const result = {};
|
|
45
|
+
try {
|
|
46
|
+
result = await new Promise(resolve => {
|
|
47
|
+
https.get(
|
|
48
|
+
{
|
|
49
|
+
host: 'wave.webaim.org',
|
|
50
|
+
path: `/api/request?key=${waveKey}&url=${page.url()}&reporttype=${reportType}`
|
|
51
|
+
},
|
|
52
|
+
response => {
|
|
53
|
+
let rawReport = '';
|
|
54
|
+
response.on('data', chunk => {
|
|
55
|
+
rawReport += chunk;
|
|
56
|
+
});
|
|
57
|
+
// When the data arrive:
|
|
58
|
+
response.on('end', async () => {
|
|
57
59
|
// Delete unnecessary properties.
|
|
58
|
-
const actResult = JSON.parse(
|
|
60
|
+
const actResult = JSON.parse(rawReport);
|
|
59
61
|
const {categories, statistics} = actResult;
|
|
60
62
|
delete categories.feature;
|
|
61
63
|
delete categories.structure;
|
|
@@ -105,19 +107,16 @@ exports.reporter = async (page, options) => {
|
|
|
105
107
|
data.totalElements = statistics.totalelements || null;
|
|
106
108
|
}
|
|
107
109
|
// Return the result.
|
|
108
|
-
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
}
|
|
119
|
-
);
|
|
120
|
-
});
|
|
110
|
+
resolve(actResult);
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
);
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
catch (error) {
|
|
117
|
+
data.prevented = true;
|
|
118
|
+
data.error = error.message;
|
|
119
|
+
};
|
|
121
120
|
return {
|
|
122
121
|
data,
|
|
123
122
|
result
|