testaro 73.0.0 → 74.0.1
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 +10 -1
- package/call.js +0 -4
- package/package.json +1 -1
- package/procs/doActs.js +11 -0
- package/procs/shoot.js +36 -4
- package/validation/jobs/todo/240101T1300-shoot-example.json +46 -0
- package/scratch/README.md +0 -12
package/actSpecs.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/*
|
|
2
2
|
© 2021–2024 CVS Health and/or one of its affiliates. All rights reserved.
|
|
3
|
-
©
|
|
3
|
+
© 2026 Jeff Witt.
|
|
4
|
+
© 2025–2026 Jonathan Robert Pool.
|
|
4
5
|
|
|
5
6
|
Licensed under the MIT License. See LICENSE file at the project root or
|
|
6
7
|
https://opensource.org/license/mit/ for details.
|
|
@@ -121,6 +122,14 @@ exports.actSpecs = {
|
|
|
121
122
|
what: [true, 'string', 'hasLength', 'substring of option text content']
|
|
122
123
|
}
|
|
123
124
|
],
|
|
125
|
+
shoot: [
|
|
126
|
+
'Save a full-page screenshot to <tmpdir>/testaro-shoot-<which>.png',
|
|
127
|
+
{
|
|
128
|
+
which: [true, 'string', 'hasLength', 'screenshot label, used in the filename'],
|
|
129
|
+
exclusion: [false, 'string', 'hasLength', 'CSS selector for an element to mask'],
|
|
130
|
+
what: [false, 'string', 'hasLength', 'comment']
|
|
131
|
+
}
|
|
132
|
+
],
|
|
124
133
|
state: [
|
|
125
134
|
'Wait until the page reaches a load state',
|
|
126
135
|
{
|
package/call.js
CHANGED
|
@@ -22,13 +22,9 @@
|
|
|
22
22
|
|
|
23
23
|
// IMPORTS
|
|
24
24
|
|
|
25
|
-
// Module to keep secrets.
|
|
26
25
|
require('dotenv').config();
|
|
27
|
-
// Module to process files.
|
|
28
26
|
const fs = require('fs/promises');
|
|
29
|
-
// Function to process a testing request.
|
|
30
27
|
const {doJob} = require('./run');
|
|
31
|
-
// Function to watch for jobs.
|
|
32
28
|
const {dirWatch} = require('./dirWatch');
|
|
33
29
|
const {netWatch} = require('./netWatch');
|
|
34
30
|
|
package/package.json
CHANGED
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
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
/*
|
|
2
|
+
© 2026 Jeff Witt.
|
|
2
3
|
© 2025–2026 Jonathan Robert Pool.
|
|
3
4
|
Licensed under the MIT License. See LICENSE file for details.
|
|
4
5
|
*/
|
|
@@ -6,6 +7,17 @@
|
|
|
6
7
|
/*
|
|
7
8
|
shoot
|
|
8
9
|
Makes and saves as a PNG buffer file a full-page screenshot and returns the file path.
|
|
10
|
+
|
|
11
|
+
Call shape:
|
|
12
|
+
shoot(page, label, options?)
|
|
13
|
+
label: string|number used in the saved filename. Sanitized to
|
|
14
|
+
testaro-shoot-<safe>.png — characters outside [A-Za-z0-9._-]
|
|
15
|
+
collapse to '_', leading/trailing dots and underscores are
|
|
16
|
+
stripped, length is capped at 100, and an empty result becomes
|
|
17
|
+
'unnamed'.
|
|
18
|
+
options: optional object:
|
|
19
|
+
exclusion: a Playwright Locator to mask in the screenshot.
|
|
20
|
+
dir: output directory (defaults to the OS temp dir).
|
|
9
21
|
*/
|
|
10
22
|
|
|
11
23
|
// IMPORTS
|
|
@@ -18,6 +30,24 @@ const {PNG} = require('pngjs');
|
|
|
18
30
|
|
|
19
31
|
// FUNCTIONS
|
|
20
32
|
|
|
33
|
+
/*
|
|
34
|
+
Coerces a label into a filesystem-safe string. Runs of any character outside
|
|
35
|
+
[A-Za-z0-9._-] collapse to one underscore; leading and trailing dots and
|
|
36
|
+
underscores are stripped (no hidden files, no traversal); capped at 100
|
|
37
|
+
characters; falls back to 'unnamed' if nothing usable remains.
|
|
38
|
+
*/
|
|
39
|
+
const sanitizeLabel = (label) => {
|
|
40
|
+
const raw = String(label);
|
|
41
|
+
const cleaned = raw
|
|
42
|
+
.replace(/[^A-Za-z0-9._-]+/g, '_')
|
|
43
|
+
.replace(/^[._]+|[._]+$/g, '')
|
|
44
|
+
.slice(0, 100) || 'unnamed';
|
|
45
|
+
if (cleaned !== raw) {
|
|
46
|
+
console.log(`>> shoot: label sanitized from "${raw}" to "${cleaned}"`);
|
|
47
|
+
}
|
|
48
|
+
return cleaned;
|
|
49
|
+
};
|
|
50
|
+
|
|
21
51
|
// Creates and returns a screenshot.
|
|
22
52
|
const screenShot = async (page, exclusion = null) => {
|
|
23
53
|
const options = {
|
|
@@ -35,9 +65,11 @@ const screenShot = async (page, exclusion = null) => {
|
|
|
35
65
|
return '';
|
|
36
66
|
});
|
|
37
67
|
};
|
|
38
|
-
exports.shoot = async (page,
|
|
68
|
+
exports.shoot = async (page, label, tmpDir, options = {}) => {
|
|
69
|
+
const exclusion = options.exclusion || null;
|
|
70
|
+
const dir = options.dir || tmpDir;
|
|
39
71
|
// Make and get a screenshot as a buffer.
|
|
40
|
-
let shot = await screenShot(page);
|
|
72
|
+
let shot = await screenShot(page, exclusion);
|
|
41
73
|
// If it succeeded:
|
|
42
74
|
if (shot.length) {
|
|
43
75
|
// Get the screenshot as an object representation of a PNG image.
|
|
@@ -49,8 +81,8 @@ exports.shoot = async (page, index, tmpDir) => {
|
|
|
49
81
|
if (global.gc) {
|
|
50
82
|
global.gc();
|
|
51
83
|
}
|
|
52
|
-
const fileName = `testaro-shoot-${
|
|
53
|
-
const pngPath = path.join(
|
|
84
|
+
const fileName = `testaro-shoot-${sanitizeLabel(label)}.png`;
|
|
85
|
+
const pngPath = path.join(dir, fileName);
|
|
54
86
|
// Save the PNG buffer.
|
|
55
87
|
await fs.writeFile(pngPath, pngBuffer);
|
|
56
88
|
// 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
|