@jsenv/snapshot 2.10.2 → 2.10.3

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.2",
3
+ "version": "2.10.3",
4
4
  "description": "Snapshot testing",
5
5
  "license": "MIT",
6
6
  "author": {
@@ -34,7 +34,7 @@
34
34
  },
35
35
  "dependencies": {
36
36
  "@jsenv/assert": "4.4.1",
37
- "@jsenv/ast": "6.2.16",
37
+ "@jsenv/ast": "6.2.17",
38
38
  "@jsenv/exception": "1.1.2",
39
39
  "@jsenv/humanize": "1.2.8",
40
40
  "@jsenv/filesystem": "4.10.2",
@@ -15,6 +15,13 @@ export const createCaptureSideEffects = ({
15
15
  rootDirectoryUrl,
16
16
  }),
17
17
  }) => {
18
+ if (executionEffects === false) {
19
+ executionEffects = {
20
+ catch: false,
21
+ return: false,
22
+ };
23
+ }
24
+
18
25
  const detectors = [];
19
26
  if (logEffects) {
20
27
  detectors.push(logSideEffects(logEffects === true ? {} : logEffects));
@@ -283,6 +290,33 @@ export const createCaptureSideEffects = ({
283
290
  finallyCallbackSet.clear();
284
291
  };
285
292
 
293
+ const onThrowOrReject = (value, isThrow) => {
294
+ if (executionEffects.catch === false) {
295
+ throw value;
296
+ }
297
+ if (typeof executionEffects.catch === "function") {
298
+ executionEffects.catch(value);
299
+ }
300
+ if (isThrow) {
301
+ onCatch(value);
302
+ } else {
303
+ onReject(value);
304
+ }
305
+ };
306
+ const onReturnOrResolve = (value, isReturn) => {
307
+ if (executionEffects.return === false) {
308
+ return;
309
+ }
310
+ if (typeof executionEffects.return === "function") {
311
+ executionEffects.return(value);
312
+ }
313
+ if (isReturn) {
314
+ onReturn(value);
315
+ } else {
316
+ onResolve(value);
317
+ }
318
+ };
319
+
286
320
  process.env.CAPTURING_SIDE_EFFECTS = "1";
287
321
  functionExecutingCount++;
288
322
  let returnedPromise = false;
@@ -292,34 +326,22 @@ export const createCaptureSideEffects = ({
292
326
  onReturn(RETURN_PROMISE);
293
327
  returnedPromise = valueReturned.then(
294
328
  (value) => {
295
- onResolve(value);
329
+ onReturnOrResolve(value);
296
330
  onFinally();
297
331
  return sideEffects;
298
332
  },
299
333
  (e) => {
300
- if (executionEffects.catch === false) {
301
- throw e;
302
- }
303
- if (typeof executionEffects.catch === "function") {
304
- executionEffects.catch(e);
305
- }
306
- onReject(e);
334
+ onThrowOrReject(e);
307
335
  onFinally();
308
336
  return sideEffects;
309
337
  },
310
338
  );
311
339
  return returnedPromise;
312
340
  }
313
- onReturn(valueReturned);
341
+ onReturnOrResolve(valueReturned, true);
314
342
  return sideEffects;
315
343
  } catch (e) {
316
- if (executionEffects.catch === false) {
317
- throw e;
318
- }
319
- if (typeof executionEffects.catch === "function") {
320
- executionEffects.catch(e);
321
- }
322
- onCatch(e);
344
+ onThrowOrReject(e, true);
323
345
  return sideEffects;
324
346
  } finally {
325
347
  if (!returnedPromise) {
@@ -49,7 +49,7 @@ export const spyFilesystemCalls = (
49
49
  const fileDescriptorPathMap = new Map();
50
50
  const fileRestoreMap = new Map();
51
51
  const dirRestoreMap = new Map();
52
- const onWriteFileDone = (fileUrl, stateBefore, stateAfter) => {
52
+ const onFileMutationDone = (stateBefore, stateAfter) => {
53
53
  if (!stateAfter.found) {
54
54
  // seems to be possible somehow
55
55
  return;
@@ -58,39 +58,42 @@ export const spyFilesystemCalls = (
58
58
  // - writing file for the 1st time
59
59
  // - updating file content
60
60
  // the important part is the file content in the end of the function execution
61
- const reason =
62
- !stateBefore.found && stateAfter.found
63
- ? "created"
64
- : Buffer.compare(stateBefore.buffer, stateAfter.buffer)
65
- ? "content_modified"
66
- : stateBefore.mtimeMs === stateAfter.mtimeMs
67
- ? ""
68
- : "mtime_modified";
69
- if (!reason) {
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 {
70
71
  // file is exactly the same
71
72
  // function did not have any effect on the file
72
73
  return;
73
74
  }
74
- const action = getAction(fileUrl);
75
+ const beforeUrl = stateBefore.url;
76
+ const afterUrl = stateAfter.url;
77
+ const action = getAction(beforeUrl);
75
78
  const shouldCompare =
76
79
  action === "compare" ||
77
80
  action === "compare_presence_only" ||
78
81
  action === true;
79
82
  if (action === "undo" || shouldCompare) {
80
- if (undoFilesystemSideEffects && !fileRestoreMap.has(fileUrl)) {
83
+ if (undoFilesystemSideEffects && !fileRestoreMap.has(beforeUrl)) {
81
84
  if (stateBefore.found) {
82
- fileRestoreMap.set(fileUrl, () => {
83
- writeFileSync(fileUrl, stateBefore.buffer);
85
+ fileRestoreMap.set(beforeUrl, () => {
86
+ writeFileSync(beforeUrl, stateBefore.buffer);
84
87
  });
85
88
  } else {
86
- fileRestoreMap.set(fileUrl, () => {
87
- removeFileSync(fileUrl, { allowUseless: true });
89
+ fileRestoreMap.set(beforeUrl, () => {
90
+ removeFileSync(beforeUrl, { allowUseless: true });
88
91
  });
89
92
  }
90
93
  }
91
94
  }
92
95
  if (shouldCompare) {
93
- onWriteFile(fileUrl, stateAfter.buffer, reason);
96
+ onWriteFile(afterUrl, stateAfter.buffer, reason);
94
97
  }
95
98
  // "ignore", false, anything else
96
99
  };
@@ -121,9 +124,9 @@ export const spyFilesystemCalls = (
121
124
  };
122
125
  const restoreCallbackSet = new Set();
123
126
 
124
- const getFileStateWithinHook = (fileUrl) => {
127
+ const getFileStateWithinHook = (filePath) => {
125
128
  return disableHooksWhileCalling(
126
- () => getFileState(fileUrl),
129
+ () => getFileState(filePath),
127
130
  [openHook, closeHook],
128
131
  );
129
132
  };
@@ -208,14 +211,13 @@ export const spyFilesystemCalls = (
208
211
  fileDescriptorPathMap.delete(fileDescriptor);
209
212
  return;
210
213
  }
211
- const fileUrl = pathToFileURL(filePath);
212
214
  if (buffer) {
213
- onReadFile(String(fileUrl));
215
+ onReadFile(filePath);
214
216
  }
215
217
  fileDescriptorPathMap.delete(fileDescriptor);
216
218
  filesystemStateInfoMap.delete(filePath);
217
- const stateAfter = getFileStateWithinHook(fileUrl);
218
- onWriteFileDone(String(fileUrl), stateBefore, stateAfter);
219
+ const stateAfter = getFileStateWithinHook(filePath);
220
+ onFileMutationDone(stateBefore, stateAfter);
219
221
  },
220
222
  };
221
223
  },
@@ -225,12 +227,11 @@ export const spyFilesystemCalls = (
225
227
  _internalFs,
226
228
  "writeFileUtf8",
227
229
  (filePath) => {
228
- const fileUrl = pathToFileURL(filePath);
229
- const stateBefore = getFileStateWithinHook(fileUrl);
230
+ const stateBefore = getFileStateWithinHook(filePath);
230
231
  return {
231
232
  return: () => {
232
- const stateAfter = getFileStateWithinHook(fileUrl);
233
- onWriteFileDone(String(fileUrl), stateBefore, stateAfter);
233
+ const stateAfter = getFileStateWithinHook(filePath);
234
+ onFileMutationDone(stateBefore, stateAfter);
234
235
  },
235
236
  };
236
237
  },
@@ -242,12 +243,44 @@ export const spyFilesystemCalls = (
242
243
  },
243
244
  };
244
245
  });
246
+ const copyFileHook = hookIntoMethod(
247
+ _internalFs,
248
+ "copyFile",
249
+ (fromPath, toPath) => {
250
+ const stateBefore = getFileStateWithinHook(fromPath);
251
+ return {
252
+ return: () => {
253
+ const stateAfter = getFileStateWithinHook(toPath);
254
+ onFileMutationDone(stateBefore, stateAfter);
255
+ },
256
+ };
257
+ },
258
+ { execute: METHOD_EXECUTION_NODE_CALLBACK },
259
+ );
260
+ const renameHook = hookIntoMethod(
261
+ _internalFs,
262
+ "rename",
263
+ (fromPath, toPath) => {
264
+ const stateBefore = getFileStateWithinHook(fromPath);
265
+ return {
266
+ return: () => {
267
+ const stateAfter = getFileStateWithinHook(toPath);
268
+ onFileMutationDone(stateBefore, stateAfter);
269
+ },
270
+ };
271
+ },
272
+ {
273
+ execute: METHOD_EXECUTION_NODE_CALLBACK,
274
+ },
275
+ );
245
276
  restoreCallbackSet.add(() => {
246
277
  mkdirHook.remove();
247
278
  openHook.remove();
248
279
  closeHook.remove();
249
280
  writeFileUtf8Hook.remove();
250
281
  unlinkHook.remove();
282
+ copyFileHook.remove();
283
+ renameHook.remove();
251
284
  });
252
285
  return {
253
286
  restore: () => {
@@ -275,11 +308,13 @@ export const spyFilesystemCalls = (
275
308
  };
276
309
  };
277
310
 
278
- const getFileState = (file) => {
311
+ const getFileState = (filePath) => {
312
+ const fileUrl = pathToFileURL(filePath);
279
313
  try {
280
- const fileBuffer = readFileSync(file);
281
- const { mtimeMs } = statSync(file);
314
+ const fileBuffer = readFileSync(fileUrl);
315
+ const { mtimeMs } = statSync(fileUrl);
282
316
  return {
317
+ url: String(fileUrl),
283
318
  found: true,
284
319
  mtimeMs,
285
320
  buffer: fileBuffer,
@@ -287,6 +322,7 @@ const getFileState = (file) => {
287
322
  } catch (e) {
288
323
  if (e.code === "ENOENT") {
289
324
  return {
325
+ url: String(fileUrl),
290
326
  found: false,
291
327
  };
292
328
  }