testaro 16.0.0 → 16.2.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/testaro/motion.js CHANGED
@@ -4,131 +4,46 @@
4
4
  brief, or else stoppable by the user. But stopping motion can be difficult or impossible, and,
5
5
  by the time a user manages to stop motion, the motion may have caused annoyance or harm. For
6
6
  superior accessibility, a page contains no motion until and unless the user authorizes it. The
7
- test compares screen shots of the part of the page within the visible viewport. You can specify
8
- how many milliseconds to wait before the first screen shot (delay), how many milliseconds to wait
9
- between screen shots (interval), and how many screen shots to make (count). The test compares the
10
- screen shots and reports 9 statistics:
11
- 0. bytes: an array of the sizes of the screen shots, in bytes
12
- 1. localRatios: an array of the ratios of bytes of the larger to the smaller of adjacent pairs
13
- of screen shots
14
- 2. meanLocalRatio: the mean of the ratios in the localRatios array
15
- 3. maxLocalRatio: the greatest of the ratios in the localRatios array
16
- 4. globalRatio: the ratio of bytes of the largest to the smallest screen shot
17
- 5. pixelChanges: an array of counts of differing pixels between adjacent pairs of screen shots
18
- 6. meanPixelChange: the mean of the counts in the pixelChanges array
19
- 7. maxPixelChange: the greatest of the counts in the pixelChanges array
20
- 8. changeFrequency: what fraction of the adjacent pairs of screen shots has pixel differences
7
+ test compares two screen shots of the viewport 2 seconds and 6 seconds after page load. It
8
+ reports a rule violation if any pixels change. The larger the change fraction, the greater the
9
+ ordinal severity.
21
10
 
22
- WARNING: This test uses the Playwright page.screenshot method, which produces incorrect results
23
- when the browser type is chromium and is not implemented for the firefox browser type. The only
24
- browser type usable with this test is webkit.
11
+ WARNING: This test uses the Playwright page.screenshot method, which is not implemented for the
12
+ firefox browser type.
25
13
  */
26
- const pixelmatch = require('pixelmatch');
27
- const {PNG} = require('pngjs');
28
- // Creates and returns a screenshot.
29
- const shoot = async page => {
30
- // Make a screenshot as a buffer.
31
- return await page.screenshot({
32
- fullPage: false,
33
- omitBackground: true,
34
- timeout: 3000
35
- })
36
- .catch(error => {
37
- console.log(`ERROR: Screenshot failed(${error.message})`);
38
- return '';
39
- });
40
- };
41
- // Recursively creates and returns screenshots.
42
- const shootAll = async (page, delay, interval, count, toDo, buffers) => {
43
- // Wait.
44
- await page.waitForTimeout(toDo === count ? delay : interval);
45
- // Make a screenshot.
46
- const buffer = await shoot(
47
- page, `${page.url().replace(/^.+\/\/|\/$/g, '').replace(/\//g, '+')}-${count - toDo}`
48
- );
49
- // Get its dimensions.
50
- if (buffer.length) {
51
- buffers.push(buffer);
52
- if (toDo > 1) {
53
- return shootAll(page, delay, interval, count, toDo - 1, buffers);
54
- }
55
- else {
56
- return buffers;
57
- }
58
- }
59
- else {
60
- return '';
61
- }
62
- };
63
- // Returns a number rounded to 2 decimal digits.
64
- const round = (num, precision) => Number.parseFloat(num.toPrecision(precision));
14
+
15
+ // IMPORTS
16
+
17
+ // Module to get pixel changes between two times.
18
+ const {visChange} = require('../procs/visChange');
19
+
20
+ // FUNCTIONS
21
+
65
22
  // Reports motion in a page.
