testilo 3.12.3 → 4.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/README.md CHANGED
@@ -1,72 +1,147 @@
1
1
  # testilo
2
- Scorer and digester of Testaro reports
2
+ Utilities for Testaro
3
3
 
4
4
  ## Introduction
5
5
 
6
- This application enriches [Testaro](https://www.npmjs.com/package/testaro) reports. Testaro performs digital accessibility tests on web artifacts and creates reports in JSON format. To make those reports more useful, this application, Testilo, computes scores, converts the scored reports to human-readable web pages (_digests_), and compiles human-readable web pages comparing the scores of multiple artifacts.
6
+ The Testilo package contains utilities that facilitate the use of the [Testaro package](https://www.npmjs.com/package/testaro).
7
+
8
+ Testaro performs digital accessibility tests on web artifacts and creates reports in JSON format. The utilities in Testilo prepare jobs for Testaro to run and create additional value from the reports that Testaro produces.
7
9
 
8
10
  ## Dependencies
9
11
 
10
- The `dotenv` dependency lets you set environment variables in an untracked `.env` file.
12
+ The `dotenv` dependency lets you set environment variables in an untracked `.env` file. This prevents secret data, such as passwords, from being shared as part of this package.
11
13
 
12
14
  ## Architecture
13
15
 
14
- The routines that perform scoring, digesting, and comparing are _procs_ and are located in the `procs` directory.
16
+ Testilo is written in Node.js. Commands are given to Testilo in a command-line (terminal) interface or programmatically.
17
+
18
+ Shared routines that perform scoring, digesting, and comparing are _procs_ and are located in the `procs` directory.
19
+
20
+ Testilo can be installed wherever Node.js (version 14 or later) is installed. This can be a server or the same workstation on which Testaro is installed.
21
+
22
+ The reason for Testilo being an independent package, rather than part of Testaro, is that Testilo can be installed on any host, while Testaro can run successfully only on a Windows or Macintosh workstation (and perhaps on some workstations with Ubuntu operating systems). Testaro runs tests similar to those that a human accessibility tester would run, using whatever browsers, input devices, system settings, simulated and attached devices, and assistive technologies tests may require. Thus, Testaro is limited to functionalities that require workstation attributes. For maximum flexibility in the management of Testaro jobs, all other functionalities are located outside of Testaro. You could have software such as Testilo running on a server, communicating with multiple workstations running Testaro, receiving job orders from the server and returning job results to the server for further processing.
23
+
24
+ ## Utilities
25
+
26
+ ### `merge`
27
+
28
+ Testaro runs _jobs_. A job gives Testaro instructions.
29
+
30
+ Sometimes you may want Testaro to perform a set of tests on multiple targets. The `merge` utility in Testilo facilitates this. It creates Testaro jobs out of a _script_ and a _batch_.
31
+
32
+ A script tells Testaro where to go and what to do. If the where-to-go part identifies a specific URL, the script can be a job, ready for Testaro to run. But the where-to-go part can also be generic, such as `http://*.*`. Then the script needs to be converted to a job by having its generic destination replaced with a specific URL. A batch is a list of _hosts_ (URLs and metadata). Merging a batch and a script means generating from the script as many jobs as there are hosts in the batch. In each job, one host from the batch becomes the specific target.
33
+
34
+ A script is a JSON file representing a `script` object, which contains a sequence of _commands_. Scripts are documented in detail in the Testaro `README.md` file.
35
+
36
+ A batch is a JSON file representing a `batch` object, which contains an array of _hosts_. Each host is an object with three properties:
37
+ - `id`: a string unique in the batch
38
+ - `which`: a URL
39
+ - `what`: a string naming the entity associated with the URL
40
+
41
+ The batch as a whole also has three properties:
42
+ - `id`: a string composed of ASCII letters and digits
43
+ - `what`: a string describing the batch
44
+ - `hosts`: an array of host objects
45
+
46
+ Here is an example of a batch:
47
+
48
+ ```json
49
+ {
50
+ "id": "usFedExec1",
51
+ "what": "United States federal executive agencies",
52
+ "hosts": [
53
+ {
54
+ "id": "achp",
55
+ "which": "https://www.achp.gov/",
56
+ "what": "Advisory Council on Historic Preservation (ACHP)"
57
+ },
58
+ {
59
+ "id": "agm",
60
+ "which": "https://www.usagm.gov/",
61
+ "what": "Agency for Global Media"
62
+ }
63
+ ]
64
+ }
65
+ ```
66
+
67
+ The `merge` utility finds all the `url` commands in a script (telling the browser what to visit), replaces them with one of the hosts in the batch, and outputs the modified script as a job. It then does the same with each of the other hosts in the batch.
68
+
69
+ To execute `merge`, you need to have three environment variables defined to tell `merge` where files are located. You can define the environment variables in the `.env` file. Here is an example:
70
+
71
+ ```
72
+ SCRIPTDIR=../testing/scripts
73
+ BATCHDIR=../testing/batches
74
+ JOBDIR=../testing/jobs
75
+ ```
76
+
77
+ In this example, the script, batch, and job files are located in directories named `scripts`, `batches`, and `jobs` within `testing`, which is a sibling directory of the Testilo project directory.
78
+
79
+ The syntax of the `merge` statement is documented in `merge.js`.
80
+
81
+ Suppose that:
82
+ - The environment variables are defined as in the above example.
83
+ - There is a script file named `testall.json`.
84
+ - The above batch example is in a file named `usFedExec1.json`.
85
+
86
+ The statement `node merge testall usFedExec1 allFedExec` would tell Testilo to merge the batch `../testing/batches/usFedExec1.json` and the script `../testing/scripts/testall.json` and write the two job files in `../testing/jobs/allFedExec`.
87
+
88
+ ### `score`
15
89
 
16
- To score reports, Testilo needs to be told which reports to score and which scoring procedure (or _score proc_) to use.
90
+ Testaro performs tests and produces reports of test results. Testilo can add scores to those reports. In this way, each report can not only detail successes and failures of individual tests but also assign scores to those results and combine the partial scores into total scores.
17
91
 
18
- Similarly, once reports have been scored, Testilo can digest them. For this purpose, Testilo needs to be told which scored reports to digest and which _digest proc_ to use.
92
+ The `score` utility performs scoring. It depends on score procs to define the scoring rules. Some score procs are in the Testilo package (in the `procs/score` directory), and you can create more score procs to implement different rules.
19
93
 
20
- Likewise, Testilo can compare scored reports. It needs to be told which reports to compare and which _comparison proc_ to use.
94
+ You can score multiple reports with a single invocation of `score`.
21
95
 
22
- Testilo includes some score procs, digest procs, and comparison procs. You can add others.
96
+ To execute `score`, you need to have two environment variables defined to tell `score` where files are located. You can define the environment variables in the `.env` file. Here is an example:
23
97
 
24
- ## Execution
98
+ ```
99
+ REPORTDIR_RAW=../testing/reports/raw
100
+ REPORTDIR_SCORED=../testing/reports/scored
101
+ ```
25
102
 
26
- ### Scoring
103
+ The named directories must already exist.
27
104
 
28
- #### Process
105
+ The syntax of the `score` statement is documented in `score.js`.
29
106
 
30
- To score Testaro reports, execute the statement `node score procID reportNameStart`. Replace (here and below) `procID` with the base of the name of the score proc. An environment variable named `REPORTDIR_RAW` defines a directory (i.e. a filesystem path, relative to the project directory of Testilo) where Testilo will look for the raw (i.e. not-yet-scored) reports. If you want Testilo to score all of the reports in that directory, you can omit the `reportNameStart` argument. If, instead, you want Testilo to score only the reports in that directory whose names begin with a certain string, replace `reportNameStart` with that string. So, for example, suppose the raw reports are in the `reports/raw` directory of a project, `testing`, that sits alongside of Testilo in your filesystem. Then you would assign the value `'../testing/reports/raw'` to the environment variable `REPORTDIR_RAW`. Now, to score all of the reports in that directory with score proc `sp11a`, execute `node score sp11a`. Or, to score only the reports in that directory whose filenames begin with `4rper`, execute node score sp11a `4rper`.
107
+ A scored report file is identical to the file it was created from, except that the scored report has new properties named `score` and `scoreProcID`. The `score` property contains the scores.
31
108
 
32
- This procedure has two preconditions:
33
- - The score proc is compatible with the script (or _test proc_) that produced the report(s).
34
- - You have defined environment variables `REPORTDIR_RAW` and (for the scored reports that Testilo will write) `REPORTDIR_SCORED`.
109
+ ### `digest`
35
110
 
36
- The scored report file has the same name as the original. The scored report has the same content as the original, plus new properties named `score` and `scoreProcID`.
111
+ Testaro reports, both originally and after they are scored, are JSON files. That format is basically designed for machine tractability.
37
112
 
38
- #### Procedures
113
+ The `digest` utility converts scored reports into HTML documents with explanatory content. Thus, it converts machine-oriented reports into human-oriented reports, called _digests_. It depends on digest procs to define the digesting rules. Some digest procs are in the Testilo package (in the `procs/digest` directory), and you can create more digest procs to implement different rules.
39
114
 
40
- The score procs included with Testilo represent milestones in the refinement of a scoring methodology.
115
+ You can digest multiple scored reports with a single invocation of `digest`.
41
116
 
42
- One development has been an expansion of the set of packages. The progression from score proc `sp09a` to `sp10a` included the addition of the Tenon package.
117
+ To execute `digest`, you need to have two environment variables defined to tell `digest` where files are located. You can define the environment variables in the `.env` file. Here is an example:
43
118
 
44
- The main development has been a change from package-based to issue-based scoring. With package-based scoring, each package yielded a score, and the scores were summed into a total score. With issue-based scoring, the individual tests in each package are classified into groups, such that the tests from various packages in any particular group all seek to discover approximately the same type of accessibility issue. An artifact gets a score on each group, and the group scores are summed into a total score. The change from package-based to issue-based scoring took place in the progression from score proc `sp10a` to `sp10b`.
119
+ ```
120
+ REPORTDIR_SCORED=../testing/reports/scored
121
+ REPORTDIR_DIGESTED=../testing/reports/digested
122
+ ```
45
123
 
46
- The problem of combining partly similar tests from different packages and producing an appropriate accessibility score has no perfect solution, and each successive score proc embodies efforts to make the result more appropriate.
124
+ The named directories must already exist.
47
125
 
48
- #### Prevention
126
+ The syntax of the `digest` statement is documented in `digest.js`.
49
127
 
50
- Testaro reports an error when it is unable to perform a test on a host. A score proc can take such errors into account. The score procs included with Testilo do that by estimating scores when a package cannot be run.
128
+ The digests created by `digest` are HTML files, and they expect a `style.css` file to exist in their directory. The `reports/digested/style.css` file in Testilo is an appropriate stylesheet to be copied into `process.env.REPORTDIR_DIGESTED`.
51
129
 
52
- ### Digesting
130
+ ### `compare`
53
131
 
54
- To make scored Testaro reports more useful for humans, Testilo can create digests of scored reports. A digest is an HTML document (a web page) summarizing and explaining the findings, with the scored report appended to it.
132
+ You can summarize the results of a multi-host job by producing a document comparing the scores received by the hosts. The `compare` utility does this.
55
133
 
56
- To make Testilo digest reports, execute the statement `node digest procID reportNameStart`. The rules for this statement are the same as for the `score` statement, except that the directory where Testilo finds the reports in the one referenced by the `REPORTDIR_SCORED` environment variable, and the directory where Testilo will write the digests is the one referenced by `REPORTDIR_DIGESTED`. In order to make the digests appear correct in a browser, you must copy the `reports/digested/style.css` file into the `REPORTDIR_DIGESTED` directory.
134
+ The `compare` utility gathers scores from a set of scored reports and produces an HTML document comparing the scores. It depends on compare procs to define the rules for making and showing the comparative scores. Some compare procs are in the Testilo package (in the `procs/compare` directory), and you can create more compare procs to implement different rules.
57
135
 
58
- ### Comparing
136
+ To execute `compare`, you need to have two environment variables defined to tell `digest` where files are located. You can define the environment variables in the `.env` file. Here is an example:
59
137
 
60
- You can use Testilo to publish comparisons of accessibility scores. To do this, execute the statement `node compare abc xyz`, replacing `abc` with a filename base for the comparison and `xyz` with the name of a subdirectory of the `procs/compare` directory.
138
+ ```
139
+ REPORTDIR_SCORED=../testing/reports/scored
140
+ COMPARISONDIR=../testing/reports/compared
141
+ ```
61
142
 
62
- Testilo will examine all of the scored reports in the `REPORTDIR_SCORED` directory. The comparison proc in the `xyz` directory will construct a web page. Testilo will save the page in the `COMPARISONDIR` directory. The name of the file will be `abc.html`.
143
+ The named directories must already exist.
63
144
 
64
- Comparison procs can design various pages on the basis of a set of scored reports. As an example, the `cp0` comparison proc creates a page that contains a table of scores, shown both numerically and with a bar graph. In the table, the first column contains descriptions of the pages (the `what` property of the hosts in the batch), such as “Wikipedia English”. Each such description is a link to the page on the web. The second column contains the scores of the pages. Each score is a link to the digest for its page. The link points to a digest located in a `digests` directory adjacent to the page itself. Thus, to use the `cp0` comparison proc, you would copy its output file to a web server, create a `digests` directory on the server as a sibling of that file, and copy the digest files into the `digests` directory.
145
+ The syntax of the `compare` statement is documented in `compare.js`.
65
146
 
66
- This procedure has some preconditions:
67
- - The comparison proc is compatible with the score proc that scored the report.
68
- - Testilo can find the scored report files in the directory whose relative path (relative to the project directory of Testilo) is the value of the `REPORTDIR_SCORED` environment variable.
69
- - Testilo can read in the `REPORTDIR_SCORED` directory.
70
- - There is a `COMPARISONDIR` environment variable, whose value is the relative path of a directory that Testilo can write to.
71
- - The `procs/compare` directory contains a subdirectory named `xyz`, which in turn contains files named `index.html` and `index.js`.
72
- - You have copied the `reports/comparative/style.css` file into the `COMPARISONDIR` directory.
147
+ The comparisons created by `compare` are HTML files, and they expect a `style.css` file to exist in their directory. The `reports/comparative/style.css` file in Testilo is an appropriate stylesheet to be copied into `process.env.COMPARISONDIR`.
package/compare.js CHANGED
@@ -1,7 +1,12 @@
1
1
  /*
2
2
  compare.js
3
- Testilo comparison script.
4
- Usage example: node compare cp12a candidates
3
+ Creates comparisons from scored reports.
4
+ Reads reports in process.env.REPORTDIR_SCORED and outputs into process.env.COMPARISONDIR.
5
+ Arguments:
6
+ 0. Base of name of compare proc located in procs/compare.
7
+ 1. Base of name of comparative report to be written.
8
+ Usage example: node compare cp18a usFedExec
9
+ Note: Compares all reports in process.env.REPORTDIR_SCORED (but not in its subdirectories).
5
10
  */
6
11
 
7
12
  // ########## IMPORTS
package/digest.js CHANGED
@@ -1,7 +1,13 @@
1
1
  /*
2
2
  digest.js
3
- Testilo digesting script.
4
- Usage example: node digest 35k1r-railpass dp10a
3
+ Creates digests from scored reports.
4
+ Reads reports in process.env.REPORTDIR_SCORED and outputs into process.env.REPORTDIR_DIGESTED.
5
+ Arguments:
6
+ 0. Base of name of digest proc located in procs/digest.
7
+ 1?. starting substring of names of reports in process.env.REPORTDIR_SCORED.
8
+ Usage examples:
9
+ node digest dp18a 35k1r (to digest all scored reports with names starting with 35k1r)
10
+ node digest dp18a (to digest all scored reports)
5
11
  */
6
12
 
7
13
  // ########## IMPORTS
@@ -23,7 +29,7 @@ const reportIDStart = process.argv[3];
23
29
  // Replaces the placeholders in content with eponymous query parameters.
24
30
  const replaceHolders = (content, query) => content
25
31
  .replace(/__([a-zA-Z]+)__/g, (ph, qp) => query[qp]);
26
- // Creates a digest.
32
+ // Creates digests.
27
33
  const digest = async () => {
28
34
  const reportDirScoredAbs = `${__dirname}/${reportDirScored}`;
29
35
  let reportFileNames = await fs.readdir(reportDirScoredAbs);
package/merge.js ADDED
@@ -0,0 +1,72 @@
1
+ /*
2
+ merge.js
3
+ Merges a batch and a script to produce jobs.
4
+ Arguments:
5
+ 0. base of name of script located in process.env.SCRIPTDIR.
6
+ 1. base of name of batch located in process.env.BATCHDIR.
7
+ 2. name of subdirectory of process.env.JOBDIR into which to write host scripts.
8
+ Usage example:
9
+ node merge tp18 weborgs tp18-weborgs-1
10
+ Note: The subdirectory for host scripts will be created if it does not exist.
11
+ */
12
+
13
+ // ########## IMPORTS
14
+
15
+ // Module to keep secrets.
16
+ require('dotenv').config();
17
+ // Module to read and write files.
18
+ const fs = require('fs/promises');
19
+
20
+ // ########## CONSTANTS
21
+
22
+ const scriptDir = process.env.SCRIPTDIR || 'scripts';
23
+ const batchDir = process.env.BATCHDIR || 'batches';
24
+ const jobDir = process.env.JOBDIR || 'jobs';
25
+ const scriptName = process.argv[2];
26
+ const batchName = process.argv[3];
27
+ const jobSubdir = process.argv[4];
28
+
29
+ // ########## FUNCTIONS
30
+
31
+ // Merges a batch into a script and writes host scripts.
32
+ const merge = async (script, batch, timeStamp, outDir) => {
33
+ await fs.mkdir(outDir, {recursive: true});
34
+ const {hosts} = batch;
35
+ // For each host in the batch:
36
+ const jobs = hosts.map(host => {
37
+ // Copy the script.
38
+ const newScript = JSON.parse(JSON.stringify(script));
39
+ // In the copy, make all url commands visit the host.
40
+ newScript.commands.forEach(command => {
41
+ if (command.type === 'url') {
42
+ command.which = host.which;
43
+ command.what = host.what;
44
+ }
45
+ });
46
+ // Create a host script.
47
+ return {
48
+ id: `${timeStamp}-${host.id}`,
49
+ host,
50
+ script: newScript
51
+ };
52
+ });
53
+ // Write the host scripts.
54
+ for (const job of jobs) {
55
+ await fs.writeFile(`${outDir}/${job.id}.json`, JSON.stringify(job, null, 2));
56
+ };
57
+ console.log(`Merger completed. Count of jobs created: ${hosts.length}`);
58
+ };
59
+
60
+ // ########## OPERATION
61
+
62
+ fs.readFile(`${scriptDir}/${scriptName}.json`, 'utf8')
63
+ .then(scriptFile => {
64
+ fs.readFile(`${batchDir}/${batchName}.json`, 'utf8')
65
+ .then(async batchFile => {
66
+ const script = JSON.parse(scriptFile);
67
+ const batch = JSON.parse(batchFile);
68
+ const timeStamp = Math.floor((Date.now() - Date.UTC(2022, 1)) / 2000).toString(36);
69
+ const outDir = `${jobDir}/${jobSubdir}`;
70
+ await merge(script, batch, timeStamp, outDir);
71
+ });
72
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "testilo",
3
- "version": "3.12.3",
3
+ "version": "4.0.0",
4
4
  "description": "Client that scores and digests Testaro reports",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -42,7 +42,7 @@
42
42
  </ul>
43
43
  <p>Testaro produced a report enumerating the test results.</p>
44
44
  <p><a href="https://www.npmjs.com/package/testilo">Testilo</a> processed the report and used the <code>sp16a</code> scoring procedure to compute partial and total scores for the page. The total score is __totalScore__ (where 0 is the best possible score). The scored report is appended below.</p>
45
- <p>Finally, Testilo used procedure <code>dp16a</code> to produce this digest, briefly explaining how <code>sp15c</code> computed the scores.</p>
45
+ <p>Finally, Testilo used procedure <code>dp16a</code> to produce this digest, briefly explaining how <code>sp16a</code> computed the scores.</p>
46
46
  <h2>Score summary</h2>
47
47
  <table class="allBorder secondCellRight">
48
48
  <caption>Score components</caption>
@@ -0,0 +1,80 @@
1
+ <!DOCTYPE HTML>
2
+ <html lang="en-US">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1">
6
+ <meta name="author" content="Testilo">
7
+ <meta name="creator" content="Testilo">
8
+ <meta name="publisher" name="Testilo">
9
+ <meta name="description" content="report of accessibility testing of a web page">
10
+ <meta name="keywords" content="accessibility a11y web testing">
11
+ <title>Accessibility test digest</title>
12
+ <link rel="icon" href="favicon.png">
13
+ <link rel="stylesheet" href="style.css">
14
+ </head>
15
+ <body>
16
+ <main>
17
+ <header>
18
+ <h1>Accessibility test digest</h1>
19
+ <h2>Synopsis</h2>
20
+ <div id="synopsis">
21
+ <p><strong>Page</strong>: __org__</p>
22
+ <p><strong>URL</strong>: __url__</p>
23
+ <p><strong>Score</strong>: __totalScore__</p>
24
+ <p><strong>Tested by</strong>: Testaro, procedure <code>__tp__</code></p>
25
+ <p><strong>Scored by</strong>: Testilo, procedure <code>__sp__</code></p>
26
+ <p><strong>Digested by</strong>: Testilo, procedure <code>__dp__</code></p>
27
+ </div>
28
+ </header>
29
+ <h2>Introduction</h2>
30
+ <p>The <a href="https://www.npmjs.com/package/testaro">Testaro</a> application used its <code>__tp__</code> testing procedure to test the <a href="https://www.w3.org/WAI/fundamentals/accessibility-intro/"><dfn>accessibility</dfn></a> (barrier-free design and coding) of the __org__ web page at <a href="__url__">__url__</a> on __dateSlash__. The procedure performed 1230 tests. Of these, 24 are custom tests or <q>quasi-tests</q> by Testaro, and the others belong to these eight other packages (programs that perform collections of tests):</p>
31
+ <ul>
32
+ <li><a href="https://github.com/Siteimprove/alfa">Alfa</a> by Siteimprove</li>
33
+ <li><a href="https://www.npmjs.com/package/axe-core">Axe-core</a> by Deque</li>
34
+ <li><a href="https://www.webaccessibility.com/tools/">Continuum</a> by Level Access</li>
35
+ <li>
36
+ <a href="https://www.npmjs.com/package/html_codesniffer">HTML CodeSniffer</a> by Squiz Labs
37
+ </li>
38
+ <li><a href="https://github.com/IBMa/equal-access">Equal Access</a> by IBM</li>
39
+ <li><a href="https://github.com/validator/validator">Nu Html Checker</a></li>
40
+ <li><a href="https://tenon.io/documentation/apiv2.php">Tenon</a> by Level Access</li>
41
+ <li><a href="https://wave.webaim.org/api/">WAVE</a> by WebAIM</li>
42
+ </ul>
43
+ <p>Testaro produced a report enumerating the test results.</p>
44
+ <p><a href="https://www.npmjs.com/package/testilo">Testilo</a> processed the report and used the <code>__sp__</code> scoring procedure to compute partial and total scores for the page. The total score is __totalScore__ (where 0 is the best possible score). The scored report is appended below.</p>
45
+ <p>Finally, Testilo used procedure <code>__dp__</code> to produce this digest, briefly explaining how <code>__sp__</code> computed the scores.</p>
46
+ <h2>Score summary</h2>
47
+ <table class="allBorder secondCellRight">
48
+ <caption>Score components</caption>
49
+ <tbody class="headersLeft">
50
+ __scoreRows__
51
+ </tbody>
52
+ </table>
53
+ <h2>Issue summary</h2>
54
+ <h3>Special issues</h3>
55
+ __specialSummary__
56
+ <h3>Classified issues</h3>
57
+ __groupSummary__
58
+ <h2>Discussion</h2>
59
+ <p>Although there are widely accepted <a href="https://www.w3.org/WAI/standards-guidelines/">accessibility standards</a>, there is no unanimity about how to define, test, and quantify accessibility. The failures reported in this digest merit investigation as potential opportunities for improved accessibility. Investigation may lead you to conclude that some of the reported failures do not actually harm accessibility. Conversely, some substantial accessibility faults can escape detection by any of these tests. You may question the attempt to assign an accessibility score to a web page, or you may prefer weightings and formulas different from those used by <code>__sp__</code>. You can modify and extend Testaro and Testilo to fit other theories and priorities.</p>
60
+ <p>Here, in brief, is how <code>__sp__</code> computes a score for a page.</p>
61
+ <ul>
62
+ <li>It finds all the defects and warnings (let&rsquo;s call them <q>issues</q>) recorded in the report.</li>
63
+ <li>It classifies them according to type. For example, a link that looks like the text around it is one issue category, while a video that has no captions is another issue category.</li>
64
+ <li>It also classifies the issues according to severity. For example, an issue that prevents a transaction is more severe than an issue that only complicates the transaction, and a warning about a possible issue is less severe than a definite finding of an issue. (Some packages rate the severity of each issue; for the other packages, <code>sp15c</code> assigns a severity weight to the issue type and uses that weight.)</li>
65
+ <li>It assigns quality ratings to particular tests that are judged abnormally reliable or unreliable.</li>
66
+ <li>It assigns a score to each issue reported by each test of each package.</li>
67
+ <li>It aggregates the issue scores, weighting them by severity, test quality, and redundancy. Redundancy occurs, and causes downweighting, when two or more packages contain tests that are designed to discover the same or mostly the same issues. So the score for a category is not simply the sum of the scores of the tests in that category.</li>
68
+ <li>It assigns a score for issues in the page logged by the browser.</li>
69
+ <li>It assigns an estimated score each time the page prevents one of the packages or one of the Testaro tests from being run on the page.</li>
70
+ <li>It adds the scores together to obtain a total score.</li>
71
+ </ul>
72
+ <p>The precise rules of <code>__sp__</code> are found in the <a href="https://github.com/jrpool/testilo/blob/main/procs/score/__sp__.js">code itself</a>.</p>
73
+ <h2>Report</h2>
74
+ <pre>__report__</pre>
75
+ <footer>
76
+ <p class="date">Produced <time itemprop="datePublished" datetime="__dateISO__">__dateSlash__</time></p>
77
+ </footer>
78
+ </main>
79
+ </body>
80
+ </html>
@@ -0,0 +1,129 @@
1
+ /*
2
+ index: digester for scoring procedure sp18a.
3
+ Creator of parameters for substitution into index.html.
4
+ Usage example for selected files in REPORTDIR_SCORED: node digest dp18a 35k1r
5
+ Usage example for all files in REPORTDIR_SCORED: node digest dp18a
6
+ */
7
+
8
+ // CONSTANTS
9
+
10
+ // Newlines with indentations.
11
+ const joiner = '\n ';
12
+ const innerJoiner = '\n ';
13
+ const specialMessages = {
14
+ log: 'This is based on the amount of browser error logging and miscellaneous logging during the tests.',
15
+ preventions: 'This is based on tests that the page did not allow to be run. That impedes accessibility progress and risks interfering with tools that users with disabilities need.',
16
+ solos: 'This is based on issues reported by unclassified tests. Details are in the report.'
17
+ };
18
+
19
+ // FUNCTIONS
20
+
21
+ // Makes strings HTML-safe.
22
+ const htmlEscape = textOrNumber => textOrNumber
23
+ .toString()
24
+ .replace(/&/g, '&amp;')
25
+ .replace(/</g, '&lt;');
26
+ // Gets a row of the score-summary table.
27
+ const getScoreRow = (component, score) => `<tr><th>${component}</th><td>${score}</td></tr>`;
28
+ // Gets the start of a paragraph about a special score.
29
+ const getSpecialPStart = (summary, scoreID) =>
30
+ `<p><span class="componentID">${scoreID}</span>: Score ${summary[scoreID]}.`;
31
+ // Adds parameters to a query for a digest.
32
+ exports.makeQuery = (report, query) => {
33
+ // Add an HTML-safe copy of the host report to the query to be appended to the digest.
34
+ const {script, host, score} = report;
35
+ const reportJSON = JSON.stringify(report, null, 2);
36
+ const reportJSONSafe = htmlEscape(reportJSON);
37
+ query.report = reportJSONSafe;
38
+ query.tp = 'tp18';
39
+ query.sp = 'sp18a';
40
+ query.dp = 'dp18a';
41
+ // Add the job data to the query.
42
+ query.dateISO = report.endTime.slice(0, 10);
43
+ query.dateSlash = query.dateISO.replace(/-/g, '/');
44
+ if (host && host.what && host.which) {
45
+ query.org = host.what;
46
+ query.url = host.which;
47
+ }
48
+ else {
49
+ const firstURLCommand = script.commands.find(command => command.type === 'url');
50
+ if (firstURLCommand && firstURLCommand.what && firstURLCommand.which) {
51
+ query.org = firstURLCommand.what;
52
+ query.url = firstURLCommand.which;
53
+ }
54
+ else {
55
+ console.log('ERROR: host missing or invalid');
56
+ return;
57
+ }
58
+ }
59
+ const {groupDetails, summary} = score;
60
+ const {total, groups} = summary;
61
+ if (typeof total === 'number') {
62
+ query.totalScore = total;
63
+ }
64
+ else {
65
+ console.log('ERROR: missing or invalid total score');
66
+ return;
67
+ }
68
+ // Add the total and any special rows of the score-summary table to the query.
69
+ const scoreRows = [];
70
+ const specialComponentIDs = ['log', 'preventions', 'solos'];
71
+ ['total'].concat(specialComponentIDs).forEach(item => {
72
+ if (summary[item]) {
73
+ scoreRows.push(getScoreRow(item, summary[item]));
74
+ }
75
+ });
76
+ // Add the group rows of the score-summary table to the query.
77
+ groups.forEach(group => {
78
+ scoreRows.push(getScoreRow(`${group.groupName}`, group.score));
79
+ });
80
+ query.scoreRows = scoreRows.join(innerJoiner);
81
+ // If the score has any special components:
82
+ const scoredSpecialIDs = specialComponentIDs.filter(item => summary[item]);
83
+ if (scoredSpecialIDs.length) {
84
+ // Add paragraphs about them for the issue summary to the query.
85
+ const specialPs = [];
86
+ scoredSpecialIDs.forEach(id => {
87
+ specialPs.push(`${getSpecialPStart(summary, id)} ${specialMessages[id]}`);
88
+ });
89
+ query.specialSummary = specialPs.join(joiner);
90
+ }
91
+ // Otherwise, i.e. if the score has no special components:
92
+ else {
93
+ // Add a paragraph stating this for the issue summary to the query.
94
+ query.specialSummary = '<p>No special issues contributed to the score.</p>'
95
+ }
96
+ // If the score has any classified issues as components:
97
+ if (groups.length) {
98
+ // Add paragraphs about them for the special summary to the query.
99
+ const groupSummaryItems = [];
100
+ groups.forEach(group => {
101
+ const {groupName, score} = group;
102
+ const groupP = `<p><span class="componentID">${groupName}</span>: Score ${score}. Issues reported by tests in this category:</p>`;
103
+ const groupListItems = [];
104
+ const groupData = groupDetails.groups[groupName];
105
+ const packageIDs = Object.keys(groupData);
106
+ packageIDs.forEach(packageID => {
107
+ const testIDs = Object.keys(groupData[packageID]);
108
+ testIDs.forEach(testID => {
109
+ const testData = groupData[packageID][testID];
110
+ const {score, what} = testData;
111
+ const listItem = `<li>Package <code>${packageID}</code>, test <code>${testID}</code>, score ${score} (${what})</li>`;
112
+ groupListItems.push(listItem);
113
+ });
114
+ });
115
+ const groupList = [
116
+ '<ul>',
117
+ groupListItems.join('\n '),
118
+ '</ul>'
119
+ ].join(joiner);
120
+ groupSummaryItems.push(groupP, groupList);
121
+ });
122
+ query.groupSummary = groupSummaryItems.join(joiner);
123
+ }
124
+ // Otherwise, i.e. if the score has no classified issues as components:
125
+ else {
126
+ // Add a paragraph stating this for the group summary to the query.
127
+ query.groupSummary = '<p>No classified issues contributed to the score.</p>'
128
+ }
129
+ };
@@ -1,5 +1,5 @@
1
1
  /*
2
- sp16a
2
+ sp16b
3
3
  Testilo score proc 16b
4
4
 
5
5
  Computes scores from Testaro script tp16 and adds them to a report.