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