66
- exports.reporter = async (page, withItems, delay = 2500, interval = 2500, count = 5) => {
67
- // Make screenshots and get their image buffers.
68
- const shots = await shootAll(page, delay, interval, count, count, []);
69
- // If the shooting succeeded:
70
- if (shots.length === count) {
71
- // Get the sizes of the shots in bytes of code.
72
- const bytes = shots.map(shot => shot.length);
73
- // Get their ratios between adjacent pairs of shots.
74
- const localRatios = bytes.slice(1).map((size, index) => round(
75
- (size > bytes[index] ? size / bytes[index] : bytes[index] / size), 4
76
- ));
77
- // Get the mean and maximum of those ratios.
78
- const meanLocalRatio = round(
79
- localRatios.reduce((sum, currentRatio) => sum + currentRatio) / localRatios.length, 4
80
- );
81
- const maxLocalRatio = Math.max(...localRatios);
82
- // Get the ratio between the largest and smallest shot.
83
- const globalRatio = round((Math.max(...bytes) / Math.min(...bytes)), 4);
84
- // Get the shots as PNG images.
85
- const pngs = shots.map(shot => PNG.sync.read(shot));
86
- // Get their dimensions.
87
- const {width, height} = pngs[0];
88
- // Get the counts of differing pixels between adjacent pairs of shots.
89
- const pixelChanges = pngs
90
- .slice(1)
91
- .map((png, index) => pixelmatch(pngs[index].data, png.data, null, width, height));
92
- // Get the mean and maximum of those counts.
93
- const meanPixelChange = Math.floor(
94
- pixelChanges.reduce((sum, currentChange) => sum + currentChange) / pixelChanges.length
95
- );
96
- const maxPixelChange = Math.max(...pixelChanges);
97
- const changeFrequency = round(
98
- pixelChanges.reduce((count, change) => count + (change ? 1 : 0), 0) / pixelChanges.length, 2
99
- );
100
- // Return the result.
101
- const rawCount = 2 * (meanLocalRatio - 1)
102
- + maxLocalRatio - 1
103
- + globalRatio - 1
104
- + meanPixelChange / 10000
105
- + maxPixelChange / 25000
106
- + 3 * changeFrequency;
107
- const count = rawCount ? Math.round(rawCount) : 0;
108
- return {
109
- data: {
110
- bytes,
111
- localRatios,
112
- meanLocalRatio,
113
- maxLocalRatio,
114
- globalRatio,
115
- pixelChanges,
116
- meanPixelChange,
117
- maxPixelChange,
118
- changeFrequency
119
- },
120
- totals: [
121
- 0,
122
- 0,
123
- count,
124
- 0
125
- ],
126
- standardInstances: count ? [{
23
+ exports.reporter = async page => {
24
+ // Initialize the totals and standard instances.
25
+ const totals = [0, 0, 0, 0];
26
+ const standardInstances = [];
27
+ // Make screenshots and get the result.
28
+ const data = await visChange(page, {
29
+ delayBefore: 2000,
30
+ delayBetween: 3000
31
+ });
32
+ // If the screenshots succeeded:
33
+ if (data.success) {
34
+ // If any pixels were changed:
35
+ if (data.pixelChanges) {
36
+ // Get the ordinal severity from the fractional pixel change.
37
+ const ordinalSeverity = Math.floor(Math.min(3, 0.4 * Math.sqrt(data.changePercent)));
38
+ // Add to the totals.
39
+ totals[ordinalSeverity] = 1;
40
+ // Get a summary standard instance.
41
+ standardInstances.push({
127
42
  ruleID: 'motion',
128
43
  what: 'Content moves or changes without user request',
129
- count,
130
- ordinalSeverity: 2,
131
- tagName: '',
44
+ count: 1,
45
+ ordinalSeverity,
46
+ tagName: 'HTML',
132
47
  id: '',
133
48
  location: {
134
49
  doc: '',
@@ -136,17 +51,13 @@ exports.reporter = async (page, withItems, delay = 2500, interval = 2500, count
136
51
  spec: ''
137
52
  },
138
53
  excerpt: ''
139
- }] : []
140
- };
141
- }
142
- // Otherwise, i.e. if the shooting failed:
143
- else {
144
- // Return failure.
145
- return {
146
- data: {
147
- prevented: true,
148
- error: 'ERROR: screenshots failed'
149
- }
150
- };
54
+ });
55
+ }
151
56
  }
57
+ // Return the result.
58
+ return {
59
+ data,
60
+ totals,
61
+ standardInstances
62
+ };
152
63
  };
@@ -0,0 +1,320 @@
1
+ {
2
+ "id": "hover",
3
+ "what": "validation of hover test",
4
+ "strict": true,
5
+ "timeLimit": 40,
6
+ "acts": [
7
+ {
8
+ "type": "launch",
9
+ "which": "webkit",
10
+ "what": "only compatible browser"
11
+ },
12
+ {
13
+ "type": "url",
14
+ "which": "__targets__/hover/good.html",
15
+ "what": "page with standard hover behavior"
16
+ },
17
+ {
18
+ "type": "test",
19
+ "which": "testaro",
20
+ "withItems": true,
21
+ "expect": [
22
+ [
23
+ "standardResult.totals.0",
24
+ "=",
25
+ 0
26
+ ],
27
+ [
28
+ "standardResult.totals.2",
29
+ "=",
30
+ 0
31
+ ],
32
+ [
33
+ "standardResult.instances.length",
34
+ "=",
35
+ 0
36
+ ]
37
+ ],
38
+ "rules": [
39
+ "y",
40
+ "hover"
41
+ ],
42
+ "args": {
43
+ "hover": [5]
44
+ }
45
+ },
46
+ {
47
+ "type": "url",
48
+ "which": "__targets__/hover/bad.html",
49
+ "what": "page with deviant hover behavior"
50
+ },
51
+ {
52
+ "type": "test",
53
+ "which": "testaro",
54
+ "withItems": true,
55
+ "expect": [
56
+ [
57
+ "standardResult.totals.3",
58
+ ">",
59
+ 0
60
+ ],
61
+ [
62
+ "standardResult.instances.0.ruleID",
63
+ "=",
64
+ "hover"
65
+ ],
66
+ [
67
+ "standardResult.instances.0.what",
68
+ "i",
69
+ "over the element"
70
+ ],
71
+ [
72
+ "standardResult.instances.0.tagName",
73
+ "=",
74
+ "A"
75
+ ],
76
+ [
77
+ "standardResult.instances.0.location.doc",
78
+ "=",
79
+ "dom"
80
+ ],
81
+ [
82
+ "standardResult.instances.0.location.type",
83
+ "=",
84
+ "box"
85
+ ],
86
+ [
87
+ "standardResult.instances.0.location.spec.height",
88
+ "<",
89
+ "20"
90
+ ],
91
+ [
92
+ "standardResult.instances.0.excerpt",
93
+ "i",
94
+ "Trigger 1"
95
+ ],
96
+ [
97
+ "standardResult.instances.2.what",
98
+ "i",
99
+ "is not hoverable"
100
+ ],
101
+ [
102
+ "standardResult.instances.2.ordinalSeverity",
103
+ "=",
104
+ 3
105
+ ],
106
+ [
107
+ "standardResult.instances.2.tagName",
108
+ "=",
109
+ "BUTTON"
110
+ ],
111
+ [
112
+ "standardResult.instances.2.id",
113
+ "=",
114
+ "smallButton"
115
+ ],
116
+ [
117
+ "standardResult.instances.0.location.doc",
118
+ "=",
119
+ "dom"
120
+ ],
121
+ [
122
+ "standardResult.instances.0.location.type",
123
+ "=",
124
+ "selector"
125
+ ],
126
+ [
127
+ "standardResult.instances.0.location.spec",
128
+ "=",
129
+ "#smallButton"
130
+ ],
131
+ [
132
+ "standardResult.instances.2.excerpt",
133
+ "i",
134
+ "Trigger 3"
135
+ ]
136
+ ],
137
+ "rules": [
138
+ "y",
139
+ "hover"
140
+ ],
141
+ "args": {
142
+ "hover": [6]
143
+ }
144
+ },
145
+ {
146
+ "type": "test",
147
+ "which": "testaro",
148
+ "withItems": false,
149
+ "expect": [
150
+ [
151
+ "standardResult.totals.3",
152
+ ">",
153
+ 0
154
+ ],
155
+ [
156
+ "standardResult.instances.length",
157
+ ">",
158
+ 0
159
+ ],
160
+ [
161
+ "standardResult.instances.0.ruleID",
162
+ "=",
163
+ "hover"
164
+ ],
165
+ [
166
+ "standardResult.instances.0.what",
167
+ "i",
168
+ "over elements"
169
+ ],
170
+ [
171
+ "standardResult.instances.0.ordinalSeverity",
172
+ ">",
173
+ -1
174
+ ],
175
+ [
176
+ "standardResult.instances.0.count",
177
+ ">",
178
+ 0
179
+ ]
180
+ ],
181
+ "rules": [
182
+ "y",
183
+ "hover"
184
+ ],
185
+ "args": {
186
+ "hover": [6]
187
+ }
188
+ },
189
+ {
190
+ "type": "test",
191
+ "which": "testaro",
192
+ "withItems": false,
193
+ "expect": [
194
+ [
195
+ "standardResult.totals.3",
196
+ "<",
197
+ 7
198
+ ],
199
+ [
200
+ "standardResult.totals.2",
201
+ "<",
202
+ 4
203
+ ],
204
+ [
205
+ "standardResult.totals.1",
206
+ "<",
207
+ 13
208
+ ],
209
+ [
210
+ "standardResult.totals.0",
211
+ "<",
212
+ 4
213
+ ]
214
+ ],
215
+ "rules": [
216
+ "y",
217
+ "hover"
218
+ ],
219
+ "args": {
220
+ "hover": [2]
221
+ }
222
+ },
223
+ {
224
+ "type": "url",
225
+ "which": "__targets__/hover/styleBad.html",
226
+ "what": "page with deviant trigger styles"
227
+ },
228
+ {
229
+ "type": "test",
230
+ "which": "testaro",
231
+ "withItems": true,
232
+ "expect": [
233
+ [
234
+ "standardResult.totals.1",
235
+ "=",
236
+ 0
237
+ ],
238
+ [
239
+ "standardResult.totals.2",
240
+ "=",
241
+ 2
242
+ ],
243
+ [
244
+ "standardResult.totals.3",
245
+ "=",
246
+ 1
247
+ ],
248
+ [
249
+ "standardResult.instances.0.ruleID",
250
+ "=",
251
+ "hover"
252
+ ],
253
+ [
254
+ "standardResult.instances.0.what",
255
+ "i",
256
+ "hides"
257
+ ],
258
+ [
259
+ "standardResult.instances.0.tagName",
260
+ "=",
261
+ "LI"
262
+ ],
263
+ [
264
+ "standardResult.instances.0.ordinalSeverity",
265
+ "=",
266
+ 3
267
+ ],
268
+ [
269
+ "standardResult.instances.0.excerpt",
270
+ "i",
271
+ "loses its cursor"
272
+ ],
273
+ [
274
+ "standardResult.instances.1.ruleID",
275
+ "=",
276
+ "hover"
277
+ ],
278
+ [
279
+ "standardResult.instances.1.what",
280
+ "i",
281
+ "cursor nonstandard"
282
+ ],
283
+ [
284
+ "standardResult.instances.1.tagName",
285
+ "=",
286
+ "A"
287
+ ],
288
+ [
289
+ "standardResult.instances.1.id",
290
+ "=",
291
+ "trigger1"
292
+ ],
293
+ [
294
+ "standardResult.instances.1.ordinalSeverity",
295
+ "=",
296
+ 2
297
+ ],
298
+ [
299
+ "standardResult.instances.1.excerpt",
300
+ "i",
301
+ "Trigger 1"
302
+ ]
303
+ ],
304
+ "rules": [
305
+ "y",
306
+ "hover"
307
+ ],
308
+ "args": {
309
+ "hover": [4]
310
+ }
311
+ }
312
+ ],
313
+ "sources": {
314
+ "script": "",
315
+ "host": {},
316
+ "requester": ""
317
+ },
318
+ "creationTime": "2013-05-28T12:00:00",
319
+ "timeStamp": "00000"
320
+ }