testilo 16.2.0 → 17.0.1

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 CHANGED
@@ -344,12 +344,11 @@ This is a valid Testaro job.
344
344
 
345
345
  If, however, you requested a merger **with** isolation, then Testilo would take cognizance of the fact that an `axe` test act is a target-modifying act. Testilo would therefore act as if another instance of the placeholder had been located in the script after the `axe` test act. So, copies of the same 6 acts that precede the `axe` test act would be inserted **after** the `axe` test act, too.
346
346
 
347
- Of the 10 tools providing tests for Testaro, 6 are target-modifying:
347
+ Of the 8 tools providing tests for Testaro, 4 are target-modifying:
348
348
  - `axe`
349
- - `continuum`
350
349
  - `htmlcs`
351
350
  - `ibm`
352
- - `wave`
351
+ - `testaro`
353
352
 
354
353
  #### Invocation
355
354
 
@@ -642,7 +641,7 @@ node call credit legislators 23pl
642
641
 
643
642
  When a user invokes `credit` in this example, the `call` module:
644
643
  - gets all the reports in the `scored` subdirectory of the `process.env.REPORTDIR` directory whose file names begin with `23pl`.
645
- - writes the credit report as JSON file named `legislators.json` to the `credit` subdirectory of the `process.env.REPORTDIR` directory.
644
+ - writes the credit report as a JSON file named `legislators.json` to the `credit` subdirectory of the `process.env.REPORTDIR` directory.
646
645
 
647
646
  The third argument to `call` (`23pl` in this example) is optional. If it is omitted, `call` will get and `credit()` will tabulate all the reports in the `scored` directory.
648
647
 
package/call.js CHANGED
@@ -279,7 +279,7 @@ else if (fn === 'compare' && fnArgs.length > 1 && fnArgs.length < 4) {
279
279
  console.log('Execution completed');
280
280
  });
281
281
  }
