testaro 22.0.0 → 23.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
@@ -144,14 +144,9 @@ Here is an example of a job:
144
144
  {
145
145
  type: 'launch',
146
146
  which: 'chromium',
147
+ url: 'https://www.w3c.org',
147
148
  what: 'Chromium browser'
148
149
  },
149
- {
150
- type: 'url',
151
- which: 'https://www.w3c.org',
152
- what: 'World Wide Web Consortium',
153
- id: 'w3c'
154
- },
155
150
  {
156
151
  type: 'test',
157
152
  which: 'alfa',
@@ -174,9 +169,8 @@ Here is an example of a job:
174
169
  }
175
170
  ```
176
171
 
177
- This job contains three _acts_, telling Testaro to:
178
- 1. open a page in the Chromium browser
179
- 1. navigate to a specified URL
172
+ This job contains two _acts_, telling Testaro to:
173
+ 1. open a page in the Chromium browser and navigate to a specified URL
180
174
  1. perform two of the tests of the `alfa` tool (the tests for rules `r25` and `r71`) on that URL
181
175
 
182
176
  Job properties:
@@ -306,7 +300,7 @@ Each act object has a `type` property and optionally has a `name` property (used
306
300
 
307
301
  #### Act sequence
308
302
 
309
- The first two acts in any job have the types `launch` and `url`, respectively, as shown in the example above. They launch a browser and then use it to visit a URL.
303
+ The first act in any job has the type `launch`, as shown in the example above. It launches a browser and then uses it to visit a URL.
310
304
 
311
305
  #### Act types
312
306
 
@@ -338,11 +332,9 @@ When the texts of multiple elements of the same type will contain the same `whic
338
332
 
339
333
  ##### Navigations
340
334
 
341
- An example of a **navigation** is the act of type `url` above.
342
-
343
- Once you have included a `url` act in a job, you do not need to add more `url` acts unless you want the browser to visit a different URL or revisit the same URL.
335
+ An example of a **navigation** is the act of type `launch` above.
344
336
 
345
- If any act alters the page, you can restore the page to its original state for the next act by inserting new `launch` and `url` acts (and, if necessary, additional page-specific acts) between them.
337
+ 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.
346
338
 
347
339
  Another navigation example is:
348
340
 
@@ -585,7 +577,7 @@ The `rules` property for `testaro` is an array whose first item is either `'y'`
585
577
 
586
578
  The `testaro` tool (like the `ibm` tool) has a `withItems` property. If you set it to `false`, the `standardResult` object of `testaro` will contain an `instances` property with summaries that identify issues and instance counts. If you set it to `true`, some of the instances will be itemized.
587
579
 
588
- Unlike any other tool, the `testaro` tools requires a `stopOnFail` property, which specifies whether a failure to conform to any rule (i.e. any value of `totals` other than `[0, 0, 0, 0]`) should terminate the execution of tests for the remaining rules.
580
+ Unlike any other tool, the `testaro` tool requires a `stopOnFail` property, which specifies whether a failure to conform to any rule (i.e. any value of `totals` other than `[0, 0, 0, 0]`) should terminate the execution of tests for the remaining rules.
589
581
 
590
582
  Warnings in the `testaro/hover.js`, `testaro/motion.js`, and `procs/visChange.js` files advise you to avoid launching particular browser types for the performance of particular Testaro tests.
591
583
 
