testaro 28.2.4 → 29.0.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.
package/CONTRIBUTING.md CHANGED
@@ -12,7 +12,6 @@ Testaro can benefit from contributions of various types, such as:
12
12
 
13
13
  Tools that may merit consideration include:
14
14
  - Arc (by TPGi). Costs $0.05 per page tested, and requires each user to have an account with the tool maker and to allow the tool maker to charge a charge account for payment.
15
- - Aslint (by Essential Accessibility). Apparently requires using a bundle file that is in the repository but is also listed in the `.gitignore` file and is missing from the published package, so would need to be physically included in the Testaro code rather than referenced as a dependency.
16
15
 
17
16
  ## Improving execution speed
18
17
 
@@ -24,13 +23,13 @@ To come.
24
23
 
25
24
  ## Implementing new rules
26
25
 
27
- Testaro has about 50 of its own rules, in addition to the approximately 600 rules of the other tools that it integrates. According to the issue classifications in the [Testilo](https://www.npmjs.com/package/testilo) package, these 650 or so rules can be classified into about 260 accessibility _issues_, because some rules of some tools at least approximately duplicate some rules of other tools.
26
+ Testaro has about 50 of its own rules, in addition to the approximately 900 rules of the other tools that it integrates. According to the issue classifications in the [Testilo](https://www.npmjs.com/package/testilo) package, these 950 or so rules can be classified into about 290 accessibility _issues_, because some rules of some tools at least approximately duplicate some rules of other tools.
28
27
 
29
28
  However, many other significant accessibility issues exist that are not covered by any of the existing rules. Thus, Testaro welcomes contributions of new rules for such issues.
30
29
 
31
30
  ### Step 1
32
31
 
33
- The first step in contributing a new rule to Testaro is to satisfy yourself that it will not duplicate existing rules. The `procs/score/tic35.js` file in the Testilo package should be helpful here.
32
+ The first step in contributing a new rule to Testaro is to satisfy yourself that it will not duplicate existing rules. The `procs/score/tic36.js` file in the Testilo package should be helpful here.
34
33
 
35
34
  ### Step 2
36
35
 
package/README.md CHANGED
@@ -221,7 +221,7 @@ Testaro helps overcome this format diversity by offering to represent the main f
221
221
 
222
222
  In the conceptual scheme underlying the format standardization of Testaro, each tool has its own set of _rules_, where a rule is an algorithm for evaluating a target and determining whether instances of some kind of problem exist in it. With standardization, Testaro reports, in a uniform way, the outcomes from the application of rules by tools to a target.
223
223
 
224
- If the `STANDARD` environment variable has the value `also` (which it has by default) or `only`, Testaro converts some data in each tool report to the standard format. That permits you to ignore the format idiosyncrasies of the tools. If `STANDARD` has the value `also`, the job report includes both formats. If the value is `only`, the job report includes only the standard format. If the value is `no`, the job report includes only the original format of each tool report.
224
+ Each job can specify how Testaro is to handle report standardization. A job can contain a `standard` property. If the value of that property is `'also'` or `'only'`, Testaro converts some data in each tool report to the standard format. That permits you to ignore the format idiosyncrasies of the tools. If `standard` has the value `'also'`, the job report includes both formats. If the value is `'only'`, the job report includes only the standard format. If the value is `'no'` (or anything else, or there is no `standard` property), the job report includes only the original format of each tool report.
225
225
 
226
226
  The standard format of each tool report has these properties:
227
227
  - `prevented`: `true` if the tool failed to run on the page, or otherwise omitted.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "testaro",
3
- "version": "28.2.4",
3
+ "version": "29.0.0",
4
4
  "description": "Run 960 web accessibility tests from 9 tools and get a standardized report",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -0,0 +1,28 @@
1
+ /*
2
+ tellServer
3
+ Notify the server.
4
+ */
5
+
6
+ // CONSTANTS
7
+
8
+ const httpClient = require('http');
9
+ const httpsClient = require('https');
10
+ const agent = process.env.AGENT;
11
+
12
+ // FUNCTIONS
13
+
14
+ exports.tellServer = (report, messageParams, logMessage) => {
15
+ const observer = report.sources.sendReportTo.replace(/report$/, 'granular');
16
+ const whoParams = `agent=${agent}&jobID=${report.id || ''}`;
17
+ const wholeURL = `${observer}?${whoParams}&${messageParams}`;
18
+ const client = wholeURL.startsWith('https://') ? httpsClient : httpClient;
19
+ const request = client.request(wholeURL);
20
+ // If the notification threw an error:
21
+ request.on('error', error => {
22
+ // Report the error.
23
+ const errorMessage = 'ERROR notifying the server';
24
+ console.log(`${errorMessage} (${error.message})`);
25
+ });
26
+ request.end();
27
+ console.log(`${logMessage} (server notified)`);
28
+ };
package/run.js CHANGED
@@ -13,6 +13,8 @@ const {actSpecs} = require('./actSpecs');
13
13
  const {browserClose, getNonce, goTo, launch} = require('./procs/nav');
14
14
  // Module to standardize report formats.
15
15
  const {standardize} = require('./procs/standardize');
16
+ // Module to send a notice to the server.
17
+ const {tellServer} = require('./procs/tellServer');
16
18
 
17
19
  // ########## CONSTANTS
18
20
 
@@ -20,8 +22,6 @@ const {standardize} = require('./procs/standardize');
20
22
  const debug = process.env.DEBUG === 'true';
21
23
  // Set WAITS environment variable to a positive number to insert delays (in ms).
22
24
  const waits = Number.parseInt(process.env.WAITS) || 0;
23
- // Set STANDARD environment variable to also if not set.
24
- process.env.STANDARD ??= 'also';
25
25
  // CSS selectors for targets of moves.
26
26
  const moves = {
27
27
  button: 'button, [role=button], input[type=submit]',
@@ -45,10 +45,6 @@ const tests = {
45
45
  testaro: 'Testaro',
46
46
  wave: 'WAVE',
47
47
  };
48
- // Observation items.
49
- const httpClient = require('http');
50
- const httpsClient = require('https');
51
- const agent = process.env.AGENT;
52
48
 
53
49
  // ########## VARIABLES
54
50
 
@@ -466,26 +462,12 @@ const doActs = async (report, actIndex, page) => {
466
462
  actInfo = act.which;
467
463
  }
468
464
  }
469
- const whichSuffix = actInfo ? ` (${actInfo})` : '';
470
465
  // If granular reporting has been specified:
471
- let granularSuffix = '';
472
466
  if (report.observe) {
473
467
  // Notify the server of the act.
474
- const observer = report.sources.sendReportTo.replace(/report$/, 'granular');
475
- const whoParams = `agent=${agent}&jobID=${report.id || ''}`;
476
- const actParams = `act=${act.type}&which=${act.which || ''}`;
477
- const wholeURL = `${observer}?${whoParams}&${actParams}`;
478
- const client = wholeURL.startsWith('https://') ? httpsClient : httpClient;
479
- const request = client.request(wholeURL);
480
- // If the notification threw an error:
481
- request.on('error', error => {
482
- // Report the error.
483
- const errorMessage = 'ERROR notifying the server of an act';
484
- console.log(`${errorMessage} (${error.message})`);
485
- });
486
- request.end();
487
- granularSuffix = ' with notice to server';
488
- console.log(`>>>> ${act.type}${whichSuffix}${granularSuffix}`);
468
+ const whichParam = act.which ? `&which=${act.which}` : '';
469
+ const messageParams = `act=${act.type}${whichParam}`;
470
+ tellServer(report, messageParams, `>>>> ${act.type}: ${actInfo}`);
489
471
  }
490
472
  // Increment the count of acts performed.
491
473
  actCount++;
@@ -709,7 +691,9 @@ const doActs = async (report, actIndex, page) => {
709
691
  act.what = tests[act.which];
710
692
  // Initialize the options argument.
711
693
  const options = {
694
+ report,
712
695
  act,
696
+ granular: report.observe,
713
697
  scriptNonce: report.jobData.lastScriptNonce || ''
714
698
  };
715
699
  // Add any specified arguments to it.
@@ -746,7 +730,7 @@ const doActs = async (report, actIndex, page) => {
746
730
  const resultCount = Object.keys(toolReport.result).length;
747
731
  act.result = resultCount ? toolReport.result : {success: false};
748
732
  // If a standard-format result is to be included in the report:
749
- const standard = process.env.STANDARD;
733
+ const standard = report.standard || 'only';
750
734
  if (['also', 'only'].includes(standard)) {
751
735
  // Initialize it.
752
736
  act.standardResult = {
@@ -757,7 +741,11 @@ const doActs = async (report, actIndex, page) => {
757
741
  standardize(act);
758
742
  // If the original-format result is not to be included in the report:
759
743
  if (standard === 'only') {
760
- // Remove it.
744
+ // Remove it, except any important property.
745
+ if (act.result.important) {
746
+ act.data = act.result.important;
747
+ console.log('>>>>>> Important result data protected from deletion');
748
+ }
761
749
  delete act.result;
762
750
  }
763
751
  // If the test has expectations:
package/tests/testaro.js CHANGED
@@ -9,21 +9,27 @@
9
9
  const {init, report} = require('../procs/testaro');
10
10
  // Module to handle files.
11
11
  const fs = require('fs/promises');
12
+ // Module to send a notice to the server.
13
+ const {tellServer} = require('../procs/tellServer');
12
14
 
13
15
  // ######## CONSTANTS
14
16
 
15
- const futureEvalRules = {
16
- adbID: 'elements with ambiguous or missing referenced descriptions',
17
+ /*
18
+ const futureEvalRulesTraining = {
17
19
  altScheme: 'img elements with alt attributes having URLs as their entire values',
18
20
  captionLoc: 'caption elements that are not first children of table elements',
19
21
  datalistRef: 'elements with ambiguous or missing referenced datalist elements',
22
+ secHeading: 'headings that violate the logical level order in their sectioning containers',
23
+ textSem: 'semantically vague elements i, b, and/or small'
24
+ };
25
+ const futureEvalRulesCleanRoom = {
26
+ adbID: 'elements with ambiguous or missing referenced descriptions',
20
27
  imageLink: 'links with image files as their destinations',
21
28
  legendLoc: 'legend elements that are not first children of fieldset elements',
22
29
  optRoleSel: 'Non-option elements with option roles that have no aria-selected attributes',
23
- phOnly: 'input elements with placeholders but no accessible names',
24
- secHeading: 'headings that violate the logical level order in their sectioning containers',
25
- textSem: 'semantically vague elements i, b, and/or small',
30
+ phOnly: 'input elements with placeholders but no accessible names'
26
31
  };
32
+ */
27
33
  const evalRules = {
28
34
  allCaps: 'leaf elements with entirely upper-case text longer than 7 characters',
29
35
  allHidden: 'page that is entirely or mostly hidden',
@@ -95,15 +101,17 @@ const jsonTest = async (ruleID, ruleArgs) => {
95
101
  };
96
102
  // Conducts and reports Testaro tests.
97
103
  exports.reporter = async (page, options) => {
98
- const {withItems, stopOnFail, args} = options;
104
+ const {withItems, stopOnFail, granular, args} = options;
99
105
  const argRules = args ? Object.keys(args) : null;
100
106
  const rules = options.rules || ['y', ... Object.keys(evalRules)];
101
107
  // Initialize the data.
102
108
  const data = {
103
109
  rules: {},
104
- preventions: [],
105
- invalid: [],
106
- testTimes: {}
110
+ important: {
111
+ preventions: [],
112
+ invalid: [],
113
+ testTimes: {}
114
+ }
107
115
  };
108
116
  // If the rule specification is valid:
109
117
  if (
@@ -129,13 +137,21 @@ exports.reporter = async (page, options) => {
129
137
  // Add them to the argument array.
130
138
  ruleArgs.push(... args[rule]);
131
139
  }
132
- // Test the page.
140
+ // If granular reporting is specified:
133
141
  const what = evalRules[rule] || etcRules[rule];
142
+ if (granular) {
143
+ // Report the rule to the server.
144
+ tellServer(
145
+ options.report,
146
+ `act=test&which=testaro&rule=${rule}&ruleWhat=${what}`,
147
+ `>>>>>> ${rule} (${what})`
148
+ );
149
+ }
150
+ // Test the page.
134
151
  if (! data.rules[rule]) {
135
152
  data.rules[rule] = {};
136
153
  }
137
154
  data.rules[rule].what = what;
138
- console.log(`>>>>>> ${rule} (${what})`);
139
155
  try {
140
156
  const startTime = Date.now();
141
157
  const ruleReport = isJS
@@ -149,7 +165,7 @@ exports.reporter = async (page, options) => {
149
165
  });
150
166
  data.rules[rule].totals = data.rules[rule].totals.map(total => Math.round(total));
151
167
  if (ruleReport.prevented) {
152
- data.preventions.push(rule);
168
+ data.important.preventions.push(rule);
153
169
  }
154
170
  // If testing is to stop after a failure and the page failed the test:
155
171
  if (stopOnFail && ruleReport.totals.some(total => total)) {
@@ -160,19 +176,19 @@ exports.reporter = async (page, options) => {
160
176
  // If an error is thrown by the test:
161
177
  catch(error) {
162
178
  // Report this.
163
- data.preventions.push(rule);
179
+ data.important.preventions.push(rule);
164
180
  console.log(`ERROR: Test of testaro rule ${rule} prevented (${error.message})`);
165
181
  }
166
182
  }
167
183
  // Otherwise, i.e. if the rule is undefined or doubly defined:
168
184
  else {
169
185
  // Report this.
170
- data.invalid.push(rule);
186
+ data.important.invalid.push(rule);
171
187
  console.log(`ERROR: Rule ${rule} not validly defined`);
172
188
  }
173
189
  }
174
190
  testTimes.sort((a, b) => b[1] - a[1]).forEach(pair => {
175
- data.testTimes[pair[0]] = pair[1];
191
+ data.important.testTimes[pair[0]] = pair[1];
176
192
  });
177
193
  }
178
194
  // Otherwise, i.e. if the rule specification is invalid: