@jsenv/snapshot 2.6.10 → 2.7.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 +1 -1
- package/src/replace_fluctuating_values.js +2 -2
- package/src/side_effects/filesystem/filesystem_side_effects.js +8 -8
- package/src/side_effects/filesystem/spy_filesystem_calls.js +4 -0
- package/src/side_effects/render_side_effects.js +48 -40
- package/src/side_effects/snapshot_side_effects.js +22 -6
- package/src/side_effects/snapshot_tests.js +26 -14
package/package.json
CHANGED
|
@@ -21,7 +21,7 @@ export const replaceFluctuatingValues = (
|
|
|
21
21
|
stringType,
|
|
22
22
|
rootDirectoryUrl,
|
|
23
23
|
fileUrl,
|
|
24
|
-
|
|
24
|
+
preserveAnsi,
|
|
25
25
|
// for unit test
|
|
26
26
|
replaceFilesystemWellKnownValues = createReplaceFilesystemWellKnownValues({
|
|
27
27
|
rootDirectoryUrl,
|
|
@@ -51,7 +51,7 @@ export const replaceFluctuatingValues = (
|
|
|
51
51
|
if (stringType === "filesystem") {
|
|
52
52
|
return replaceFilesystemWellKnownValues(value);
|
|
53
53
|
}
|
|
54
|
-
if (
|
|
54
|
+
if (!preserveAnsi) {
|
|
55
55
|
value = stripAnsi(value);
|
|
56
56
|
}
|
|
57
57
|
value = replaceFilesystemWellKnownValues(value, {
|
|
@@ -55,19 +55,19 @@ export const filesystemSideEffects = (
|
|
|
55
55
|
}
|
|
56
56
|
return url;
|
|
57
57
|
};
|
|
58
|
-
const getUrlInsideOutDirectory = (url,
|
|
58
|
+
const getUrlInsideOutDirectory = (url, generateOutFileUrl) => {
|
|
59
59
|
if (baseDirectory) {
|
|
60
60
|
if (
|
|
61
61
|
url.href === baseDirectory.href ||
|
|
62
62
|
urlIsInsideOf(url, baseDirectory)
|
|
63
63
|
) {
|
|
64
64
|
const outRelativeUrl = urlToRelativeUrl(url, baseDirectory);
|
|
65
|
-
return
|
|
65
|
+
return generateOutFileUrl(outRelativeUrl);
|
|
66
66
|
}
|
|
67
67
|
}
|
|
68
68
|
// otherwise we replace the url with well known
|
|
69
69
|
const toRelativeUrl = replaceFilesystemWellKnownValues(url);
|
|
70
|
-
return
|
|
70
|
+
return generateOutFileUrl(toRelativeUrl);
|
|
71
71
|
};
|
|
72
72
|
|
|
73
73
|
addSkippableHandler((sideEffect) => {
|
|
@@ -189,7 +189,7 @@ ${renderFileContent(
|
|
|
189
189
|
if (allFilesInsideOutDirectory) {
|
|
190
190
|
const commonDirectoryOutUrl = getUrlInsideOutDirectory(
|
|
191
191
|
commonDirectoryUrl,
|
|
192
|
-
options.
|
|
192
|
+
options.generateOutFileUrl,
|
|
193
193
|
);
|
|
194
194
|
const commonDirectoryOutRelativeUrl = urlToRelativeUrl(
|
|
195
195
|
commonDirectoryOutUrl,
|
|
@@ -240,15 +240,15 @@ ${renderFileContent(
|
|
|
240
240
|
outDirectoryReason,
|
|
241
241
|
},
|
|
242
242
|
render: {
|
|
243
|
-
md: ({ sideEffectFileUrl,
|
|
243
|
+
md: ({ sideEffectFileUrl, generateOutFileUrl }) => {
|
|
244
244
|
const urlRelativeToBase = getUrlRelativeToBase(url);
|
|
245
245
|
if (outDirectoryReason) {
|
|
246
|
-
|
|
246
|
+
let urlInsideOutDirectory = getUrlInsideOutDirectory(
|
|
247
247
|
url,
|
|
248
|
-
|
|
248
|
+
generateOutFileUrl,
|
|
249
249
|
);
|
|
250
250
|
if (writeFileSideEffect.counter) {
|
|
251
|
-
setUrlBasename(
|
|
251
|
+
urlInsideOutDirectory = setUrlBasename(
|
|
252
252
|
urlInsideOutDirectory,
|
|
253
253
|
(basename) =>
|
|
254
254
|
`${basename}_${writeFileSideEffect.counter}`,
|
|
@@ -37,6 +37,10 @@ export const spyFilesystemCalls = (
|
|
|
37
37
|
const fileDescriptorPathMap = new Map();
|
|
38
38
|
const fileRestoreMap = new Map();
|
|
39
39
|
const onWriteFileDone = (fileUrl, stateBefore, stateAfter) => {
|
|
40
|
+
if (!stateAfter.found) {
|
|
41
|
+
// not suppoed to happen but could apparently
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
40
44
|
// we use same type because we don't want to differentiate between
|
|
41
45
|
// - writing file for the 1st time
|
|
42
46
|
// - updating file content
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createException } from "@jsenv/exception";
|
|
2
2
|
import { writeFileSync } from "@jsenv/filesystem";
|
|
3
3
|
import { renderTerminalSvg } from "@jsenv/terminal-recorder";
|
|
4
|
-
import {
|
|
4
|
+
import { urlToExtension, urlToRelativeUrl } from "@jsenv/urls";
|
|
5
5
|
import ansiRegex from "ansi-regex";
|
|
6
6
|
import { replaceFluctuatingValues } from "../replace_fluctuating_values.js";
|
|
7
7
|
|
|
@@ -39,6 +39,7 @@ export const renderSideEffects = (
|
|
|
39
39
|
{
|
|
40
40
|
sideEffectFileUrl,
|
|
41
41
|
outDirectoryUrl,
|
|
42
|
+
generateOutFileUrl,
|
|
42
43
|
generatedBy = true,
|
|
43
44
|
titleLevel = 1,
|
|
44
45
|
getBigSizeEffect = createBigSizeEffect({
|
|
@@ -86,6 +87,7 @@ export const renderSideEffects = (
|
|
|
86
87
|
markdown += renderOneSideEffect(sideEffect, {
|
|
87
88
|
sideEffectFileUrl,
|
|
88
89
|
outDirectoryUrl,
|
|
90
|
+
generateOutFileUrl,
|
|
89
91
|
rootDirectoryUrl,
|
|
90
92
|
titleLevel,
|
|
91
93
|
getBigSizeEffect,
|
|
@@ -133,6 +135,7 @@ const renderOneSideEffect = (
|
|
|
133
135
|
{
|
|
134
136
|
sideEffectFileUrl,
|
|
135
137
|
outDirectoryUrl,
|
|
138
|
+
generateOutFileUrl,
|
|
136
139
|
rootDirectoryUrl,
|
|
137
140
|
titleLevel,
|
|
138
141
|
getBigSizeEffect,
|
|
@@ -151,6 +154,7 @@ const renderOneSideEffect = (
|
|
|
151
154
|
let { label, text } = md({
|
|
152
155
|
sideEffectFileUrl,
|
|
153
156
|
outDirectoryUrl,
|
|
157
|
+
generateOutFileUrl,
|
|
154
158
|
replace,
|
|
155
159
|
rootDirectoryUrl,
|
|
156
160
|
lastSideEffectNumber,
|
|
@@ -159,7 +163,7 @@ const renderOneSideEffect = (
|
|
|
159
163
|
text = renderText(text, {
|
|
160
164
|
sideEffect,
|
|
161
165
|
sideEffectFileUrl,
|
|
162
|
-
|
|
166
|
+
generateOutFileUrl,
|
|
163
167
|
replace,
|
|
164
168
|
rootDirectoryUrl,
|
|
165
169
|
errorStackHidden,
|
|
@@ -200,7 +204,7 @@ const renderText = (
|
|
|
200
204
|
{
|
|
201
205
|
sideEffect,
|
|
202
206
|
sideEffectFileUrl,
|
|
203
|
-
|
|
207
|
+
generateOutFileUrl,
|
|
204
208
|
replace,
|
|
205
209
|
rootDirectoryUrl,
|
|
206
210
|
errorStackHidden,
|
|
@@ -242,25 +246,25 @@ const renderText = (
|
|
|
242
246
|
typeof value.stack === "string")
|
|
243
247
|
) {
|
|
244
248
|
onRenderError();
|
|
249
|
+
// return renderMarkdownBlock(text.value.stack);
|
|
245
250
|
const exception = createException(text.value, { rootDirectoryUrl });
|
|
246
251
|
const exceptionText = errorStackHidden
|
|
247
252
|
? `${exception.name}: ${exception.message}`
|
|
248
253
|
: exception.stack || exception.message || exception;
|
|
249
|
-
|
|
254
|
+
return renderPotentialAnsi(exceptionText, {
|
|
255
|
+
stringType: "error",
|
|
250
256
|
sideEffect,
|
|
251
257
|
sideEffectFileUrl,
|
|
252
|
-
|
|
258
|
+
generateOutFileUrl,
|
|
253
259
|
replace,
|
|
254
260
|
});
|
|
255
|
-
if (potentialAnsi) {
|
|
256
|
-
return potentialAnsi;
|
|
257
|
-
}
|
|
258
|
-
return renderMarkdownBlock(
|
|
259
|
-
replace(exceptionText, { stringType: "error" }),
|
|
260
|
-
);
|
|
261
261
|
}
|
|
262
|
+
|
|
262
263
|
return renderMarkdownBlock(
|
|
263
|
-
replace(
|
|
264
|
+
replace(
|
|
265
|
+
typeof value === "string" ? value : JSON.stringify(value, null, " "),
|
|
266
|
+
{ stringType: "json" },
|
|
267
|
+
),
|
|
264
268
|
"js",
|
|
265
269
|
);
|
|
266
270
|
}
|
|
@@ -268,7 +272,7 @@ const renderText = (
|
|
|
268
272
|
return renderConsole(text.value, {
|
|
269
273
|
sideEffect,
|
|
270
274
|
sideEffectFileUrl,
|
|
271
|
-
|
|
275
|
+
generateOutFileUrl,
|
|
272
276
|
replace,
|
|
273
277
|
});
|
|
274
278
|
}
|
|
@@ -288,47 +292,51 @@ const renderText = (
|
|
|
288
292
|
|
|
289
293
|
export const renderConsole = (
|
|
290
294
|
string,
|
|
291
|
-
{ sideEffect, sideEffectFileUrl,
|
|
295
|
+
{ sideEffect, sideEffectFileUrl, generateOutFileUrl, replace },
|
|
292
296
|
) => {
|
|
293
|
-
|
|
297
|
+
return renderPotentialAnsi(string, {
|
|
298
|
+
stringType: "console",
|
|
294
299
|
sideEffect,
|
|
295
300
|
sideEffectFileUrl,
|
|
296
|
-
|
|
301
|
+
generateOutFileUrl,
|
|
297
302
|
replace,
|
|
298
303
|
});
|
|
299
|
-
if (potentialAnsi) {
|
|
300
|
-
return potentialAnsi;
|
|
301
|
-
}
|
|
302
|
-
return renderMarkdownBlock(
|
|
303
|
-
replace(string, { stringType: "console" }),
|
|
304
|
-
"console",
|
|
305
|
-
);
|
|
306
304
|
};
|
|
307
305
|
|
|
308
306
|
const renderPotentialAnsi = (
|
|
309
307
|
string,
|
|
310
|
-
{ sideEffect, sideEffectFileUrl,
|
|
308
|
+
{ stringType, sideEffect, sideEffectFileUrl, generateOutFileUrl, replace },
|
|
311
309
|
) => {
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
310
|
+
const rawTextBlock = renderMarkdownBlock(
|
|
311
|
+
replace(string, { stringType }),
|
|
312
|
+
"console",
|
|
313
|
+
);
|
|
314
|
+
// for assert we want ideally hummm
|
|
315
|
+
// colored in details block?
|
|
316
|
+
const includesAnsi = ansiRegex().test(string);
|
|
317
|
+
if (!includesAnsi) {
|
|
318
|
+
return rawTextBlock;
|
|
319
319
|
}
|
|
320
|
-
svgFilename
|
|
321
|
-
const svgFileUrl =
|
|
322
|
-
let svgFileContent = renderTerminalSvg(
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
320
|
+
const svgFilename = `${sideEffect.code}${sideEffect.counter ? `_${sideEffect.counter}` : ""}.svg`;
|
|
321
|
+
const svgFileUrl = generateOutFileUrl(svgFilename);
|
|
322
|
+
let svgFileContent = renderTerminalSvg(
|
|
323
|
+
replace(string, { stringType: "console", preserveAnsi: true }),
|
|
324
|
+
{
|
|
325
|
+
head: false,
|
|
326
|
+
paddingTop: 10,
|
|
327
|
+
paddingBottom: 10,
|
|
328
|
+
},
|
|
329
|
+
);
|
|
327
330
|
svgFileContent = replace(svgFileContent, { fileUrl: svgFileUrl });
|
|
328
331
|
writeFileSync(svgFileUrl, svgFileContent);
|
|
329
332
|
const svgFileRelativeUrl = urlToRelativeUrl(svgFileUrl, sideEffectFileUrl);
|
|
330
|
-
|
|
331
|
-
|
|
333
|
+
let md = ``;
|
|
334
|
+
md += "\n\n";
|
|
335
|
+
md += renderMarkdownDetails(`${rawTextBlock}`, {
|
|
336
|
+
summary: "see without style",
|
|
337
|
+
});
|
|
338
|
+
md += "\n";
|
|
339
|
+
return md;
|
|
332
340
|
};
|
|
333
341
|
|
|
334
342
|
export const renderFileContent = (text, { sideEffect, replace }) => {
|
|
@@ -11,16 +11,19 @@ export const snapshotSideEffects = (
|
|
|
11
11
|
fn,
|
|
12
12
|
{
|
|
13
13
|
sideEffectFileUrl,
|
|
14
|
-
sideEffectFilePattern = "./output
|
|
14
|
+
sideEffectFilePattern = "./output/[basename].md",
|
|
15
|
+
outDirectoryPattern = "./output/[basename]/",
|
|
16
|
+
outFilePattern = "./output/[basename]/[filename]",
|
|
17
|
+
generateOutFileUrl,
|
|
15
18
|
outDirectoryUrl,
|
|
16
19
|
errorStackHidden,
|
|
17
20
|
...captureOptions
|
|
18
21
|
} = {},
|
|
19
22
|
) => {
|
|
23
|
+
const basename = urlToBasename(sourceFileUrl, true);
|
|
20
24
|
if (sideEffectFileUrl === undefined) {
|
|
21
|
-
const basename = urlToBasename(sourceFileUrl, true);
|
|
22
25
|
const sideEffectFileRelativeUrl = sideEffectFilePattern.replaceAll(
|
|
23
|
-
"
|
|
26
|
+
"[basename]",
|
|
24
27
|
basename,
|
|
25
28
|
);
|
|
26
29
|
sideEffectFileUrl = new URL(sideEffectFileRelativeUrl, sourceFileUrl);
|
|
@@ -30,17 +33,30 @@ export const snapshotSideEffects = (
|
|
|
30
33
|
|
|
31
34
|
const captureSideEffects = createCaptureSideEffects(captureOptions);
|
|
32
35
|
if (outDirectoryUrl === undefined) {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
+
const outDirectoryRelativeUrl = outDirectoryPattern.replaceAll(
|
|
37
|
+
"[basename]",
|
|
38
|
+
basename,
|
|
36
39
|
);
|
|
40
|
+
outDirectoryUrl = new URL(outDirectoryRelativeUrl, sideEffectFileUrl);
|
|
37
41
|
}
|
|
42
|
+
if (generateOutFileUrl === undefined) {
|
|
43
|
+
generateOutFileUrl = (filename) => {
|
|
44
|
+
const outRelativeUrl = outFilePattern
|
|
45
|
+
.replaceAll("[basename]", basename)
|
|
46
|
+
.replaceAll("[filename]", filename);
|
|
47
|
+
const outFileUrl = new URL(outRelativeUrl, new URL("./", sourceFileUrl))
|
|
48
|
+
.href;
|
|
49
|
+
return outFileUrl;
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
|
|
38
53
|
const sideEffectFileSnapshot = takeFileSnapshot(sideEffectFileUrl);
|
|
39
54
|
const outDirectorySnapshot = takeDirectorySnapshot(outDirectoryUrl);
|
|
40
55
|
const onSideEffects = (sideEffects) => {
|
|
41
56
|
const sideEffectFileContent = renderSideEffects(sideEffects, {
|
|
42
57
|
sideEffectFileUrl,
|
|
43
58
|
outDirectoryUrl,
|
|
59
|
+
generateOutFileUrl,
|
|
44
60
|
errorStackHidden,
|
|
45
61
|
});
|
|
46
62
|
sideEffectFileSnapshot.update(sideEffectFileContent, {
|
|
@@ -9,7 +9,7 @@ import { renderSideEffects, renderSmallLink } from "./render_side_effects.js";
|
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
11
|
* Generate a markdown file describing all test side effects. When executed in CI throw if there is a diff.
|
|
12
|
-
* @param {URL}
|
|
12
|
+
* @param {URL} testFileUrl
|
|
13
13
|
* @param {Function} fnRegisteringTest
|
|
14
14
|
* @param {Object} snapshotTestsOptions
|
|
15
15
|
* @param {string|url} snapshotTestsOptions.sideEffectFileUrl
|
|
@@ -17,11 +17,14 @@ import { renderSideEffects, renderSmallLink } from "./render_side_effects.js";
|
|
|
17
17
|
* @return {Array.<Object>} sideEffects
|
|
18
18
|
*/
|
|
19
19
|
export const snapshotTests = async (
|
|
20
|
-
|
|
20
|
+
testFileUrl,
|
|
21
21
|
fnRegisteringTest,
|
|
22
22
|
{
|
|
23
|
+
testName = urlToBasename(testFileUrl, true),
|
|
23
24
|
sideEffectFileUrl,
|
|
24
|
-
sideEffectFilePattern = "
|
|
25
|
+
sideEffectFilePattern = "./output/[test_name].md",
|
|
26
|
+
outDirectoryPattern = "./output/[test_name]/",
|
|
27
|
+
outFilePattern = "./output/[test_scenario]/[filename]",
|
|
25
28
|
rootDirectoryUrl,
|
|
26
29
|
generatedBy = true,
|
|
27
30
|
linkToSource = true,
|
|
@@ -33,14 +36,13 @@ export const snapshotTests = async (
|
|
|
33
36
|
} = {},
|
|
34
37
|
) => {
|
|
35
38
|
if (sideEffectFileUrl === undefined) {
|
|
36
|
-
const basename = urlToBasename(sourceFileUrl, true);
|
|
37
39
|
const sideEffectFileRelativeUrl = sideEffectFilePattern.replaceAll(
|
|
38
|
-
"
|
|
39
|
-
|
|
40
|
+
"[test_name]",
|
|
41
|
+
testName,
|
|
40
42
|
);
|
|
41
|
-
sideEffectFileUrl = new URL(sideEffectFileRelativeUrl,
|
|
43
|
+
sideEffectFileUrl = new URL(sideEffectFileRelativeUrl, testFileUrl);
|
|
42
44
|
} else {
|
|
43
|
-
sideEffectFileUrl = new URL(sideEffectFileUrl,
|
|
45
|
+
sideEffectFileUrl = new URL(sideEffectFileUrl, testFileUrl);
|
|
44
46
|
}
|
|
45
47
|
|
|
46
48
|
const testMap = new Map();
|
|
@@ -70,8 +72,8 @@ export const snapshotTests = async (
|
|
|
70
72
|
{
|
|
71
73
|
prefix: "Generated by ",
|
|
72
74
|
suffix:
|
|
73
|
-
linkToSource &&
|
|
74
|
-
? generateExecutingLink(
|
|
75
|
+
linkToSource && testFileUrl
|
|
76
|
+
? generateExecutingLink(testFileUrl, sideEffectFileUrl)
|
|
75
77
|
: "",
|
|
76
78
|
},
|
|
77
79
|
);
|
|
@@ -87,19 +89,29 @@ export const snapshotTests = async (
|
|
|
87
89
|
callSite: linkToEachSource ? callSite : undefined,
|
|
88
90
|
baseDirectory: String(new URL("./", callSite.url)),
|
|
89
91
|
});
|
|
90
|
-
const
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
92
|
+
const testScenario = asValidFilename(scenario);
|
|
93
|
+
let outDirectoryRelativeUrl = outDirectoryPattern
|
|
94
|
+
.replaceAll("[test_name]", testName)
|
|
95
|
+
.replaceAll("[test_scenario]", testScenario);
|
|
96
|
+
const outDirectoryUrl = new URL(outDirectoryRelativeUrl, testFileUrl);
|
|
94
97
|
const outDirectorySnapshot = takeDirectorySnapshot(outDirectoryUrl, {
|
|
95
98
|
pattern: {
|
|
96
99
|
"**/*": true,
|
|
97
100
|
"**/*.svg": "presence_only",
|
|
98
101
|
},
|
|
99
102
|
});
|
|
103
|
+
const generateOutFileUrl = (filename) => {
|
|
104
|
+
const outFileRelativeUrl = outFilePattern
|
|
105
|
+
.replaceAll("[test_name]", testName)
|
|
106
|
+
.replaceAll("[test_scenario]", testScenario)
|
|
107
|
+
.replaceAll("[filename]", filename);
|
|
108
|
+
const outFileUrl = new URL(outFileRelativeUrl, testFileUrl).href;
|
|
109
|
+
return outFileUrl;
|
|
110
|
+
};
|
|
100
111
|
const sideEffectsMarkdown = renderSideEffects(sideEffects, {
|
|
101
112
|
sideEffectFileUrl,
|
|
102
113
|
outDirectoryUrl,
|
|
114
|
+
generateOutFileUrl,
|
|
103
115
|
generatedBy: false,
|
|
104
116
|
titleLevel: 3,
|
|
105
117
|
errorStackHidden,
|