testilo 3.9.8 → 3.9.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "testilo",
3
- "version": "3.9.8",
3
+ "version": "3.9.11",
4
4
  "description": "Client that scores and digests Testaro reports",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -0,0 +1,68 @@
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>tpA11yMessage</code></p>
25
+ <p><strong>Scored by</strong>: Testilo, procedure <code>spA11yMessage</code></p>
26
+ <p><strong>Digested by</strong>: Testilo, procedure <code>dpA11yMessage</code></p>
27
+ </div>
28
+ </header>
29
+ <h2>Introduction</h2>
30
+ <p>This is a report on transactional <a href="https://www.w3.org/WAI/fundamentals/accessibility-intro/">accessibility</a>. Suppose a person is visiting a website and wants to engage in some transaction with it. Is the transaction easy, predictable, and safe? If so, the website is <dfn>transactionally accessible</dfn>. Some disabilities make it difficult to discover how to do things on a website. Everybody, but especially any person with such a disability, benefits from transactions being designed to conform to the most common and standard conventions.</p>
31
+ <p>This report deals with an issue-reporting transaction. Specifically, the transaction begins when a person notices an accessibility issue on a page or view of a website or web application and wants to report that issue to whoever is responsible for the website. The simple, standard, and thus predictable transaction is assumed to look like this:</p>
32
+ <ol>
33
+ <li>The person finds an accessibility link on the page.</li>
34
+ <li>The person clicks that link.</li>
35
+ <li>That link takes the person to an accessibility page.</li>
36
+ <li>On the accessibility page, there is a link for sending an email message about accessibility, and there is another link for making a telephone call about accessibility.</li>
37
+ </ol>
38
+ <p>Thus, instead of the person needing to figure out how this particular website accepts issue reports, the person is assumed already to know how websites normally accept issue reports. So, instead of exploring the site to find its method, the person uses the standard method.</p>
39
+ <h2>Procedures</h2>
40
+ <p>The <a href="https://www.npmjs.com/package/testaro">Testaro</a> application used its <code>tpA11yMessage</code> testing procedure to evaluate the accessibility of this transaction on the __org__ web page at <a href="__url__">__url__</a> on __dateSlash__. Testaro produced a report.</p>
41
+ <p>The <a href="https://www.npmjs.com/package/testilo">Testilo</a> application processed the report and used the <code>spA11yMessage</code> scoring procedure to compute a score for the transaction. The total score is __totalScore__ (where 0 is the worst and 16 is the best possible score). The scored report is appended below.</p>
42
+ <p>Finally, Testilo used procedure <code>dpA11yMessage</code> to produce this digest, briefly explaining how <code>spA11yMessage</code> computed the scores.</p>
43
+ <h2>Score summary</h2>
44
+ <table class="allBorder secondCellRight">
45
+ <caption>Score components</caption>
46
+ <tbody class="headersLeft">
47
+ __scoreRows__
48
+ </tbody>
49
+ </table>
50
+ <h2>Discussion</h2>
51
+ <p>The components of the total score are:</p>
52
+ <ul>
53
+ <li><code>page</code>: Can the page be visited?</li>
54
+ <li><code>a11yLink</code>: Does the page have a functioning <q>accessibility</q> link?</li>
55
+ <li><code>title</code>: Is the page to which the link goes titled to show it is about accessibility?</li>
56
+ <li><code>heading</code>: Does that page (the accessibility page) have a top heading indicating the page is about accessibility?</li>
57
+ <li><code>mailLink</code>: Does the accessibility page have a link to send email about accessibility?.</li>
58
+ <li><code>telLink</code>: Does the accessibility page have a link to make a telephone call about accessibility?</li>
59
+ </ul>
60
+ <p>The precise rules of <code>spA11yMessage</code> are found in the <a href="https://github.com/jrpool/testilo/blob/main/procs/score/spA11yMessage.js">code itself</a>.</p>
61
+ <h2>Report</h2>
62
+ <pre>__report__</pre>
63
+ <footer>
64
+ <p class="date">Produced <time itemprop="datePublished" datetime="__dateISO__">__dateSlash__</time></p>
65
+ </footer>
66
+ </main>
67
+ </body>
68
+ </html>
@@ -0,0 +1,55 @@
1
+ /*
2
+ index: digester for scoring procedure spA11yMessage.
3
+ Creator of parameters for substitution into index.html.
4
+ Usage example for selected files in REPORTDIR_SCORED: node digest dpA11yMessage 35k1r
5
+ Usage example for all files in REPORTDIR_SCORED: node digest dpA11yMessage
6
+ */
7
+
8
+ // CONSTANTS
9
+
10
+ // Newlines with indentations.
11
+ const joiner = '\n ';
12
+ const innerJoiner = '\n ';
13
+
14
+ // FUNCTIONS
15
+
16
+ // Makes strings HTML-safe.
17
+ const htmlEscape = textOrNumber => textOrNumber
18
+ .toString()
19
+ .replace(/&/g, '&amp;')
20
+ .replace(/</g, '&lt;');
21
+ // Gets a row of the score-summary table.
22
+ const getScoreRow = (component, score) => `<tr><th>${component}</th><td>${score}</td></tr>`;
23
+ // Adds parameters to a query for a digest.
24
+ exports.makeQuery = (report, query) => {
25
+ // Add an HTML-safe copy of the host report to the query to be appended to the digest.
26
+ const {script, host, score} = report;
27
+ const reportJSON = JSON.stringify(report, null, 2);
28
+ const reportJSONSafe = htmlEscape(reportJSON);
29
+ query.report = reportJSONSafe;
30
+ // Add the job data to the query.
31
+ query.dateISO = report.endTime.slice(0, 10);
32
+ query.dateSlash = query.dateISO.replace(/-/g, '/');
33
+ if (host && host.what && host.which) {
34
+ query.org = host.what;
35
+ query.url = host.which;
36
+ }
37
+ else {
38
+ const firstURLCommand = script.commands.find(command => command.type === 'url');
39
+ if (firstURLCommand && firstURLCommand.what && firstURLCommand.which) {
40
+ query.org = firstURLCommand.what;
41
+ query.url = firstURLCommand.which;
42
+ }
43
+ else {
44
+ console.log('ERROR: host missing or invalid');
45
+ return;
46
+ }
47
+ }
48
+ // Add the score data to the query.
49
+ const scoreRows = [];
50
+ Object.keys(score).forEach(scoreName => {
51
+ scoreRows.push(getScoreRow(scoreName, score[scoreName]));
52
+ });
53
+ query.totalScore = score.total;
54
+ query.scoreRows = scoreRows.join(innerJoiner);
55
+ };
@@ -8,7 +8,8 @@
8
8
  node score a11yMessage
