@cronn/lib-file-snapshots 0.1.0 → 0.3.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/dist/index.d.ts +112 -7
- package/dist/index.js +255 -129
- package/package.json +5 -5
package/dist/index.d.ts
CHANGED
|
@@ -1,15 +1,120 @@
|
|
|
1
|
-
interface
|
|
2
|
-
|
|
1
|
+
interface SnapshotSerializer {
|
|
2
|
+
/**
|
|
3
|
+
* Returns true when value can be serialized
|
|
4
|
+
*
|
|
5
|
+
* @param value The value to be serialized
|
|
6
|
+
*/
|
|
7
|
+
canSerialize(value: unknown): boolean;
|
|
8
|
+
/**
|
|
9
|
+
* Serializes value
|
|
10
|
+
*
|
|
11
|
+
* @param value The value to be serialized
|
|
12
|
+
* @throws {Error} Will throw an error if value cannot be serialized.
|
|
13
|
+
*/
|
|
14
|
+
serialize(value: unknown): SnapshotSerializerResult;
|
|
15
|
+
}
|
|
16
|
+
interface SnapshotSerializerResult {
|
|
17
|
+
/**
|
|
18
|
+
* The serialized value
|
|
19
|
+
*/
|
|
20
|
+
serializedValue: string;
|
|
21
|
+
/**
|
|
22
|
+
* The file extension associated with the serialized value
|
|
23
|
+
*/
|
|
3
24
|
fileExtension: string;
|
|
4
25
|
}
|
|
5
26
|
|
|
27
|
+
declare class CompositeSerializer implements SnapshotSerializer {
|
|
28
|
+
private readonly serializers;
|
|
29
|
+
constructor(serializers: SnapshotSerializer[]);
|
|
30
|
+
canSerialize(value: unknown): boolean;
|
|
31
|
+
serialize(value: unknown): SnapshotSerializerResult;
|
|
32
|
+
}
|
|
33
|
+
|
|
6
34
|
interface JsonSerializerOptions {
|
|
7
|
-
|
|
35
|
+
/**
|
|
36
|
+
* Serializes `undefined` properties in objects. By default, they are omitted.
|
|
37
|
+
*
|
|
38
|
+
* @default false
|
|
39
|
+
*/
|
|
40
|
+
includeUndefinedObjectProperties?: boolean;
|
|
41
|
+
}
|
|
42
|
+
declare class JsonSerializer implements SnapshotSerializer {
|
|
43
|
+
private readonly includeUndefinedObjectProperties;
|
|
44
|
+
constructor(options?: JsonSerializerOptions);
|
|
45
|
+
canSerialize(value: unknown): boolean;
|
|
46
|
+
serialize(value: unknown): SnapshotSerializerResult;
|
|
47
|
+
private normalizeValueRecursive;
|
|
48
|
+
private normalizeValue;
|
|
49
|
+
private normalizeNumber;
|
|
50
|
+
private normalizeArray;
|
|
51
|
+
private normalizeObject;
|
|
52
|
+
private normalizeDate;
|
|
53
|
+
private normalizePlainObject;
|
|
54
|
+
private normalizeMap;
|
|
55
|
+
private serializedValue;
|
|
56
|
+
private assertKeyType;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
declare class TextSerializer implements SnapshotSerializer {
|
|
60
|
+
canSerialize(value: unknown): value is string;
|
|
61
|
+
serialize(value: unknown): SnapshotSerializerResult;
|
|
62
|
+
private normalizeValue;
|
|
8
63
|
}
|
|
9
|
-
declare function serializeAsJson(value: unknown, options: JsonSerializerOptions): SerializerResult;
|
|
10
64
|
|
|
11
|
-
|
|
65
|
+
interface ValidationFileMatcherConfig {
|
|
66
|
+
/**
|
|
67
|
+
* Directory in which golden masters are stored
|
|
68
|
+
*
|
|
69
|
+
* @default "data/test/validation"
|
|
70
|
+
*/
|
|
71
|
+
validationDir?: string;
|
|
72
|
+
/**
|
|
73
|
+
* Directory in which file snapshots from test runs are stored
|
|
74
|
+
*
|
|
75
|
+
* @default "data/test/output"
|
|
76
|
+
*/
|
|
77
|
+
outputDir?: string;
|
|
78
|
+
}
|
|
79
|
+
interface MatchValidationFileOptions {
|
|
80
|
+
/**
|
|
81
|
+
* The full path to the current test file
|
|
82
|
+
*
|
|
83
|
+
* @example "src/tests/feature.test.ts"
|
|
84
|
+
*/
|
|
85
|
+
testPath: string;
|
|
86
|
+
/**
|
|
87
|
+
* The full path of titles describing the current test, including nested blocks
|
|
88
|
+
*
|
|
89
|
+
* @example ["test A", "when x, then y"]
|
|
90
|
+
*/
|
|
91
|
+
titlePath: string[];
|
|
92
|
+
/**
|
|
93
|
+
* Unique name of the file snapshot
|
|
94
|
+
*
|
|
95
|
+
* Used to distinguish multiple file snapshots within the same `test`.
|
|
96
|
+
*/
|
|
97
|
+
name?: string;
|
|
98
|
+
/**
|
|
99
|
+
* The serializer to use for the snapshot
|
|
100
|
+
*/
|
|
101
|
+
serializer: SnapshotSerializer;
|
|
102
|
+
}
|
|
103
|
+
interface ValidationFileMatcherResult {
|
|
104
|
+
actual: string;
|
|
105
|
+
expected: string;
|
|
106
|
+
actualFile: string;
|
|
107
|
+
validationFile: string;
|
|
108
|
+
message: () => string;
|
|
109
|
+
}
|
|
12
110
|
|
|
13
|
-
declare
|
|
111
|
+
declare class ValidationFileMatcher {
|
|
112
|
+
private readonly validationDir;
|
|
113
|
+
private readonly outputDir;
|
|
114
|
+
constructor(config?: ValidationFileMatcherConfig);
|
|
115
|
+
matchFileSnapshot(actual: unknown, options: MatchValidationFileOptions): ValidationFileMatcherResult;
|
|
116
|
+
private buildValidationFilePath;
|
|
117
|
+
private writeFileSnapshots;
|
|
118
|
+
}
|
|
14
119
|
|
|
15
|
-
export {
|
|
120
|
+
export { CompositeSerializer, JsonSerializer, TextSerializer, ValidationFileMatcher };
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,25 @@
|
|
|
1
|
-
// src/
|
|
1
|
+
// src/serializers/composite-serializer.ts
|
|
2
|
+
var CompositeSerializer = class {
|
|
3
|
+
serializers;
|
|
4
|
+
constructor(serializers) {
|
|
5
|
+
this.serializers = serializers;
|
|
6
|
+
}
|
|
7
|
+
canSerialize(value) {
|
|
8
|
+
return this.serializers.some(
|
|
9
|
+
(serializer) => serializer.canSerialize(value)
|
|
10
|
+
);
|
|
11
|
+
}
|
|
12
|
+
serialize(value) {
|
|
13
|
+
for (const serializer of this.serializers) {
|
|
14
|
+
if (serializer.canSerialize(value)) {
|
|
15
|
+
return serializer.serialize(value);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
throw new Error(`Missing serializer for value of type ${typeof value}.`);
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
// src/utils/guards.ts
|
|
2
23
|
function isArray(value) {
|
|
3
24
|
return Array.isArray(value);
|
|
4
25
|
}
|
|
@@ -13,157 +34,262 @@ function isPlainObject(value) {
|
|
|
13
34
|
return proto === null || proto === Object.prototype;
|
|
14
35
|
}
|
|
15
36
|
|
|
16
|
-
// src/json-serializer.ts
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
value: serializedValue,
|
|
22
|
-
fileExtension: "json"
|
|
23
|
-
};
|
|
24
|
-
}
|
|
25
|
-
function normalizeValueRecursive(value, options) {
|
|
26
|
-
if (isArray(value)) {
|
|
27
|
-
return normalizeArray(value, options);
|
|
37
|
+
// src/serializers/json-serializer.ts
|
|
38
|
+
var JsonSerializer = class {
|
|
39
|
+
includeUndefinedObjectProperties;
|
|
40
|
+
constructor(options = {}) {
|
|
41
|
+
this.includeUndefinedObjectProperties = options.includeUndefinedObjectProperties ?? false;
|
|
28
42
|
}
|
|
29
|
-
|
|
30
|
-
return
|
|
43
|
+
canSerialize(value) {
|
|
44
|
+
return true;
|
|
31
45
|
}
|
|
32
|
-
|
|
33
|
-
|
|
46
|
+
serialize(value) {
|
|
47
|
+
const jsonValue = isPlainObject(value) || isArray(value) ? this.normalizeValueRecursive(value) : this.normalizeValue(value);
|
|
48
|
+
const serializedValue = JSON.stringify(jsonValue, void 0, 2);
|
|
49
|
+
return {
|
|
50
|
+
serializedValue,
|
|
51
|
+
fileExtension: "json"
|
|
52
|
+
};
|
|
34
53
|
}
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
return
|
|
54
|
+
normalizeValueRecursive(value) {
|
|
55
|
+
if (isArray(value)) {
|
|
56
|
+
return this.normalizeArray(value);
|
|
57
|
+
}
|
|
58
|
+
if (isPlainObject(value)) {
|
|
59
|
+
return this.normalizePlainObject(value);
|
|
60
|
+
}
|
|
61
|
+
if (typeof value === "string" || typeof value === "boolean" || value === null) {
|
|
62
|
+
return value;
|
|
63
|
+
}
|
|
64
|
+
return this.normalizeValue(value);
|
|
46
65
|
}
|
|
47
|
-
|
|
48
|
-
|
|
66
|
+
normalizeValue(value) {
|
|
67
|
+
if (value === void 0) {
|
|
68
|
+
return this.serializedValue("undefined");
|
|
69
|
+
}
|
|
70
|
+
if (value === null || typeof value === "string" || typeof value === "boolean") {
|
|
71
|
+
return this.serializedValue(typeof value, { value });
|
|
72
|
+
}
|
|
73
|
+
if (typeof value === "number") {
|
|
74
|
+
return this.normalizeNumber(value);
|
|
75
|
+
}
|
|
76
|
+
if (typeof value === "bigint") {
|
|
77
|
+
return this.serializedValue("bigint", { value: value.toString() });
|
|
78
|
+
}
|
|
79
|
+
if (typeof value === "symbol") {
|
|
80
|
+
return this.serializedValue("symbol", { description: value.description });
|
|
81
|
+
}
|
|
82
|
+
if (typeof value === "function") {
|
|
83
|
+
return this.serializedValue("function", { name: value.name });
|
|
84
|
+
}
|
|
85
|
+
if (typeof value === "object") {
|
|
86
|
+
return this.normalizeObject(value);
|
|
87
|
+
}
|
|
88
|
+
throw new Error(
|
|
89
|
+
`Missing JSON normalization for value of type ${typeof value}.`
|
|
90
|
+
);
|
|
49
91
|
}
|
|
50
|
-
|
|
51
|
-
|
|
92
|
+
normalizeNumber(value) {
|
|
93
|
+
if (Number.isNaN(value)) {
|
|
94
|
+
return this.serializedValue("number", { value: "Number.NaN" });
|
|
95
|
+
}
|
|
96
|
+
switch (value) {
|
|
97
|
+
case Number.MIN_VALUE:
|
|
98
|
+
return this.serializedValue("number", { value: "Number.MIN_VALUE" });
|
|
99
|
+
case Number.MAX_VALUE:
|
|
100
|
+
return this.serializedValue("number", { value: "Number.MAX_VALUE" });
|
|
101
|
+
case Number.MIN_SAFE_INTEGER:
|
|
102
|
+
return this.serializedValue("number", {
|
|
103
|
+
value: "Number.MIN_SAFE_INTEGER"
|
|
104
|
+
});
|
|
105
|
+
case Number.MAX_SAFE_INTEGER:
|
|
106
|
+
return this.serializedValue("number", {
|
|
107
|
+
value: "Number.MAX_SAFE_INTEGER"
|
|
108
|
+
});
|
|
109
|
+
case Number.NEGATIVE_INFINITY:
|
|
110
|
+
return this.serializedValue("number", {
|
|
111
|
+
value: "Number.NEGATIVE_INFINITY"
|
|
112
|
+
});
|
|
113
|
+
case Number.POSITIVE_INFINITY:
|
|
114
|
+
return this.serializedValue("number", {
|
|
115
|
+
value: "Number.POSITIVE_INFINITY"
|
|
116
|
+
});
|
|
117
|
+
default:
|
|
118
|
+
return value;
|
|
119
|
+
}
|
|
52
120
|
}
|
|
53
|
-
|
|
54
|
-
return
|
|
121
|
+
normalizeArray(value) {
|
|
122
|
+
return value.map((item) => this.normalizeValueRecursive(item));
|
|
55
123
|
}
|
|
56
|
-
|
|
57
|
-
|
|
124
|
+
normalizeObject(value) {
|
|
125
|
+
if (value instanceof Date) {
|
|
126
|
+
return this.normalizeDate(value);
|
|
127
|
+
}
|
|
128
|
+
if (value instanceof Promise) {
|
|
129
|
+
return this.serializedValue("Promise");
|
|
130
|
+
}
|
|
131
|
+
if (value instanceof Set) {
|
|
132
|
+
return this.serializedValue("Set", {
|
|
133
|
+
values: this.normalizeArray(Array.from(value.values()))
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
if (value instanceof Map) {
|
|
137
|
+
const mapAsObject = this.normalizeMap(value);
|
|
138
|
+
return this.serializedValue("Map", {
|
|
139
|
+
values: this.normalizePlainObject(mapAsObject)
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
throw new Error(
|
|
143
|
+
`Missing JSON normalization for object of type ${Object.getPrototypeOf(value)}`
|
|
144
|
+
);
|
|
58
145
|
}
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
if (Number.isNaN(value)) {
|
|
65
|
-
return normalizedValue("number", { value: "Number.NaN" });
|
|
66
|
-
}
|
|
67
|
-
switch (value) {
|
|
68
|
-
case Number.MIN_VALUE:
|
|
69
|
-
return normalizedValue("number", { value: "Number.MIN_VALUE" });
|
|
70
|
-
case Number.MAX_VALUE:
|
|
71
|
-
return normalizedValue("number", { value: "Number.MAX_VALUE" });
|
|
72
|
-
case Number.MIN_SAFE_INTEGER:
|
|
73
|
-
return normalizedValue("number", { value: "Number.MIN_SAFE_INTEGER" });
|
|
74
|
-
case Number.MAX_SAFE_INTEGER:
|
|
75
|
-
return normalizedValue("number", { value: "Number.MAX_SAFE_INTEGER" });
|
|
76
|
-
case Number.NEGATIVE_INFINITY:
|
|
77
|
-
return normalizedValue("number", { value: "Number.NEGATIVE_INFINITY" });
|
|
78
|
-
case Number.POSITIVE_INFINITY:
|
|
79
|
-
return normalizedValue("number", { value: "Number.POSITIVE_INFINITY" });
|
|
80
|
-
default:
|
|
81
|
-
return value;
|
|
146
|
+
normalizeDate(value) {
|
|
147
|
+
if (Number.isNaN(value.getTime())) {
|
|
148
|
+
return this.serializedValue("Date", { value: "Invalid date" });
|
|
149
|
+
}
|
|
150
|
+
return this.serializedValue("Date", { value: value.toISOString() });
|
|
82
151
|
}
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
152
|
+
normalizePlainObject(value) {
|
|
153
|
+
const normalizedObject = {};
|
|
154
|
+
for (const [key, propertyValue] of Object.entries(value)) {
|
|
155
|
+
if (propertyValue === void 0 && !this.includeUndefinedObjectProperties) {
|
|
156
|
+
continue;
|
|
157
|
+
}
|
|
158
|
+
this.assertKeyType(key);
|
|
159
|
+
normalizedObject[key] = this.normalizeValueRecursive(propertyValue);
|
|
160
|
+
}
|
|
161
|
+
return normalizedObject;
|
|
90
162
|
}
|
|
91
|
-
|
|
92
|
-
return
|
|
163
|
+
normalizeMap(value) {
|
|
164
|
+
return Array.from(value.entries()).reduce(
|
|
165
|
+
(object, [key, value2]) => {
|
|
166
|
+
this.assertKeyType(key);
|
|
167
|
+
object[key] = value2;
|
|
168
|
+
return object;
|
|
169
|
+
},
|
|
170
|
+
{}
|
|
171
|
+
);
|
|
93
172
|
}
|
|
94
|
-
|
|
95
|
-
return
|
|
96
|
-
values: normalizeArray(Array.from(value.values()), options)
|
|
97
|
-
});
|
|
173
|
+
serializedValue(type, additionalProps = {}) {
|
|
174
|
+
return { $type: type, ...additionalProps };
|
|
98
175
|
}
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
});
|
|
176
|
+
assertKeyType(key) {
|
|
177
|
+
if (!(typeof key === "string")) {
|
|
178
|
+
throw new Error(`Key of type ${typeof key} cannot be normalized.`);
|
|
179
|
+
}
|
|
104
180
|
}
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
return normalizedValue("Date", { value: "Invalid date" });
|
|
181
|
+
};
|
|
182
|
+
|
|
183
|
+
// src/serializers/text-serializer.ts
|
|
184
|
+
var TextSerializer = class {
|
|
185
|
+
canSerialize(value) {
|
|
186
|
+
return typeof value === "string";
|
|
112
187
|
}
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
if (propertyValue === void 0 && !options.includeUndefinedObjectProperties) {
|
|
119
|
-
continue;
|
|
188
|
+
serialize(value) {
|
|
189
|
+
if (!this.canSerialize(value)) {
|
|
190
|
+
throw new Error(
|
|
191
|
+
`Missing text serialization for value of type ${typeof value}.`
|
|
192
|
+
);
|
|
120
193
|
}
|
|
121
|
-
|
|
122
|
-
|
|
194
|
+
return {
|
|
195
|
+
serializedValue: this.normalizeValue(value),
|
|
196
|
+
fileExtension: "txt"
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
normalizeValue(value) {
|
|
200
|
+
return value.trim();
|
|
123
201
|
}
|
|
124
|
-
|
|
202
|
+
};
|
|
203
|
+
|
|
204
|
+
// src/matcher/validation-file-matcher.ts
|
|
205
|
+
import * as fs2 from "fs";
|
|
206
|
+
import * as path from "path";
|
|
207
|
+
|
|
208
|
+
// src/utils/file.ts
|
|
209
|
+
import fs from "fs";
|
|
210
|
+
var NEW_LINE_SEPARATOR = "\n";
|
|
211
|
+
function normalizeFileName(testName) {
|
|
212
|
+
return testName.replaceAll(/\+0/g, "0").replaceAll(/'([\w ]+)'/g, "$1").replaceAll(/[ .:']/g, "_").replaceAll(/,/g, "");
|
|
125
213
|
}
|
|
126
|
-
function
|
|
127
|
-
|
|
128
|
-
(object, [key, value2]) => {
|
|
129
|
-
assertKeyType(key);
|
|
130
|
-
object[key] = value2;
|
|
131
|
-
return object;
|
|
132
|
-
},
|
|
133
|
-
{}
|
|
134
|
-
);
|
|
214
|
+
function mkdirRecursive(path2) {
|
|
215
|
+
fs.mkdirSync(path2, { recursive: true });
|
|
135
216
|
}
|
|
136
|
-
function
|
|
137
|
-
return {
|
|
217
|
+
function readSnapshotFile(path2) {
|
|
218
|
+
return fs.readFileSync(path2, { encoding: "utf8" });
|
|
138
219
|
}
|
|
139
|
-
function
|
|
140
|
-
|
|
141
|
-
|
|
220
|
+
function writeSnapshotFile(file, data, markAsMissing = false) {
|
|
221
|
+
let finalizedData = addTrailingNewLine(data);
|
|
222
|
+
if (markAsMissing) {
|
|
223
|
+
finalizedData = addMissingFileMarker(finalizedData);
|
|
142
224
|
}
|
|
225
|
+
fs.writeFileSync(file, finalizedData, { encoding: "utf8" });
|
|
143
226
|
}
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
function serializeAsText(value) {
|
|
147
|
-
return {
|
|
148
|
-
value: normalizeValue2(value),
|
|
149
|
-
fileExtension: "txt"
|
|
150
|
-
};
|
|
227
|
+
function addTrailingNewLine(data) {
|
|
228
|
+
return `${data}${NEW_LINE_SEPARATOR}`;
|
|
151
229
|
}
|
|
152
|
-
function
|
|
153
|
-
|
|
154
|
-
return value.trim();
|
|
155
|
-
}
|
|
156
|
-
throw new Error(
|
|
157
|
-
`Missing text normalization for value of type ${typeof value}.`
|
|
158
|
-
);
|
|
230
|
+
function addMissingFileMarker(data) {
|
|
231
|
+
return `===== missing file =====${NEW_LINE_SEPARATOR}${data}`;
|
|
159
232
|
}
|
|
160
233
|
|
|
161
|
-
// src/
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
234
|
+
// src/matcher/validation-file-matcher.ts
|
|
235
|
+
var ValidationFileMatcher = class {
|
|
236
|
+
validationDir;
|
|
237
|
+
outputDir;
|
|
238
|
+
constructor(config = {}) {
|
|
239
|
+
this.validationDir = config.validationDir ?? "data/test/validation";
|
|
240
|
+
this.outputDir = config.outputDir ?? "data/test/output";
|
|
241
|
+
}
|
|
242
|
+
matchFileSnapshot(actual, options) {
|
|
243
|
+
const { testPath, titlePath, name, serializer } = options;
|
|
244
|
+
if (!serializer.canSerialize(actual)) {
|
|
245
|
+
throw new Error(`Cannot serialize value of type ${typeof actual}`);
|
|
246
|
+
}
|
|
247
|
+
const serializerResult = serializer.serialize(actual);
|
|
248
|
+
const validationFilePath = this.buildValidationFilePath({
|
|
249
|
+
titlePath,
|
|
250
|
+
testPath,
|
|
251
|
+
name,
|
|
252
|
+
fileExtension: serializerResult.fileExtension
|
|
253
|
+
});
|
|
254
|
+
return this.writeFileSnapshots(
|
|
255
|
+
serializerResult.serializedValue,
|
|
256
|
+
validationFilePath
|
|
257
|
+
);
|
|
258
|
+
}
|
|
259
|
+
buildValidationFilePath(options) {
|
|
260
|
+
const { testPath, titlePath, name, fileExtension } = options;
|
|
261
|
+
const normalizedTitlePath = titlePath.map(normalizeFileName);
|
|
262
|
+
const normalizedFileName = name !== void 0 ? `_${normalizeFileName(name)}` : "";
|
|
263
|
+
const normalizedTestName = normalizedTitlePath.pop();
|
|
264
|
+
const validationFilePath = path.join(testPath, ...normalizedTitlePath);
|
|
265
|
+
const validationFileName = `${normalizedTestName}${normalizedFileName}.${fileExtension}`;
|
|
266
|
+
return path.join(validationFilePath, validationFileName);
|
|
267
|
+
}
|
|
268
|
+
writeFileSnapshots(actual, validationFilePath) {
|
|
269
|
+
const validationFileDir = path.dirname(validationFilePath);
|
|
270
|
+
const testOutputDir = `${this.outputDir}/${validationFileDir}`;
|
|
271
|
+
const actualFile = `${this.outputDir}/${validationFilePath}`;
|
|
272
|
+
const testValidationDir = `${this.validationDir}/${validationFileDir}`;
|
|
273
|
+
const validationFile = `${this.validationDir}/${validationFilePath}`;
|
|
274
|
+
mkdirRecursive(testOutputDir);
|
|
275
|
+
mkdirRecursive(testValidationDir);
|
|
276
|
+
if (!fs2.existsSync(validationFile)) {
|
|
277
|
+
writeSnapshotFile(validationFile, actual, true);
|
|
278
|
+
}
|
|
279
|
+
writeSnapshotFile(actualFile, actual);
|
|
280
|
+
return {
|
|
281
|
+
actual: readSnapshotFile(actualFile),
|
|
282
|
+
expected: readSnapshotFile(validationFile),
|
|
283
|
+
actualFile,
|
|
284
|
+
validationFile,
|
|
285
|
+
message: () => `Actual file '${actualFile}'
|
|
286
|
+
does not match validation file '${validationFile}'`
|
|
287
|
+
};
|
|
288
|
+
}
|
|
289
|
+
};
|
|
165
290
|
export {
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
291
|
+
CompositeSerializer,
|
|
292
|
+
JsonSerializer,
|
|
293
|
+
TextSerializer,
|
|
294
|
+
ValidationFileMatcher
|
|
169
295
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cronn/lib-file-snapshots",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "The library agnostic core for testing file snapshots",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"file snapshots"
|
|
@@ -33,11 +33,11 @@
|
|
|
33
33
|
],
|
|
34
34
|
"devDependencies": {
|
|
35
35
|
"@biomejs/biome": "1.9.4",
|
|
36
|
-
"@types/node": "22.15.
|
|
37
|
-
"@vitest/coverage-istanbul": "3.
|
|
36
|
+
"@types/node": "22.15.30",
|
|
37
|
+
"@vitest/coverage-istanbul": "3.2.3",
|
|
38
38
|
"tsup": "8.5.0",
|
|
39
39
|
"typescript": "5.8.3",
|
|
40
|
-
"vitest": "3.
|
|
40
|
+
"vitest": "3.2.3",
|
|
41
41
|
"@cronn/shared-configs": "0.0.0"
|
|
42
42
|
},
|
|
43
43
|
"scripts": {
|
|
@@ -47,6 +47,6 @@
|
|
|
47
47
|
"test:coverage": "vitest run --coverage",
|
|
48
48
|
"compile": "tsc",
|
|
49
49
|
"build": "tsup",
|
|
50
|
-
"ci": "biome ci . && pnpm run compile
|
|
50
|
+
"ci": "biome ci . && pnpm run compile && pnpm run test:coverage && pnpm run build"
|
|
51
51
|
}
|
|
52
52
|
}
|