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 +8 -0
- package/package.json +1 -1
- package/procs/doActs.js +11 -0
- package/procs/shoot.js +33 -4
- package/validation/jobs/todo/240101T1300-shoot-example.json +46 -0
- package/scratch/README.md +0 -12
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
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,
|
|
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-${
|
|
53
|
-
const pngPath = path.join(
|
|
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
|