@@ -622,6 +614,26 @@ This act checks the result of the previous act to determine whether its `result.
622
614
 
623
615
  A `next` act can use a `next` property instead of a `jump` property. The value of the `next` property is an act name. It tells Testaro to continue performing acts starting with the act having that value as the value of its `name` property.
624
616
 
617
+ #### Browser types
618
+
619
+ After any act in a job, you can change the browser type by inserting a `launch` act. One reason for specifying a particular browser type is that particular tests have different results with different browser types. Another is that you may wish to perform tests with more than a single browser type.
620
+
621
+ The warning comments in the `testaro/hover.js` and `testaro/motion.js` files state that those tests operate correctly only with the `webkit` browser type.
622
+
623
+ When you want to run some tests of a tool with one browser type and other tests of the same tool with another browser type, you can do so by splitting the rules into two test acts. For example, one test act can specify the rules as
624
+
625
+ ```javascript
626
+ ['y', 'r15', 'r54']
627
+ ```
628
+
629
+ and the other test act can specify the rules as
630
+
631
+ ```javascript
632
+ ['n', 'r15', 'r54']
633
+ ```
634
+
635
+ Before each test act, you can ensure that the latest `launch` act has specified the browser type to be used in that test act.
636
+
625
637
  #### `actSpecs` file
626
638
 
627
639
  ##### Introduction
package/actSpecs.js CHANGED
@@ -27,9 +27,10 @@ exports.actSpecs = {
27
27
  launch: [
28
28
  'Launch a Playwright browser',
29
29
  {
30
- which: [true, 'string', 'isBrowserType', 'chromium”, firefox”, or webkit'],
31
- what: [false, 'string', 'hasLength', 'comment'],
32
- lowMotion: [false, 'boolean', '', 'set reduced-motion option if true']
30
+ which: [true, 'string', 'isBrowserType', 'chromium, firefox, or webkit'],
31
+ url: [true, 'string', 'isURL', 'initial URL to navigate to'],
32
+ lowMotion: [false, 'boolean', '', 'set reduced-motion option if true'],
33
+ what: [false, 'string', 'hasLength', 'comment']
33
34
  }
34
35
  ],
35
36
  link: [
package/dirWatch.js CHANGED
@@ -34,11 +34,11 @@ const reWatch = () => {
34
34
  }
35
35
  if (code === 0) {
36
36
  console.log('Watcher exited successfully');
37
+ reWatch();
37
38
  }
38
39
  else {
39
40
  console.log(`Watcher exited with error code ${code}`);
40
41
  }
41
- reWatch();
42
42
  });
43
43
  };
44
44
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "testaro",
3
- "version": "22.0.0",
3
+ "version": "23.0.0",
4
4
  "description": "Run 920 web accessibility tests from 9 tools and get a standardized report",
5
5
  "main": "index.js",
6
6
  "scripts": {
package/procs/nav.js ADDED
@@ -0,0 +1,220 @@
1
+ // nav
2
+
3
+ // ######## IMPORTS
4
+
5
+ // Playwright package.
6
+ const playwright = require('playwright');
7
+
8
+ // ######## CONSTANTS
9
+
10
+ // Strings in log messages indicating errors.
11
+ const errorWords = [
12
+ 'but not used',
13
+ 'content security policy',
14
+ 'deprecated',
15
+ 'error',
16
+ 'exception',
17
+ 'expected',
18
+ 'failed',
19
+ 'invalid',
20
+ 'missing',
21
+ 'non-standard',
22
+ 'not supported',
23
+ 'refused',
24
+ 'requires',
25
+ 'sorry',
26
+ 'suspicious',
27
+ 'unrecognized',
28
+ 'violates',
29
+ 'warning'
30
+ ];
31
+
32
+ // ######## VARIABLES
33
+
34
+ let browser;
35
+
36
+ // ######## FUNCTIONS
37
+
38
+ // Returns a string with any final slash removed.
39
+ const deSlash = string => string.endsWith('/') ? string.slice(0, -1) : string;
40
+ // Visits a URL and returns the response of the server.
41
+ const goTo = async (report, page, url, timeout, waitUntil) => {
42
+ if (url.startsWith('file://')) {
43
+ url = url.replace('file://', `file://${__dirname}/`);
44
+ }
45
+ // Visit the URL.
46
+ const startTime = Date.now();
47
+ try {
48
+ const response = await page.goto(url, {
49
+ timeout,
50
+ waitUntil
51
+ });
52
+ report.jobData.visitLatency += Math.round((Date.now() - startTime) / 1000);
53
+ const httpStatus = response.status();
54
+ // If the response status was normal:
55
+ if ([200, 304].includes(httpStatus) || url.startsWith('file:')) {
56
+ // If the browser was redirected in violation of a strictness requirement:
57
+ const actualURL = page.url();
58
+ if (report.strict && deSlash(actualURL) !== deSlash(url)) {
59
+ // Return an error.
60
+ console.log(`ERROR: Visit to ${url} redirected to ${actualURL}`);
61
+ return {
62
+ exception: 'badRedirection'
63
+ };
64
+ }
65
+ // Otherwise, i.e. if no prohibited redirection occurred:
66
+ else {
67
+ // Press the Escape key to dismiss any modal dialog.
68
+ await page.keyboard.press('Escape');
69
+ // Return the response.
70
+ return response;
71
+ }
72
+ }
73
+ // Otherwise, i.e. if the response status was abnormal:
74
+ else {
75
+ // Return an error.
76
+ console.log(`ERROR: Visit to ${url} got status ${httpStatus}`);
77
+ report.jobData.visitRejectionCount++;
78
+ return {
79
+ error: 'badStatus'
80
+ };
81
+ }
82
+ }
83
+ catch(error) {
84
+ console.log(`ERROR visiting ${url} (${error.message.slice(0, 200)})`);
85
+ return {
86
+ error: 'noVisit'
87
+ };
88
+ }
89
+ };
90
+ // Closes the current browser.
91
+ const browserClose = async () => {
92
+ if (browser) {
93
+ const browserType = browser.browserType().name();
94
+ let contexts = browser.contexts();
95
+ for (const context of contexts) {
96
+ await context.close();
97
+ contexts = browser.contexts();
98
+ }
99
+ await browser.close();
100
+ browser = null;
101
+ console.log(`${browserType} browser closed`);
102
+ }
103
+ };
104
+ // Launches a browser, navigates to a URL, and returns the status.
105
+ const launch = async (report, typeName, url, debug, waits, isLowMotion = false) => {
106
+ // If the specified browser type exists:
107
+ const browserType = playwright[typeName];
108
+ if (browserType) {
109
+ // Close the current browser, if any.
110
+ await browserClose();
111
+ // Launch a browser of the specified type.
112
+ const browserOptions = {
113
+ logger: {
114
+ isEnabled: () => false,
115
+ log: (name, severity, message) => console.log(message.slice(0, 100))
116
+ }
117
+ };
118
+ if (debug) {
119
+ browserOptions.headless = false;
120
+ }
121
+ if (waits) {
122
+ browserOptions.slowMo = waits;
123
+ }
124
+ browser = await browserType.launch(browserOptions)
125
+ // If the launch failed:
126
+ .catch(async error => {
127
+ healthy = false;
128
+ console.log(`ERROR launching browser (${errorStart(error)})`);
129
+ // Return this.
130
+ return false;
131
+ });
132
+ // Open a context (i.e. browser tab), with reduced motion if specified.
133
+ const options = {reduceMotion: isLowMotion ? 'reduce' : 'no-preference'};
134
+ browserContext = await browser.newContext(options);
135
+ // When a page (i.e. browser tab) is added to the browser context (i.e. browser window):
136
+ browserContext.on('page', async page => {
137
+ // Make the page current.
138
+ currentPage = page;
139
+ // If it emits a message:
140
+ page.on('console', msg => {
141
+ const msgText = msg.text();
142
+ let indentedMsg = '';
143
+ // If debugging is on:
144
+ if (debug) {
145
+ // Log a summary of the message on the console.
146
+ const parts = [msgText.slice(0, 75)];
147
+ if (msgText.length > 75) {
148
+ parts.push(msgText.slice(75, 150));
149
+ if (msgText.length > 150) {
150
+ const tail = msgText.slice(150).slice(-150);
151
+ if (msgText.length > 300) {
152
+ parts.push('...');
153
+ }
154
+ parts.push(tail.slice(0, 75));
155
+ if (tail.length > 75) {
156
+ parts.push(tail.slice(75));
157
+ }
158
+ }
159
+ }
160
+ indentedMsg = parts.map(part => ` | ${part}`).join('\n');
161
+ console.log(`\n${indentedMsg}`);
162
+ }
163
+ // Add statistics on the message to the report.
164
+ const msgTextLC = msgText.toLowerCase();
165
+ const msgLength = msgText.length;
166
+ report.jobData.logCount++;
167
+ report.jobData.logSize += msgLength;
168
+ if (errorWords.some(word => msgTextLC.includes(word))) {
169
+ report.jobData.errorLogCount++;
170
+ report.jobData.errorLogSize += msgLength;
171
+ }
172
+ const msgLC = msgText.toLowerCase();
173
+ if (
174
+ msgText.includes('403') && (msgLC.includes('status')
175
+ || msgLC.includes('prohibited'))
176
+ ) {
177
+ report.jobData.prohibitedCount++;
178
+ }
179
+ });
180
+ });
181
+ // Open the first page of the context.
182
+ currentPage = await browserContext.newPage();
183
+ try {
184
+ // Wait until it is stable.
185
+ await currentPage.waitForLoadState('domcontentloaded', {timeout: 5000});
186
+ // Navigate to the specified URL.
187
+ const navResult = await goTo(report, currentPage, url, 15000, 'domcontentloaded');
188
+ // If the navigation failed:
189
+ if (navResult.error) {
190
+ // Return this.
191
+ return false;
192
+ }
193
+ // Otherwise, i.e. if it succeeded:
194
+ else if (! navResult.error) {
195
+ // Update the name of the current browser type and store it in the page.
196
+ currentPage.browserTypeName = typeName;
197
+ // Return the browser context and the page.
198
+ return {
199
+ browserContext,
200
+ currentPage
201
+ };
202
+ }
203
+ }
204
+ // If it fails to become stable by the deadline:
205
+ catch(error) {
206
+ // Return this.
207
+ console.log(`ERROR: Blank page load in new tab timed out (${error.message})`);
208
+ return false;
209
+ }
210
+ }
211
+ // Otherwise, i.e. if it does not exist:
212
+ else {
213
+ // Return this.
214
+ console.log(`ERROR: Browser of type ${typeName} could not be launched`);
215
+ return false;
216
+ }
217
+ };
218
+ exports.browserClose = browserClose;
219
+ exports.goTo = goTo;
220
+ exports.launch = launch;
package/procs/testaro.js CHANGED
@@ -9,7 +9,7 @@ const {getLocatorData} = require('../procs/getLocatorData');
9
9
 
10
10
  // ########## CONSTANTS
11
11
 
12
- let sampleSize = 100;
12
+ const sampleMax = 100;
13
13
 
14
14
  // ########## FUNCTIONS
15
15
 
@@ -19,7 +19,7 @@ exports.init = async (page, locAllSelector, options = {}) => {
19
19
  const locPop = page.locator(locAllSelector, options);
20
20
  const locPops = await locPop.all();
21
21
  const populationSize = locPops.length;
22
- sampleSize = Math.min(sampleSize, populationSize);
22
+ const sampleSize = Math.min(sampleMax, populationSize);
23
23
  const locIndexes = getSample(locPops, sampleSize);
24
24
  const allLocs = locIndexes.map(index => locPops[index]);
25
25
  const result = {
@@ -2,6 +2,7 @@
2
2
  visChange
3
3
  This procedure reports a change in the visible content of a page between two times, optionally
4
4
  hovering over a locator-defined element immediately after the first time.
5
+
5
6
  WARNING: This test uses the Playwright page.screenshot method, which produces incorrect results
6
7
  when the browser type is chromium and is not implemented for the firefox browser type. The only
7
8
  browser type usable with this test is webkit.