9
9
 
10
10
  This proc computes a score that is intended to represent how accessibly a web page offers
11
- a user an opportunity to report an accessibility issue about that page.
11
+ a user an opportunity to report an accessibility issue about that page. Scores can range
12
+ from 0 to 16.
12
13
  */
13
14
 
14
15
  // CONSTANTS
@@ -18,67 +19,80 @@ const scoreProcID = 'a11ymessage';
18
19
 
19
20
  // FUNCTIONS
20
21
 
22
+ // Scores the contact links of a type.
23
+ const contactScorer = (result, score, type) => {
24
+ const links = result.items;
25
+ score[type] += 1;
26
+ if (
27
+ links.some(
28
+ link => link.textContent.toLowerCase().includes('accessibility')
29
+ )
30
+ ) {
31
+ score[type] += 2;
32
+ }
33
+ else if (
34
+ links.some(
35
+ link => link.parentTextContent.toLowerCase().includes('accessibility')
36
+ )
37
+ ) {
38
+ score[type] += 1;
39
+ }
40
+ };
21
41
  // Scores a report.
22
42
  exports.scorer = async report => {
23
43
  const {acts} = report;
24
44
  report.score = {
25
- scoreProcID,
45
+ page: 0,
46
+ a11yLink: 0,
47
+ title: 0,
48
+ heading: 0,
49
+ mailLink: 0,
50
+ telLink: 0,
26
51
  total: 0
27
52
  };
28
53
  const {score} = report;
29
54
  if (Array.isArray(acts)) {
30
- // Act 1: page load.
55
+ // Act 1: page loads.
31
56
  if (acts[1].result.startsWith('http')) {
32
- score.total += 2;
33
- // Act 2: click an accessibility link.
57
+ score.page = 2;
58
+ // Act 2: accessibility link exists and loads promptly.
34
59
  if (acts[2].result.move === 'clicked') {
35
- score.total += 2;
36
- // Act 4: next page has an accessibility title.
37
- const act4Result = acts[4].result;
38
- if (act4Result && act4Result.toLowerCase().includes('accessibility')) {
39
- score.total += 2;
40
- // Act 5: page has exactly 1 h1 heading.
41
- const act5Result = acts[5].result;
42
- if (act5Result && act5Result.total === 1) {
43
- score.total += 2;
44
- // Act 5: h1 is an accessibility heading.
45
- if (act5Result.items[0].textContent.toLowerCase().includes('accessibility')) {
46
- score.total += 2;
60
+ score.a11yLink = 2;
61
+ const loadScore = ['incomplete', 'loaded', 'idle'].indexOf(acts[2].result.loadState);
62
+ if (loadScore > -1) {
63
+ score.a11yLink += loadScore;
64
+ }
65
+ // Act 3: next page has an accessibility title.
66
+ const act3Result = acts[3].result;
67
+ if (act3Result && act3Result.toLowerCase().includes('accessibility')) {
68
+ score.title = 2;
69
+ // Act 4: page has exactly 1 h1 heading.
70
+ const act4Result = acts[4].result;
71
+ if (act4Result && act4Result.total === 1) {
72
+ score.heading = 1;
73
+ // Act 4: h1 is an accessibility heading.
74
+ if (act4Result.items[0].textContent.toLowerCase().includes('accessibility')) {
75
+ score.heading += 1;
47
76
  }
48
77
  }
49
78
  }
79
+ // Act 5: page has accessibility email and telephone links.
80
+ const act5Result = acts[5].result;
81
+ if (act5Result.total) {
82
+ contactScorer(act5Result, score, 'mailLink');
83
+ }
50
84
  // Act 6: page has accessibility email and telephone links.
51
85
  const act6Result = acts[6].result;
52
86
  if (act6Result.total) {
53
- const mailLinks = act6Result.items.filter(item => item.attributes.some(
54
- attribute => attribute.name === 'href' && attribute.value.startsWith('mailto:')
55
- ));
56
- const telLinks = act6Result.items.filter(item => item.attributes.some(
57
- attribute => attribute.name === 'href' && attribute.value.startsWith('tel:')
58
- ));
59
- [mailLinks, telLinks].forEach(linkArray => {
60
- if (linkArray.length) {
61
- score.total += 2;
62
- if (
63
- linkArray.some(link => link.textContent.toLowerCase().includes('accessibility'))
64
- ) {
65
- score.total += 2;
66
- }
67
- else if (
68
- linkArray.some(
69
- link => ['before', 'after'].some(
70
- side => link.siblings[side].some(
71
- sib => sib.type === 3 && sib.text.toLowerCase().includes('accessibility')
72
- )
73
- )
74
- )
75
- ) {
76
- score.total += 1;
77
- }
78
- }
79
- });
87
+ contactScorer(act6Result, score, 'telLink');
80
88
  }
81
89
  }
82
90
  }
83
91
  }
92
+ score.total = score.page
93
+ + score.a11yLink
94
+ + score.title
95
+ + score.heading
96
+ + score.mailLink
97
+ + score.telLink;
84
98
  };
package/score.js CHANGED
@@ -38,7 +38,7 @@ const score = async () => {
38
38
  const reportJSON = await fs.readFile(`${reportDirRawAbs}/${fileName}`, 'utf8');
39
39
  const report = JSON.parse(reportJSON);
40
40
  await scorer(report);
41
- report.score.scoreProcID = scoreProcID;
41
+ report.scoreProcID = scoreProcID;
42
42
  // Write it to a file.
43
43
  const scoredReportJSON = JSON.stringify(report, null, 2);
44
44
  await fs.writeFile(`${__dirname}/${reportDirScored}/${fileName}`, `${scoredReportJSON}\n`);