282
- else if (fn === 'credit' && fnArgs.length === 2) {
282
+ else if (fn === 'credit' && fnArgs.length > 0 && fnArgs.length < 3) {
283
283
  callCredit(... fnArgs)
284
284
  .then(() => {
285
285
  console.log('Execution completed');
package/merge.js CHANGED
@@ -18,7 +18,6 @@ const stdRequester = process.env.REQUESTER;
18
18
  // Tools that alter the page.
19
19
  const contaminantNames = new Set([
20
20
  'axe',
21
- 'continuum',
22
21
  'htmlcs',
23
22
  'ibm'
24
23
  ]);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "testilo",
3
- "version": "16.2.0",
3
+ "version": "17.0.1",
4
4
  "description": "Prepares and processes Testaro reports",
5
5
  "main": "aim.js",
6
6
  "scripts": {
@@ -0,0 +1,69 @@
1
+ /*
2
+ coverage.js
3
+ Checks coverage of Testaro tests in an issue classification.
4
+ */
5
+
6
+ // Returns a tabulation of the instance counts of issues reported by tools in scored reports.
7
+ const coverage = ticID => {
8
+ const evalRules = {
9
+ allCaps: 'leaf elements with entirely upper-case text longer than 7 characters',
10
+ allHidden: 'page that is entirely or mostly hidden',
11
+ allSlanted: 'leaf elements with entirely italic or oblique text longer than 39 characters',
12
+ autocomplete: 'name and email inputs without autocomplete attributes',
13
+ bulk: 'large count of visible elements',
14
+ buttonMenu: 'nonstandard keyboard navigation between items of button-controlled menus',
15
+ captionLoc: 'caption elements that are not first children of table elements',
16
+ distortion: 'distorted text',
17
+ docType: 'document without a doctype property',
18
+ dupAtt: 'elements with duplicate attributes',
19
+ embAc: 'active elements embedded in links or buttons',
20
+ filter: 'filter styles on elements',
21
+ focAll: 'discrepancies between focusable and Tab-focused elements',
22
+ focInd: 'missing and nonstandard focus indicators',
23
+ focOp: 'Tab-focusable elements that are not operable',
24
+ focVis: 'links that are invisible when focused',
25
+ headEl: 'invalid elements within the head',
26
+ headingAmb: 'same-level sibling headings with identical texts',
27
+ hover: 'hover-caused content changes',
28
+ hovInd: 'hover indication nonstandard',
29
+ hr: 'hr element instead of styles used for vertical segmentation',
30
+ labClash: 'labeling inconsistencies',
31
+ legendLoc: 'legend elements that are not first children of fieldset elements',
32
+ lineHeight: 'text with a line height less than 1.5 times its font size',
33
+ linkExt: 'links that automatically open new windows',
34
+ linkAmb: 'links with identical texts but different destinations',
35
+ linkOldAtt: 'links with deprecated attributes',
36
+ linkTitle: 'links with title attributes repeating text content',
37
+ linkTo: 'links without destinations',
38
+ linkUl: 'missing underlines on inline links',
39
+ miniText: 'text smaller than 11 pixels',
40
+ motion: 'motion without user request',
41
+ nonTable: 'table elements used for layout',
42
+ opFoc: 'Operable elements that are not Tab-focusable',
43
+ optRoleSel: 'Non-option elements with option roles that have no aria-selected attributes',
44
+ phOnly: 'input elements with placeholders but no accessible names',
45
+ pseudoP: 'adjacent br elements suspected of nonsemantically simulating p elements',
46
+ radioSet: 'radio buttons not grouped into standard field sets',
47
+ role: 'invalid and native-replacing explicit roles',
48
+ styleDiff: 'style inconsistencies',
49
+ tabNav: 'nonstandard keyboard navigation between elements with the tab role',
50
+ targetSize: 'buttons, inputs, and non-inline links smaller than 44 pixels wide and high',
51
+ titledEl: 'title attributes on inappropriate elements',
52
+ zIndex: 'non-default Z indexes'
53
+ };
54
+ const {issues} = require(`${__dirname}/../score/${ticID}`);
55
+ const testaroRuleIDs = new Set();
56
+ Object.values(issues).forEach(issue => {
57
+ if (issue.tools && issue.tools.testaro) {
58
+ Object.keys(issue.tools.testaro).forEach(ruleID => {
59
+ testaroRuleIDs.add(ruleID);
60
+ });
61
+ }
62
+ });
63
+ Object.keys(evalRules).forEach(ruleID => {
64
+ if (! testaroRuleIDs.has(ruleID)) {
65
+ console.log(`${ticID} is missing ${ruleID}`);
66
+ }
67
+ });
68
+ };
69
+ coverage('tic35');
@@ -17,7 +17,7 @@ exports.credit = reports => {
17
17
  // If it is valid:
18
18
  if (report.score && report.score.details && report.score.details.issue) {
19
19
  // For each issue:
20
- const issues = report.score.details.issue;
20
+ const issues = report.score.details && report.score.details.issue;
21
21
  Object.keys(issues).forEach(issueID => {
22
22
  // For each tool with any complaints about it:
23
23
  if (! counts[issueID]) {
@@ -28,19 +28,29 @@ exports.credit = reports => {
28
28
  Object.keys(issueTools).forEach(toolID => {
29
29
  // For each rule cited by any of those complaints:
30
30
  if (! counts[issueID][toolID]) {
31
- counts[issueID][toolID] = 0;
31
+ counts[issueID][toolID] = {
32
+ total: 0,
33
+ rules: {}
34
+ };
32
35
  }
33
36
  Object.keys(issueTools[toolID]).forEach(ruleID => {
34
37
  // If an instance count was recorded:
35
38
  const {complaints} = issueTools[toolID][ruleID];
36
39
  if (complaints && complaints.countTotal) {
37
40
  // Add it to the tally.
38
- counts[issueID][toolID] += complaints.countTotal;
41
+ counts[issueID][toolID].total += complaints.countTotal;
42
+ // Add a rule itemization to the tally.
43
+ if (! counts[issueID][toolID].rules[ruleID]) {
44
+ counts[issueID][toolID].rules[ruleID] = 0;
45
+ }
46
+ counts[issueID][toolID].rules[ruleID] += complaints.countTotal;
39
47
  }
40
48
  // Otherwise, i.e. if no instance count was recorded:
41
49
  else {
42
50
  // Report this.
43
- console.log(`ERROR: Missing countTotal for ${toolID} in ${issueID}`);
51
+ console.log(
52
+ `ERROR: Report ${report.id} missing countTotal for ${toolID} in ${issueID}`
53
+ );
44
54
  }
45
55
  });
46
56
  });
@@ -69,9 +79,9 @@ exports.credit = reports => {
69
79
  // Add the tools with the maximum instance count to the tally.
70
80
  const maxCount = Object
71
81
  .values(counts[issueID])
72
- .reduce((max, current) => Math.max(max, current));
82
+ .reduce((max, current) => Math.max(max, current ? current.total : 0), 0);
73
83
  Object.keys(counts[issueID]).forEach(toolID => {
74
- if (counts[issueID][toolID] === maxCount) {
84
+ if (maxCount && counts[issueID][toolID].total === maxCount) {
75
85
  if (! mosts[issueID]) {
76
86
  mosts[issueID] = [];
77
87
  }
@@ -354,7 +354,7 @@ exports.issues = {
354
354
  863: {
355
355
  variable: false,
356
356
  quality: 1,
357
- what: 'input has an accessible name that depends on a placeholder'
357
+ what: 'input element has an accessible name that depends on a placeholder'
358
358
  }
359
359
  }
360
360
  }