testaro 73.0.0 → 74.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/actSpecs.js CHANGED
@@ -121,6 +121,14 @@ exports.actSpecs = {
121
121
  what: [true, 'string', 'hasLength', 'substring of option text content']
122
122
  }
123
123
  ],
124
+ shoot: [
125
+ 'Save a full-page screenshot to <tmpdir>/testaro-shoot-<which>.png',
126
+ {
127
+ which: [true, 'string', 'hasLength', 'screenshot label, used in the filename'],
128
+ exclusion: [false, 'string', 'hasLength', 'CSS selector for an element to mask'],
129
+ what: [false, 'string', 'hasLength', 'comment']
130
+ }
131
+ ],
124
132
  state: [
125
133
  'Wait until the page reaches a load state',
126
134
  {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "testaro",
3
- "version": "73.0.0",
3
+ "version": "74.0.0",
4
4
  "description": "Run 1300 web accessibility tests from 10 tools and get a standardized report",
5
5
  "main": "index.js",
6
6
  "scripts": {
package/procs/doActs.js CHANGED
@@ -20,6 +20,9 @@ const {getNonce, goTo, launch, wait} = require('./launch');
20
20
  const {tools} = require('./job');
21
21
  const {fork} = require('child_process');
22
22
  const {pruneCatalog} = require('./catalog');
23
+ // Function to take a full-page screenshot.
24
+ const {shoot} = require('./shoot');
25
+ // Module to handle file system operations.
23
26
  const {applyMultiplier} = require('./config');
24
27
  const fs = require('fs/promises');
25
28
  const path = require('path');
@@ -636,6 +639,14 @@ exports.doActs = async report => {
636
639
  act.result.success = false;
637
640
  });
638
641
  }
642
+ // Otherwise, if the act is a screenshot:
643
+ else if (type === 'shoot') {
644
+ const exclusion = act.exclusion ? page.locator(act.exclusion) : null;
645
+ const pngPath = await shoot(page, act.which, {exclusion});
646
+ act.result = pngPath
647
+ ? {success: true, path: pngPath}
648
+ : {success: false, prevented: true};
649
+ }
639
650
  // Otherwise, if the act is a move:
640
651
  else if (moves[type]) {
641
652
  const selector = typeof moves[type] === 'string' ? moves[type] : act.what;
package/procs/shoot.js CHANGED
@@ -6,6 +6,17 @@
6
6
  /*
7
7
  shoot
8
8
  Makes and saves as a PNG buffer file a full-page screenshot and returns the file path.
9
+
10
+ Call shape:
11
+ shoot(page, label, options?)
12
+ label: string|number used in the saved filename. Sanitized to
13
+ testaro-shoot-<safe>.png — characters outside [A-Za-z0-9._-]
14
+ collapse to '_', leading/trailing dots and underscores are
15
+ stripped, length is capped at 100, and an empty result becomes
16
+ 'unnamed'.
17
+ options: optional object:
18
+ exclusion: a Playwright Locator to mask in the screenshot.
19
+ dir: output directory (defaults to the OS temp dir).
9
20
  */
10
21
 
11
22
  // IMPORTS
@@ -18,6 +29,22 @@ const {PNG} = require('pngjs');
18
29
 
19
30
  // FUNCTIONS
20
31
 
32
+ // Coerces a label into a filesystem-safe string. Runs of any character outside
33
+ // [A-Za-z0-9._-] collapse to one underscore; leading and trailing dots and
34
+ // underscores are stripped (no hidden files, no traversal); capped at 100
35
+ // characters; falls back to 'unnamed' if nothing usable remains.
36
+ const sanitizeLabel = (label) => {
37
+ const raw = String(label);
38
+ const cleaned = raw
39
+ .replace(/[^A-Za-z0-9._-]+/g, '_')
40
+ .replace(/^[._]+|[._]+$/g, '')
41
+ .slice(0, 100) || 'unnamed';
42
+ if (cleaned !== raw) {
43
+ console.log(`>> shoot: label sanitized from "${raw}" to "${cleaned}"`);
44
+ }
45
+ return cleaned;
46
+ };
47
+
21
48
  // Creates and returns a screenshot.
22
49
  const screenShot = async (page, exclusion = null) => {
23
50
  const options = {
@@ -35,9 +62,11 @@ const screenShot = async (page, exclusion = null) => {
35
62
  return '';
36
63
  });
37
64
  };
38
- exports.shoot = async (page, index, tmpDir) => {
65
+ exports.shoot = async (page, label, tmpDir, options = {}) => {
66
+ const exclusion = options.exclusion || null;
67
+ const dir = options.dir || tmpDir;
39
68
  // Make and get a screenshot as a buffer.
40
- let shot = await screenShot(page);
69
+ let shot = await screenShot(page, exclusion);
41
70
  // If it succeeded:
42
71
  if (shot.length) {
43
72
  // Get the screenshot as an object representation of a PNG image.
@@ -49,8 +78,8 @@ exports.shoot = async (page, index, tmpDir) => {
49
78
  if (global.gc) {
50
79
  global.gc();
51
80
  }
52
- const fileName = `testaro-shoot-${index}.png`;
53
- const pngPath = path.join(tmpDir, fileName);
81
+ const fileName = `testaro-shoot-${sanitizeLabel(label)}.png`;
82
+ const pngPath = path.join(dir, fileName);
54
83
  // Save the PNG buffer.
55
84
  await fs.writeFile(pngPath, pngBuffer);
56
85
  // Return the result.
@@ -0,0 +1,46 @@
1
+ {
2
+ "id": "240101T1300-shoot-example",
3
+ "what": "Demonstrate the shoot action: full-page screenshots interleaved with scripted steps",
4
+ "strict": true,
5
+ "timeLimit": 30,
6
+ "acts": [
7
+ {
8
+ "type": "launch",
9
+ "which": "chromium",
10
+ "url": "https://example.edu/",
11
+ "what": "Chromium browser"
12
+ },
13
+ {
14
+ "type": "shoot",
15
+ "which": "before",
16
+ "what": "Snapshot the landing page before any interaction"
17
+ },
18
+ {
19
+ "type": "shoot",
20
+ "which": "before-masked",
21
+ "exclusion": "header",
22
+ "what": "Same view with the page header masked out"
23
+ },
24
+ {
25
+ "type": "test",
26
+ "which": "testaro",
27
+ "withItems": false,
28
+ "stopOnFail": true,
29
+ "rules": [
30
+ "y",
31
+ "bulk"
32
+ ]
33
+ },
34
+ {
35
+ "type": "shoot",
36
+ "which": "after-tests",
37
+ "what": "Snapshot the page after Testaro tests have run"
38
+ }
39
+ ],
40
+ "sources": {},
41
+ "standard": "only",
42
+ "observe": false,
43
+ "sendReportTo": "http://localhost:3007/api",
44
+ "timeStamp": "240101T1300",
45
+ "creationTimeStamp": "240101T1300"
46
+ }
package/scratch/README.md DELETED
@@ -1,12 +0,0 @@
1
- # scratch
2
-
3
- This directory is used for temporary files produced during execution of jobs.
4
-
5
- ## License
6
-
7
- © 2021–2025 CVS Health and/or one of its affiliates. All rights reserved.
8
- © 2025–2026 Jonathan Robert Pool.
9
-
10
- Licensed under the [MIT License](https://opensource.org/license/mit/). See [LICENSE](../../LICENSE) file at the project root for details.
11
-
12
- SPDX-License-Identifier: MIT