@jsenv/snapshot 1.1.0 → 1.2.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jsenv/snapshot",
3
- "version": "1.1.0",
3
+ "version": "1.2.0",
4
4
  "description": "Snapshot testing",
5
5
  "license": "MIT",
6
6
  "author": {
@@ -35,9 +35,9 @@
35
35
  "test": "node --conditions=development ./scripts/test.mjs"
36
36
  },
37
37
  "dependencies": {
38
- "@jsenv/filesystem": "4.5.1",
38
+ "@jsenv/filesystem": "4.6.0",
39
39
  "@jsenv/urls": "2.2.1",
40
40
  "@jsenv/utils": "2.1.0",
41
- "@jsenv/assert": "2.13.0"
41
+ "@jsenv/assert": "2.13.1"
42
42
  }
43
43
  }
@@ -0,0 +1,307 @@
1
+ import { readdirSync, statSync, readFileSync } from "node:fs";
2
+ import {
3
+ assertAndNormalizeDirectoryUrl,
4
+ assertAndNormalizeFileUrl,
5
+ comparePathnames,
6
+ ensureEmptyDirectorySync,
7
+ removeFileSync,
8
+ writeFileSync,
9
+ removeDirectorySync,
10
+ writeFileStructureSync,
11
+ } from "@jsenv/filesystem";
12
+ import { urlToFilename, urlToRelativeUrl } from "@jsenv/urls";
13
+ import { CONTENT_TYPE } from "@jsenv/utils/src/content_type/content_type.js";
14
+
15
+ import {
16
+ createAssertionError,
17
+ formatStringAssertionErrorMessage,
18
+ } from "@jsenv/assert";
19
+
20
+ export const takeFileSnapshot = (fileUrl) => {
21
+ fileUrl = assertAndNormalizeFileUrl(fileUrl);
22
+ const expectedFileSnapshot = createFileSnapshot(fileUrl);
23
+ removeFileSync(fileUrl, { allowUseless: true });
24
+
25
+ return {
26
+ compare: () => {
27
+ compareFileSnapshots(createFileSnapshot(fileUrl), expectedFileSnapshot);
28
+ },
29
+ writeContent: (content) => {
30
+ writeFileSync(fileUrl, content);
31
+ },
32
+ restore: () => {
33
+ if (expectedFileSnapshot.empty) {
34
+ removeFileSync(fileUrl, { allowUseless: true });
35
+ return;
36
+ }
37
+ writeFileSync(fileUrl, expectedFileSnapshot.content);
38
+ },
39
+ };
40
+ };
41
+ const createFileSnapshot = (fileUrl) => {
42
+ const fileSnapshot = {
43
+ type: "file",
44
+ url: fileUrl,
45
+ stat: null,
46
+ content: "",
47
+ };
48
+
49
+ try {
50
+ fileSnapshot.stat = statSync(new URL(fileUrl));
51
+ } catch (e) {
52
+ if (e.code === "ENOENT") {
53
+ return fileSnapshot;
54
+ }
55
+ throw e;
56
+ }
57
+ if (!fileSnapshot.stat.isFile()) {
58
+ throw new Error(`file expected at ${fileUrl}`);
59
+ }
60
+
61
+ const isTextual = CONTENT_TYPE.isTextual(
62
+ CONTENT_TYPE.fromUrlExtension(fileUrl),
63
+ );
64
+ if (isTextual) {
65
+ const contentAsString = readFileSync(new URL(fileUrl), "utf8");
66
+ if (process.platform === "win32") {
67
+ // ensure unix line breaks
68
+ fileSnapshot.content = contentAsString.replace(/\r\n/g, "\n");
69
+ } else {
70
+ fileSnapshot.content = contentAsString;
71
+ }
72
+ } else {
73
+ const contentAsBuffer = readFileSync(new URL(fileUrl));
74
+ if (contentAsBuffer.length === 0) {
75
+ fileSnapshot.content = "";
76
+ } else {
77
+ fileSnapshot.content = contentAsBuffer;
78
+ }
79
+ }
80
+ return fileSnapshot;
81
+ };
82
+ const compareFileSnapshots = (actualFileSnapshot, expectedFileSnapshot) => {
83
+ const fileUrl = actualFileSnapshot.url;
84
+ const filename = urlToFilename(fileUrl);
85
+ const failureMessage = `snapshot comparison failed for "${filename}"`;
86
+
87
+ if (!actualFileSnapshot.stat) {
88
+ throw createAssertionError(`${failureMessage}
89
+ --- reason ---
90
+ file not found
91
+ --- file ---
92
+ ${fileUrl}`);
93
+ }
94
+ if (!expectedFileSnapshot.stat) {
95
+ return;
96
+ }
97
+ const actualFileContent = actualFileSnapshot.content;
98
+ const expectedFileContent = expectedFileSnapshot.content;
99
+ if (Buffer.isBuffer(actualFileContent)) {
100
+ if (actualFileContent.equals(expectedFileContent)) {
101
+ return;
102
+ }
103
+ throw createAssertionError(`${failureMessage}
104
+ --- reason ---
105
+ content has changed
106
+ --- file ---
107
+ ${fileUrl}`);
108
+ }
109
+ if (actualFileContent === expectedFileContent) {
110
+ return;
111
+ }
112
+ const message = formatStringAssertionErrorMessage({
113
+ actual: actualFileContent,
114
+ expected: expectedFileContent,
115
+ name: `file content`,
116
+ });
117
+ throw createAssertionError(`${failureMessage}
118
+ --- reason ---
119
+ ${message}
120
+ --- file ---
121
+ ${fileUrl}`);
122
+ };
123
+
124
+ export const takeDirectorySnapshot = (directoryUrl) => {
125
+ directoryUrl = assertAndNormalizeDirectoryUrl(directoryUrl);
126
+ directoryUrl = new URL(directoryUrl);
127
+
128
+ const expectedDirectorySnapshot = createDirectorySnapshot(directoryUrl);
129
+ ensureEmptyDirectorySync(directoryUrl);
130
+ return {
131
+ compare: () => {
132
+ const dirname = `${urlToFilename(directoryUrl)}/`;
133
+ const failureMessage = `snapshot comparison failed for "${dirname}"`;
134
+ const actualDirectorySnapshot = createDirectorySnapshot(directoryUrl);
135
+ if (!expectedDirectorySnapshot.stat || expectedDirectorySnapshot.empty) {
136
+ // the snapshot taken for directory/file/whatever is empty:
137
+ // - first time code executes:
138
+ // it defines snapshot that will be used for comparison by future runs
139
+ // - snapshot have been cleaned:
140
+ // we want to re-generated all snapshots without failing tests
141
+ // (happens when we know beforehand snapshot will change and we just want
142
+ // to review them using git diff)
143
+ return;
144
+ }
145
+
146
+ const actualFileSnapshots = actualDirectorySnapshot.fileSnapshots;
147
+ const expectedFileSnapshots = expectedDirectorySnapshot.fileSnapshots;
148
+ const actualRelativeUrls = Object.keys(actualFileSnapshots);
149
+ const expectedRelativeUrls = Object.keys(expectedFileSnapshots);
150
+
151
+ // missing_files
152
+ {
153
+ const missingRelativeUrls = expectedRelativeUrls.filter(
154
+ (expectedRelativeUrl) =>
155
+ !actualRelativeUrls.includes(expectedRelativeUrl),
156
+ );
157
+ const missingFileCount = missingRelativeUrls.length;
158
+ if (missingFileCount > 0) {
159
+ const missingUrls = missingRelativeUrls.map(
160
+ (relativeUrl) => new URL(relativeUrl, directoryUrl).href,
161
+ );
162
+ if (missingFileCount === 1) {
163
+ throw createAssertionError(`${failureMessage}
164
+ --- reason ---
165
+ "${missingRelativeUrls[0]}" is missing
166
+ --- file missing ---
167
+ ${missingUrls[0]}`);
168
+ }
169
+ throw createAssertionError(`${failureMessage}
170
+ --- reason ---
171
+ ${missingFileCount} files are missing
172
+ --- files missing ---
173
+ ${missingUrls.join("\n")}`);
174
+ }
175
+ }
176
+
177
+ // unexpected files
178
+ {
179
+ const extraRelativeUrls = actualRelativeUrls.filter(
180
+ (actualRelativeUrl) =>
181
+ !expectedRelativeUrls.includes(actualRelativeUrl),
182
+ );
183
+ const extraFileCount = extraRelativeUrls.length;
184
+ if (extraFileCount > 0) {
185
+ const extraUrls = extraRelativeUrls.map(
186
+ (relativeUrl) => new URL(relativeUrl, directoryUrl).href,
187
+ );
188
+ if (extraFileCount === 1) {
189
+ throw createAssertionError(`${failureMessage}
190
+ --- reason ---
191
+ "${extraRelativeUrls[0]}" is unexpected
192
+ --- file unexpected ---
193
+ ${extraUrls[0]}`);
194
+ }
195
+ throw createAssertionError(`${failureMessage}
196
+ --- reason ---
197
+ ${extraFileCount} files are unexpected
198
+ --- files unexpected ---
199
+ ${extraUrls.join("\n")}`);
200
+ }
201
+ }
202
+
203
+ // file contents
204
+ {
205
+ for (const relativeUrl of actualRelativeUrls) {
206
+ const actualFileSnapshot = actualFileSnapshots[relativeUrl];
207
+ const expectedFileSnapshot = expectedFileSnapshots[relativeUrl];
208
+ compareFileSnapshots(actualFileSnapshot, expectedFileSnapshot);
209
+ }
210
+ }
211
+ },
212
+ addFile: (relativeUrl, content) => {
213
+ writeFileSync(new URL(relativeUrl, directoryUrl), content);
214
+ },
215
+ restore: () => {
216
+ if (expectedDirectorySnapshot.notFound) {
217
+ removeDirectorySync(directoryUrl, {
218
+ recursive: true,
219
+ allowUseless: true,
220
+ });
221
+ return;
222
+ }
223
+ if (expectedDirectorySnapshot.empty) {
224
+ ensureEmptyDirectorySync(directoryUrl);
225
+ return;
226
+ }
227
+
228
+ const fileStructure = {};
229
+ Object.keys(expectedDirectorySnapshot.fileSnapshots).forEach(
230
+ (relativeUrl) => {
231
+ const fileSnapshot =
232
+ expectedDirectorySnapshot.fileSnapshots[relativeUrl];
233
+ if (!fileSnapshot.empty) {
234
+ fileStructure[relativeUrl] = fileSnapshot.content;
235
+ }
236
+ },
237
+ );
238
+ writeFileStructureSync(
239
+ directoryUrl,
240
+ expectedDirectorySnapshot.fileStructure,
241
+ );
242
+ },
243
+ };
244
+ };
245
+ const createDirectorySnapshot = (directoryUrl) => {
246
+ const directorySnapshot = {
247
+ type: "directory",
248
+ url: directoryUrl.href,
249
+ stat: null,
250
+ empty: false,
251
+ fileSnapshots: {},
252
+ };
253
+
254
+ try {
255
+ directorySnapshot.stat = statSync(directoryUrl);
256
+ } catch (e) {
257
+ if (e.code === "ENOENT") {
258
+ return directorySnapshot;
259
+ }
260
+ if (e.code === "ENOTDIR") {
261
+ // trailing slash is forced on directoryUrl
262
+ // as a result Node.js throw ENOTDIR when doing "stat" operation
263
+ throw new Error(`directory expected at ${directoryUrl}`);
264
+ }
265
+ throw e;
266
+ }
267
+ if (!directorySnapshot.stat.isDirectory()) {
268
+ throw new Error(`directory expected at ${directoryUrl}`);
269
+ }
270
+
271
+ const entryNames = readdirSync(directoryUrl);
272
+ if (entryNames.length === 0) {
273
+ directorySnapshot.empty = true;
274
+ return directorySnapshot;
275
+ }
276
+
277
+ const fileSnapshotsNaturalOrder = {};
278
+ const visitDirectory = (url) => {
279
+ try {
280
+ const directoryContent = readdirSync(url);
281
+ for (const filename of directoryContent) {
282
+ const contentUrl = new URL(filename, url);
283
+ const stat = statSync(contentUrl);
284
+ if (stat.isDirectory()) {
285
+ visitDirectory(new URL(`${contentUrl}/`));
286
+ return;
287
+ }
288
+ const relativeUrl = urlToRelativeUrl(contentUrl, directoryUrl);
289
+ fileSnapshotsNaturalOrder[relativeUrl] = createFileSnapshot(contentUrl);
290
+ }
291
+ } catch (e) {
292
+ if (e && e.code === "ENOENT") {
293
+ return;
294
+ }
295
+ throw e;
296
+ }
297
+ };
298
+ visitDirectory(directoryUrl);
299
+
300
+ const relativeUrls = Object.keys(fileSnapshotsNaturalOrder);
301
+ relativeUrls.sort(comparePathnames);
302
+ relativeUrls.forEach((relativeUrl) => {
303
+ directorySnapshot.fileSnapshots[relativeUrl] =
304
+ fileSnapshotsNaturalOrder[relativeUrl];
305
+ });
306
+ return directorySnapshot;
307
+ };
package/src/main.js CHANGED
@@ -1,327 +1 @@
1
- import { readdirSync, statSync, readFileSync } from "node:fs";
2
- import {
3
- assertAndNormalizeDirectoryUrl,
4
- assertAndNormalizeFileUrl,
5
- comparePathnames,
6
- ensureEmptyDirectorySync,
7
- removeFileSync,
8
- writeFileSync,
9
- removeDirectorySync,
10
- writeFileStructureSync,
11
- } from "@jsenv/filesystem";
12
- import { urlToFilename, urlToRelativeUrl } from "@jsenv/urls";
13
- import { CONTENT_TYPE } from "@jsenv/utils/src/content_type/content_type.js";
14
-
15
- import {
16
- createAssertionError,
17
- formatStringAssertionErrorMessage,
18
- } from "@jsenv/assert";
19
-
20
- const snapshotSymbol = Symbol.for("snapshot");
21
-
22
- export const takeDirectorySnapshot = (directoryUrl) => {
23
- directoryUrl = assertAndNormalizeDirectoryUrl(directoryUrl);
24
- directoryUrl = new URL(directoryUrl);
25
-
26
- const expectedDirectorySnapshot = createDirectorySnapshot(directoryUrl);
27
- ensureEmptyDirectorySync(directoryUrl);
28
- return {
29
- addFile: (relativeUrl, content) => {
30
- writeFileSync(new URL(relativeUrl, directoryUrl), content);
31
- },
32
- compare: () => {
33
- const actualDirectorySnapshot = createDirectorySnapshot(directoryUrl);
34
- compareSnapshots(actualDirectorySnapshot, expectedDirectorySnapshot);
35
- },
36
- restore: () => {
37
- if (expectedDirectorySnapshot.notFound) {
38
- removeDirectorySync(directoryUrl, {
39
- recursive: true,
40
- allowUseless: true,
41
- });
42
- return;
43
- }
44
- if (expectedDirectorySnapshot.empty) {
45
- ensureEmptyDirectorySync(directoryUrl);
46
- return;
47
- }
48
-
49
- const fileStructure = {};
50
- Object.keys(expectedDirectorySnapshot.fileSnapshots).forEach(
51
- (relativeUrl) => {
52
- const fileSnapshot =
53
- expectedDirectorySnapshot.fileSnapshots[relativeUrl];
54
- if (!fileSnapshot.empty) {
55
- fileStructure[relativeUrl] = fileSnapshot.content;
56
- }
57
- },
58
- );
59
- writeFileStructureSync(
60
- directoryUrl,
61
- expectedDirectorySnapshot.fileStructure,
62
- );
63
- },
64
- };
65
- };
66
- const createDirectorySnapshot = (directoryUrl) => {
67
- const directorySnapshot = {
68
- [snapshotSymbol]: true,
69
- empty: false,
70
- type: "directory",
71
- url: directoryUrl.href,
72
- notFound: false,
73
- fileSnapshots: {},
74
- };
75
-
76
- let stat;
77
- try {
78
- stat = statSync(directoryUrl);
79
- if (!stat.isDirectory()) {
80
- throw new Error(`directory expected at ${directoryUrl}`);
81
- }
82
- const entryNames = readdirSync(directoryUrl);
83
- if (entryNames.length === 0) {
84
- directorySnapshot.empty = true;
85
- return directorySnapshot;
86
- }
87
- } catch (e) {
88
- if (e.code === "ENOENT") {
89
- directorySnapshot.empty = true;
90
- directorySnapshot.notFound = true;
91
- return directorySnapshot;
92
- }
93
- }
94
-
95
- const fileSnapshotsNaturalOrder = {};
96
- const visitDirectory = (url) => {
97
- try {
98
- const directoryContent = readdirSync(url);
99
- directoryContent.forEach((filename) => {
100
- const contentUrl = new URL(filename, url);
101
- const stat = statSync(contentUrl);
102
- if (stat.isDirectory()) {
103
- visitDirectory(new URL(`${contentUrl}/`));
104
- return;
105
- }
106
- const relativeUrl = urlToRelativeUrl(contentUrl, directoryUrl);
107
- fileSnapshotsNaturalOrder[relativeUrl] = createFileSnapshot(contentUrl);
108
- });
109
- } catch (e) {
110
- if (e && e.code === "ENOENT") {
111
- return;
112
- }
113
- throw e;
114
- }
115
- };
116
- visitDirectory(directoryUrl);
117
-
118
- const relativeUrls = Object.keys(fileSnapshotsNaturalOrder);
119
- relativeUrls.sort(comparePathnames);
120
- relativeUrls.forEach((relativeUrl) => {
121
- directorySnapshot.fileSnapshots[relativeUrl] =
122
- fileSnapshotsNaturalOrder[relativeUrl];
123
- });
124
- return directorySnapshot;
125
- };
126
-
127
- export const takeFileSnapshot = (fileUrl) => {
128
- fileUrl = assertAndNormalizeFileUrl(fileUrl);
129
- const expectedFileSnapshot = createFileSnapshot(fileUrl);
130
- removeFileSync(fileUrl);
131
- return {
132
- writeContent: (content) => {
133
- writeFileSync(fileUrl, content);
134
- },
135
- compare: () => {
136
- const actualFileSnapshot = createFileSnapshot(fileUrl);
137
- compareSnapshots(actualFileSnapshot, expectedFileSnapshot);
138
- },
139
- restore: () => {
140
- if (expectedFileSnapshot.empty) {
141
- removeFileSync(fileUrl, { allowUseless: true });
142
- return;
143
- }
144
- writeFileSync(fileUrl, expectedFileSnapshot.content);
145
- },
146
- };
147
- };
148
- const createFileSnapshot = (fileUrl) => {
149
- const fileSnapshot = {
150
- [snapshotSymbol]: true,
151
- empty: false,
152
- type: "file",
153
- url: fileUrl,
154
- content: "",
155
- };
156
-
157
- let stat;
158
- try {
159
- stat = statSync(new URL(fileUrl));
160
- } catch (e) {
161
- if (e.code === "ENOENT") {
162
- fileSnapshot.empty = true;
163
- return fileSnapshot;
164
- }
165
- }
166
- if (!stat.isFile()) {
167
- throw new Error(`file expected at ${fileUrl}`);
168
- }
169
-
170
- const isTextual = CONTENT_TYPE.isTextual(
171
- CONTENT_TYPE.fromUrlExtension(fileUrl),
172
- );
173
- if (isTextual) {
174
- const contentAsString = readFileSync(new URL(fileUrl), "utf8");
175
- if (process.platform === "win32") {
176
- // ensure unix line breaks
177
- fileSnapshot.content = contentAsString.replace(/\r\n/g, "\n");
178
- } else {
179
- fileSnapshot.content = contentAsString;
180
- }
181
- } else {
182
- const contentAsBuffer = readFileSync(new URL(fileUrl));
183
- if (contentAsBuffer.length === 0) {
184
- fileSnapshot.content = "";
185
- } else {
186
- fileSnapshot.content = contentAsBuffer;
187
- }
188
- }
189
- return fileSnapshot;
190
- };
191
-
192
- const compareSnapshots = (currentSnapshot, previousSnapshot) => {
193
- if (!currentSnapshot || !currentSnapshot[snapshotSymbol]) {
194
- throw new TypeError(
195
- `1st argument must be a snapshot, received ${currentSnapshot}`,
196
- );
197
- }
198
- if (!previousSnapshot || !previousSnapshot[snapshotSymbol]) {
199
- throw new TypeError(
200
- `2nd argument must be a snapshot, received ${previousSnapshot}`,
201
- );
202
- }
203
-
204
- const currentShapsnotType = currentSnapshot.type;
205
- const previousSnapshotType = previousSnapshot.type;
206
- if (currentShapsnotType !== previousSnapshotType) {
207
- throw new TypeError(
208
- `cannot compare snapshots of different types "${currentShapsnotType}" vs "${previousSnapshotType}"`,
209
- );
210
- }
211
- const comparer = snapshotComparers[currentShapsnotType];
212
- if (!comparer) {
213
- throw new TypeError(`Unknow snapshot type "${currentShapsnotType}"`);
214
- }
215
- if (previousSnapshot.empty) {
216
- // the snapshot taken for directory/file/whatever is empty:
217
- // - first time code executes:
218
- // it defines snapshot that will be used for comparison by future runs
219
- // - snapshot have been cleaned:
220
- // we want to re-generated all snapshots without failing tests
221
- // (happens when we know beforehand snapshot will change and we just want
222
- // to review them using git diff)
223
- return;
224
- }
225
- comparer(currentSnapshot, previousSnapshot);
226
- };
227
-
228
- const snapshotComparers = {
229
- directory: (currentDirectorySnapshot, previousDirectorySnapshot) => {
230
- const failureMessage = `comparison with previous directory snapshot failed`;
231
- const currentFileSnapshots = currentDirectorySnapshot.fileSnapshots;
232
- const previousFileSnapshots = previousDirectorySnapshot.fileSnapshots;
233
- const currentRelativeUrls = Object.keys(currentFileSnapshots);
234
- const previousRelativeUrls = Object.keys(previousFileSnapshots);
235
-
236
- // missing_files
237
- {
238
- const missingRelativeUrls = previousRelativeUrls.filter(
239
- (previousRelativeUrl) =>
240
- !currentRelativeUrls.includes(previousRelativeUrl),
241
- );
242
- const missingFileCount = missingRelativeUrls.length;
243
- if (missingFileCount > 0) {
244
- const missingUrls = missingRelativeUrls.map(
245
- (relativeUrl) =>
246
- new URL(relativeUrl, currentDirectorySnapshot.url).href,
247
- );
248
- if (missingFileCount === 1) {
249
- throw createAssertionError(`${failureMessage}
250
- --- reason ---
251
- "${missingRelativeUrls[0]}" is missing
252
- --- file missing ---
253
- ${missingUrls[0]}`);
254
- }
255
- throw createAssertionError(`${failureMessage}
256
- --- reason ---
257
- ${missingFileCount} files are missing
258
- --- files missing ---
259
- ${missingUrls.join("\n")}`);
260
- }
261
- }
262
-
263
- // unexpected files
264
- {
265
- const extraRelativeUrls = currentRelativeUrls.filter(
266
- (currentRelativeUrl) =>
267
- !previousRelativeUrls.includes(currentRelativeUrl),
268
- );
269
- const extraFileCount = extraRelativeUrls.length;
270
- if (extraFileCount > 0) {
271
- const extraUrls = extraRelativeUrls.map(
272
- (relativeUrl) =>
273
- new URL(relativeUrl, currentDirectorySnapshot.url).href,
274
- );
275
- if (extraFileCount === 1) {
276
- throw createAssertionError(`${failureMessage}
277
- --- reason ---
278
- "${extraRelativeUrls[0]}" is unexpected
279
- --- file unexpected ---
280
- ${extraUrls[0]}`);
281
- }
282
- throw createAssertionError(`${failureMessage}
283
- --- reason ---
284
- ${extraFileCount} files are unexpected
285
- --- files unexpected ---
286
- ${extraUrls.join("\n")}`);
287
- }
288
- }
289
-
290
- // file contents
291
- {
292
- for (const relativeUrl of currentRelativeUrls) {
293
- const currentFileSnapshot = currentFileSnapshots[relativeUrl];
294
- const previousFileSnapshot = previousFileSnapshots[relativeUrl];
295
- compareSnapshots(currentFileSnapshot, previousFileSnapshot);
296
- }
297
- }
298
- },
299
- file: (currentFileSnapshot, previousFileSnapshot) => {
300
- const failureMessage = `comparison with previous file snapshot failed`;
301
- const currentFileContent = currentFileSnapshot.content;
302
- const previousFileContent = previousFileSnapshot.content;
303
- if (Buffer.isBuffer(currentFileContent)) {
304
- if (currentFileContent.equals(previousFileContent)) {
305
- return;
306
- }
307
- throw createAssertionError(`${failureMessage}
308
- --- reason ---
309
- "${urlToFilename(currentFileSnapshot.url)}" content has changed
310
- --- file ---
311
- ${currentFileSnapshot.url}`);
312
- }
313
- if (currentFileContent === previousFileContent) {
314
- return;
315
- }
316
- const message = formatStringAssertionErrorMessage({
317
- actual: currentFileContent,
318
- expected: previousFileContent,
319
- name: `"${urlToFilename(currentFileSnapshot.url)}" content`,
320
- });
321
- throw createAssertionError(`${failureMessage}
322
- --- reason ---
323
- ${message}
324
- --- file ---
325
- ${currentFileSnapshot.url}`);
326
- },
327
- };
1
+ export { takeDirectorySnapshot, takeFileSnapshot } from "./file_snapshots.js";