@jsenv/snapshot 2.10.3 → 2.11.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jsenv/snapshot",
3
- "version": "2.10.3",
3
+ "version": "2.11.1",
4
4
  "description": "Snapshot testing",
5
5
  "license": "MIT",
6
6
  "author": {
@@ -29,16 +29,13 @@
29
29
  "files": [
30
30
  "/src/"
31
31
  ],
32
- "scripts": {
33
- "test": "node --conditions=development ./scripts/test.mjs"
34
- },
35
32
  "dependencies": {
36
33
  "@jsenv/assert": "4.4.1",
37
34
  "@jsenv/ast": "6.2.17",
38
- "@jsenv/exception": "1.1.2",
35
+ "@jsenv/exception": "1.1.3",
39
36
  "@jsenv/humanize": "1.2.8",
40
- "@jsenv/filesystem": "4.10.2",
41
- "@jsenv/terminal-recorder": "1.4.7",
37
+ "@jsenv/filesystem": "4.10.3",
38
+ "@jsenv/terminal-recorder": "1.4.8",
42
39
  "@jsenv/urls": "2.5.2",
43
40
  "@jsenv/utils": "2.1.2",
44
41
  "ansi-regex": "6.0.1",
@@ -4,12 +4,17 @@ import { createReplaceFilesystemWellKnownValues } from "../filesystem_well_known
4
4
  import { filesystemSideEffects } from "./filesystem/filesystem_side_effects.js";
5
5
  import { logSideEffects } from "./log/log_side_effects.js";
6
6
 
7
+ const executionEffectsDefault = {
8
+ catch: true,
9
+ return: true,
10
+ };
11
+
7
12
  export const createCaptureSideEffects = ({
8
13
  sourceFileUrl,
9
14
  logEffects = true,
10
15
  filesystemEffects = true,
11
16
  filesystemActions,
12
- executionEffects = {},
17
+ executionEffects = executionEffectsDefault,
13
18
  rootDirectoryUrl,
14
19
  replaceFilesystemWellKnownValues = createReplaceFilesystemWellKnownValues({
15
20
  rootDirectoryUrl,
@@ -21,6 +26,7 @@ export const createCaptureSideEffects = ({
21
26
  return: false,
22
27
  };
23
28
  }
29
+ executionEffects = { ...executionEffectsDefault, ...executionEffects };
24
30
 
25
31
  const detectors = [];
26
32
  if (logEffects) {
@@ -49,6 +49,25 @@ export const spyFilesystemCalls = (
49
49
  const fileDescriptorPathMap = new Map();
50
50
  const fileRestoreMap = new Map();
51
51
  const dirRestoreMap = new Map();
52
+
53
+ const onWriteFileDone = (stateBefore, stateAfter) =>
54
+ onFileMutationDone(stateBefore, stateAfter);
55
+ const onCopyFileDone = (stateBefore, stateAfter) =>
56
+ onFileMutationDone(stateBefore, stateAfter);
57
+ const onMoveFileDone = (fromStateBefore, toStateBefore, toStateAfter) => {
58
+ if (!toStateAfter.found) {
59
+ // seems to be possible somehow
60
+ return;
61
+ }
62
+ // effect on source file
63
+ registerUndoAndNotify(fromStateBefore, () => {
64
+ onRemoveFile(fromStateBefore.url, fromStateBefore.buffer, "move");
65
+ });
66
+ // effect on target file
67
+ registerUndoAndNotify(toStateBefore, () => {
68
+ onWriteFile(toStateBefore.url, fromStateBefore.buffer, "created");
69
+ });
70
+ };
52
71
  const onFileMutationDone = (stateBefore, stateAfter) => {
53
72
  if (!stateAfter.found) {
54
73
  // seems to be possible somehow
@@ -58,45 +77,61 @@ export const spyFilesystemCalls = (
58
77
  // - writing file for the 1st time
59
78
  // - updating file content
60
79
  // the important part is the file content in the end of the function execution
61
- let reason;
62
- if (!stateBefore.found && stateAfter.found) {
63
- reason = "created";
64
- } else if (Buffer.compare(stateBefore.buffer, stateAfter.buffer)) {
65
- reason = "content_modified";
66
- } else if (stateBefore.mtimeMs !== stateAfter.mtimeMs) {
67
- reason = "mtime_modified";
68
- } else if (stateBefore.url !== stateAfter.url) {
69
- reason = "moved";
70
- } else {
71
- // file is exactly the same
72
- // function did not have any effect on the file
80
+ const reason = getMutationReason(stateBefore, stateAfter);
81
+ if (!reason) {
73
82
  return;
74
83
  }
75
- const beforeUrl = stateBefore.url;
76
- const afterUrl = stateAfter.url;
77
- const action = getAction(beforeUrl);
84
+ registerUndoAndNotify(stateBefore, () => {
85
+ onWriteFile(stateAfter.url, stateAfter.buffer, reason);
86
+ });
87
+ };
88
+ const getMutationReason = (stateBefore, stateAfter) => {
89
+ if (!stateBefore.found && stateAfter.found) {
90
+ return "created";
91
+ }
92
+ if (Buffer.compare(stateBefore.buffer, stateAfter.buffer)) {
93
+ return "content_modified";
94
+ }
95
+ if (stateBefore.mtimeMs !== stateAfter.mtimeMs) {
96
+ return "mtime_modified";
97
+ }
98
+ // file is exactly the same
99
+ // function did not have any effect on the file
100
+ return null;
101
+ };
102
+ const registerUndoAndNotify = (stateBefore, notify) => {
103
+ const url = stateBefore.url;
104
+ const action = getAction(url);
78
105
  const shouldCompare =
79
106
  action === "compare" ||
80
107
  action === "compare_presence_only" ||
81
108
  action === true;
82
- if (action === "undo" || shouldCompare) {
83
- if (undoFilesystemSideEffects && !fileRestoreMap.has(beforeUrl)) {
84
- if (stateBefore.found) {
85
- fileRestoreMap.set(beforeUrl, () => {
86
- writeFileSync(beforeUrl, stateBefore.buffer);
87
- });
88
- } else {
89
- fileRestoreMap.set(beforeUrl, () => {
90
- removeFileSync(beforeUrl, { allowUseless: true });
91
- });
92
- }
109
+ // "ignore", false, anything else
110
+ undo: {
111
+ if (!undoFilesystemSideEffects) {
112
+ break undo;
113
+ }
114
+ if (action !== "undo" && !shouldCompare) {
115
+ break undo;
116
+ }
117
+ if (fileRestoreMap.has(url)) {
118
+ break undo;
119
+ }
120
+ if (stateBefore.found) {
121
+ fileRestoreMap.set(url, () => {
122
+ writeFileSync(url, stateBefore.buffer);
123
+ });
124
+ } else {
125
+ fileRestoreMap.set(url, () => {
126
+ removeFileSync(url, { allowUseless: true });
127
+ });
93
128
  }
94
129
  }
95
130
  if (shouldCompare) {
96
- onWriteFile(afterUrl, stateAfter.buffer, reason);
131
+ notify();
97
132
  }
98
- // "ignore", false, anything else
99
133
  };
134
+
100
135
  const onWriteDirectoryDone = (directoryUrl) => {
101
136
  const action = getAction(directoryUrl);
102
137
  const shouldCompare =
@@ -217,7 +252,7 @@ export const spyFilesystemCalls = (
217
252
  fileDescriptorPathMap.delete(fileDescriptor);
218
253
  filesystemStateInfoMap.delete(filePath);
219
254
  const stateAfter = getFileStateWithinHook(filePath);
220
- onFileMutationDone(stateBefore, stateAfter);
255
+ onWriteFileDone(stateBefore, stateAfter);
221
256
  },
222
257
  };
223
258
  },
@@ -231,7 +266,7 @@ export const spyFilesystemCalls = (
231
266
  return {
232
267
  return: () => {
233
268
  const stateAfter = getFileStateWithinHook(filePath);
234
- onFileMutationDone(stateBefore, stateAfter);
269
+ onWriteFileDone(stateBefore, stateAfter);
235
270
  },
236
271
  };
237
272
  },
@@ -247,11 +282,11 @@ export const spyFilesystemCalls = (
247
282
  _internalFs,
248
283
  "copyFile",
249
284
  (fromPath, toPath) => {
250
- const stateBefore = getFileStateWithinHook(fromPath);
285
+ const toStateBefore = getFileStateWithinHook(toPath);
251
286
  return {
252
287
  return: () => {
253
- const stateAfter = getFileStateWithinHook(toPath);
254
- onFileMutationDone(stateBefore, stateAfter);
288
+ const toStateAfter = getFileStateWithinHook(toPath);
289
+ onCopyFileDone(toStateBefore, toStateAfter);
255
290
  },
256
291
  };
257
292
  },
@@ -261,11 +296,12 @@ export const spyFilesystemCalls = (
261
296
  _internalFs,
262
297
  "rename",
263
298
  (fromPath, toPath) => {
264
- const stateBefore = getFileStateWithinHook(fromPath);
299
+ const fromStateBefore = getFileStateWithinHook(fromPath);
300
+ const toStateBefore = getFileStateWithinHook(toPath);
265
301
  return {
266
302
  return: () => {
267
- const stateAfter = getFileStateWithinHook(toPath);
268
- onFileMutationDone(stateBefore, stateAfter);
303
+ const toStateAfter = getFileStateWithinHook(toPath);
304
+ onMoveFileDone(fromStateBefore, toStateBefore, toStateAfter);
269
305
  },
270
306
  };
271
307
  },
@@ -12,6 +12,11 @@ import { renderSideEffects, renderSmallLink } from "./render_side_effects.js";
12
12
  * @param {Object} snapshotTestsOptions
13
13
  * @param {string|url} snapshotTestsOptions.outFilePattern
14
14
  * @param {string|url} snapshotTestsOptions.rootDirectoryUrl
15
+ * @param {Object} [snapshotTestsOptions.executionEffects]
16
+ * @param {boolean} [snapshotTestsOptions.executionEffects.catch=true]
17
+ * Any error thrown by test function is detected and added to side effects
18
+ * @param {boolean} [snapshotTestsOptions.executionEffects.return=true]
19
+ * Test function return value is added to side effects
15
20
  * @param {Object} [snapshotTestsOptions.filesystemActions]
16
21
  * Control what to do when there is a file side effect
17
22
  * "compare", "compare_presence_only", "undo", "ignore"