@jsenv/snapshot 2.14.0 → 2.14.2
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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jsenv/snapshot",
|
|
3
|
-
"version": "2.14.
|
|
3
|
+
"version": "2.14.2",
|
|
4
4
|
"description": "Snapshot testing",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": {
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
"@jsenv/exception": "1.1.7",
|
|
37
37
|
"@jsenv/humanize": "1.4.0",
|
|
38
38
|
"@jsenv/filesystem": "4.14.6",
|
|
39
|
-
"@jsenv/terminal-recorder": "1.5.
|
|
39
|
+
"@jsenv/terminal-recorder": "1.5.11",
|
|
40
40
|
"@jsenv/urls": "2.7.1",
|
|
41
41
|
"@jsenv/utils": "2.3.0",
|
|
42
42
|
"ansi-regex": "6.1.0",
|
package/readme.md
CHANGED
|
@@ -2,38 +2,37 @@
|
|
|
2
2
|
|
|
3
3
|
[](https://www.npmjs.com/package/@jsenv/snapshot)
|
|
4
4
|
|
|
5
|
-
A
|
|
5
|
+
A powerful snapshot testing tool for JavaScript applications.
|
|
6
6
|
|
|
7
|
-
##
|
|
7
|
+
## Introduction to Snapshot Testing
|
|
8
8
|
|
|
9
|
-
Snapshot testing
|
|
9
|
+
Snapshot testing is a technique that:
|
|
10
10
|
|
|
11
|
-
1.
|
|
12
|
-
2.
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
11
|
+
1. Captures the output of code execution into files (snapshots)
|
|
12
|
+
2. Validates future code changes by:
|
|
13
|
+
- Reading the existing snapshot
|
|
14
|
+
- Executing the code
|
|
15
|
+
- Generating a new snapshot
|
|
16
|
+
- Comparing the two snapshots and reporting differences
|
|
17
17
|
|
|
18
|
-
This
|
|
18
|
+
This approach ensures your code continues to behave as expected by verifying its outputs remain consistent over time.
|
|
19
19
|
|
|
20
|
-
## How
|
|
20
|
+
## How `@jsenv/snapshot` Works
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
When running tests:
|
|
23
23
|
|
|
24
|
-
|
|
24
|
+
- **First run**: If no snapshot exists, one will be generated without comparison
|
|
25
|
+
- **Subsequent runs**: Snapshots are compared with the following behavior:
|
|
26
|
+
- In CI environments (`process.env.CI` is set): An error is thrown if differences are detected
|
|
27
|
+
- Locally: No error is thrown, allowing you to review changes with tools like git diff
|
|
25
28
|
|
|
26
|
-
|
|
29
|
+
> **Note**: All functions accept a throwWhenDiff parameter to force errors even in local environments.
|
|
27
30
|
|
|
28
|
-
|
|
29
|
-
- Otherwise nothing special happens (it's your job to review eventual diff in the snapshots, using `git diff` for example)
|
|
31
|
+
## API Reference
|
|
30
32
|
|
|
31
|
-
|
|
33
|
+
### takeFileSnapshot(fileUrl)
|
|
32
34
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
The code below ensure `writeFileTxt` write `content` into "./file.txt".
|
|
36
|
-
Changing that behaviour would fail snapshot comparison.
|
|
35
|
+
Captures and compares the state of a specific file.
|
|
37
36
|
|
|
38
37
|
```js
|
|
39
38
|
import { writeFileSync } from "node:fs";
|
|
@@ -51,10 +50,9 @@ writeFileTxt("Hello world");
|
|
|
51
50
|
fileSnapshot.compare();
|
|
52
51
|
```
|
|
53
52
|
|
|
54
|
-
|
|
53
|
+
### takeDirectorySnapshot(directoryUrl)
|
|
55
54
|
|
|
56
|
-
|
|
57
|
-
Changing that behaviour would fail snapshot comparison.
|
|
55
|
+
Captures and compares the state of an entire directory.
|
|
58
56
|
|
|
59
57
|
```js
|
|
60
58
|
import { writeFileSync } from "node:fs";
|
|
@@ -73,9 +71,9 @@ writeFileTxt(directoryUrl);
|
|
|
73
71
|
directorySnapshot.compare();
|
|
74
72
|
```
|
|
75
73
|
|
|
76
|
-
|
|
74
|
+
### snapshotTests(testFileUrl, fnRegistertingTests, options)
|
|
77
75
|
|
|
78
|
-
|
|
76
|
+
The most powerful feature of this library - creates readable markdown snapshots of test executions.
|
|
79
77
|
|
|
80
78
|
```js
|
|
81
79
|
import { snapshotTests } from "@jsenv/snapshot";
|
|
@@ -104,46 +102,38 @@ await snapshotTests(import.meta.url, ({ test }) => {
|
|
|
104
102
|
});
|
|
105
103
|
```
|
|
106
104
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
See the markdown at [./docs/\_circle_area.test.js/circle_area.test.js.md](./docs/_circle_area.test.js/circle_area.test.js.md)
|
|
105
|
+
This generates a markdown file documenting how your code behaves in different scenarios.
|
|
106
|
+
See an example at [./docs/\_circle_area.test.js/circle_area.test.js.md](./docs/_circle_area.test.js/circle_area.test.js.md)
|
|
111
107
|
|
|
112
|
-
Why
|
|
108
|
+
## Why Use snapshotTests?
|
|
113
109
|
|
|
114
|
-
-
|
|
115
|
-
-
|
|
116
|
-
-
|
|
117
|
-
-
|
|
110
|
+
- **Assertion-free testing**: Simply call your functions and let the snapshots document their behavior
|
|
111
|
+
- **Self-documenting tests**: Markdown files serve as both test validation and documentation
|
|
112
|
+
- **Visual change reviews**: Code changes are reflected in snapshots, making reviews easy
|
|
113
|
+
- **Side effect tracking**: Automatically captures and documents:
|
|
118
114
|
|
|
119
|
-
|
|
115
|
+
- Console logs [example](./docs/_log.test.js/log.test.js.md)
|
|
116
|
+
- Filesystem operations [example](./docs/_filesystem.test.js/filesystem.test.js.md)
|
|
117
|
+
- And more
|
|
120
118
|
|
|
121
|
-
- Log side effects are catched, see [./docs/\_logs.test.js/log.test.js.md](./docs/_log.test.js/log.test.js.md)
|
|
122
|
-
- Filesystem side effects are catched and undone, see [./docs/\_filesystem.test.js/filesystem.test.js.md](./docs/_filesystem.test.js/filesystem.test.js.md)
|
|
123
119
|
- Fluctuating values are replaced with stable values, see [#Fluctuating values replacement](#fluctuating-values-replacement)
|
|
124
120
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
- Tests how `assert` throw in many different ways: [@jsenv/assert/tests/array.test.js.md](../assert/tests/_array.test.js/array.test.js.md).
|
|
128
|
-
- Tests generating build files, starting a server and executing build files in a browser: [@jsenv/core/tests/script_type_module_basic.test.mjs](../../../tests/build/basics/script_type_module_basic/_script_type_module_basic.test.mjs/script_type_module_basic.test.mjs.md).
|
|
121
|
+
## Stable Snapshots Across Environments
|
|
129
122
|
|
|
130
|
-
|
|
123
|
+
To ensure snapshots remain consistent across different machines and CI environments, `@jsenv/snapshot` automatically normalizes fluctuating values:
|
|
131
124
|
|
|
132
|
-
|
|
125
|
+
- Time values like "2s" become "Xs"
|
|
126
|
+
- Filesystem paths are standardized
|
|
127
|
+
- Network ports in URLs are removed
|
|
128
|
+
- And much more...
|
|
133
129
|
|
|
134
|
-
|
|
130
|
+
This ensures your snapshot tests remain stable regardless of when or where they run.
|
|
135
131
|
|
|
136
|
-
|
|
137
|
-
- operating system
|
|
138
|
-
- filesystem location
|
|
139
|
-
- available ressources,
|
|
140
|
-
- and so on...
|
|
132
|
+
## Advanced Examples
|
|
141
133
|
|
|
142
|
-
|
|
134
|
+
- Testing complex assertion behavior: [@jsenv/assert/tests/array.test.js.md](../assert/tests/_array.test.js/array.test.js.md)
|
|
135
|
+
- Testing server-side builds with browser execution: [@jsenv/core/tests/script_type_module_basic.test.mjs](../../../tests/build/basics/script_type_module_basic/_script_type_module_basic.test.mjs/script_type_module_basic.test.mjs.md)
|
|
143
136
|
|
|
144
|
-
|
|
145
|
-
- Filesystem urls dynamic parts are replaced
|
|
146
|
-
- Port in https urls is removed
|
|
147
|
-
- and so on...
|
|
137
|
+
## Contributing
|
|
148
138
|
|
|
149
|
-
If
|
|
139
|
+
If you encounter unstable snapshots due to fluctuating values not being properly normalized, please open an issue or submit a pull request.
|
package/src/main.js
CHANGED
|
@@ -5,6 +5,7 @@ export {
|
|
|
5
5
|
export { createReplaceFilesystemWellKnownValues } from "./filesystem_well_known_values.js";
|
|
6
6
|
export { getCallerLocation } from "./get_caller_location.js";
|
|
7
7
|
export { replaceFluctuatingValues } from "./replace_fluctuating_values.js";
|
|
8
|
+
export { captureLogsIntoFile } from "./side_effects/capture_logs_into_file.js";
|
|
8
9
|
export { renderLogsGif } from "./side_effects/render_logs_gif.js";
|
|
9
10
|
export { snapshotSideEffects } from "./side_effects/snapshot_side_effects.js";
|
|
10
11
|
export { snapshotTests } from "./side_effects/snapshot_tests.js";
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { createCaptureSideEffects } from "./create_capture_side_effects.js";
|
|
2
|
+
import { renderLogsSvg } from "./render_logs_svg.js";
|
|
3
|
+
|
|
4
|
+
export const captureLogsIntoFile = async (fn, { svgFileUrl }) => {
|
|
5
|
+
const capture = createCaptureSideEffects({
|
|
6
|
+
executionEffects: false,
|
|
7
|
+
filesystemEffects: false,
|
|
8
|
+
logEffects: {
|
|
9
|
+
group: false,
|
|
10
|
+
},
|
|
11
|
+
});
|
|
12
|
+
const sideEffects = await capture(fn);
|
|
13
|
+
renderLogsSvg(sideEffects, svgFileUrl);
|
|
14
|
+
};
|
|
@@ -71,7 +71,7 @@ export const logSideEffects = (logSideEffectsOptions) => {
|
|
|
71
71
|
const logGroupSideEffect = {
|
|
72
72
|
code: "log_group",
|
|
73
73
|
type: `log_group`,
|
|
74
|
-
value: {},
|
|
74
|
+
value: {}, // TODO: the concatenation of the logs
|
|
75
75
|
render: {
|
|
76
76
|
md: (options) => {
|
|
77
77
|
const renderLogGroup = () => {
|
|
@@ -2,7 +2,7 @@ import { writeFileSync } from "@jsenv/filesystem";
|
|
|
2
2
|
import { startTerminalRecording } from "@jsenv/terminal-recorder";
|
|
3
3
|
import { isLogSideEffect } from "./log/log_side_effects.js";
|
|
4
4
|
|
|
5
|
-
export const renderLogsGif = async (sideEffects,
|
|
5
|
+
export const renderLogsGif = async (sideEffects, gifFileUrl) => {
|
|
6
6
|
const terminalRecorder = await startTerminalRecording({
|
|
7
7
|
gif: true,
|
|
8
8
|
});
|
|
@@ -15,5 +15,5 @@ export const renderLogsGif = async (sideEffects, gitFileUrl) => {
|
|
|
15
15
|
}
|
|
16
16
|
const result = await terminalRecorder.stop();
|
|
17
17
|
const gif = await result.gif();
|
|
18
|
-
writeFileSync(new URL(
|
|
18
|
+
writeFileSync(new URL(gifFileUrl), gif);
|
|
19
19
|
};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { writeFileSync } from "@jsenv/filesystem";
|
|
2
|
+
import { startTerminalRecording } from "@jsenv/terminal-recorder";
|
|
3
|
+
import { isLogSideEffect } from "./log/log_side_effects.js";
|
|
4
|
+
|
|
5
|
+
export const renderLogsSvg = async (
|
|
6
|
+
sideEffects,
|
|
7
|
+
svgFileUrl,
|
|
8
|
+
svgOptions = {},
|
|
9
|
+
) => {
|
|
10
|
+
const terminalRecorder = await startTerminalRecording({
|
|
11
|
+
svg: {
|
|
12
|
+
title: "Terminal",
|
|
13
|
+
width: "auto",
|
|
14
|
+
...svgOptions,
|
|
15
|
+
},
|
|
16
|
+
});
|
|
17
|
+
for (const sideEffect of sideEffects) {
|
|
18
|
+
if (isLogSideEffect(sideEffect)) {
|
|
19
|
+
await terminalRecorder.write(`${sideEffect.value}\n`, {
|
|
20
|
+
delay: sideEffect.delay,
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
const result = await terminalRecorder.stop();
|
|
25
|
+
const svg = await result.svg();
|
|
26
|
+
writeFileSync(new URL(svgFileUrl), svg);
|
|
27
|
+
};
|