@systemfsoftware/vitest 0.2.0 → 1.0.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/CHANGELOG.md +12 -0
- package/dist/{checks-Cq9of-Lx.d.ts → checks-DiuzHhQM.d.ts} +1 -105
- package/dist/{engine-YsoQ_9we.d.ts → engine-CMvYG5V0.d.ts} +14 -6
- package/dist/{failure-BquJJPFZ.mjs → failure-D8mPXwf4.mjs} +252 -176
- package/dist/failure.d.ts +139 -15
- package/dist/failure.mjs +3 -3
- package/dist/{guard-p_8ARgPm.mjs → guard-BocOhXt2.mjs} +11 -15
- package/dist/guard.mjs +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.mjs +14 -17
- package/dist/integration.d.ts +1 -1
- package/dist/integration.mjs +1 -1
- package/dist/{test-context-ChvjVyCo.mjs → test-context-D_-acRSc.mjs} +7 -12
- package/package.json +12 -4
|
@@ -1,27 +1,133 @@
|
|
|
1
1
|
|
|
2
|
-
import { d as
|
|
3
|
-
import { b as refusedRecordDetail } from "./guard-p_8ARgPm.mjs";
|
|
2
|
+
import { d as isUserFrame, f as siteOfFrame, i as checksFor, o as makeLedger, p as withRaisingFrame, r as Asserted, s as callFrame, t as VitestTestContext, u as framesOf$1 } from "./test-context-D_-acRSc.mjs";
|
|
4
3
|
import * as V from "vitest";
|
|
5
4
|
import { TestRunner, inject } from "vitest";
|
|
6
5
|
import * as Cause from "effect/Cause";
|
|
7
|
-
import * as Effect from "effect/Effect";
|
|
6
|
+
import * as Effect$1 from "effect/Effect";
|
|
7
|
+
import * as Equal from "effect/Equal";
|
|
8
8
|
import * as Exit from "effect/Exit";
|
|
9
9
|
import * as Function from "effect/Function";
|
|
10
10
|
import * as Schema$1 from "effect/Schema";
|
|
11
|
-
import * as Option from "effect/Option";
|
|
12
|
-
import { Schema } from "effect";
|
|
11
|
+
import * as Option$1 from "effect/Option";
|
|
13
12
|
import * as Match from "effect/Match";
|
|
14
13
|
import * as Tracer from "effect/Tracer";
|
|
15
|
-
import
|
|
14
|
+
import { Effect, Option, Schema, SchemaGetter, SchemaIssue } from "effect";
|
|
15
|
+
import * as Arbitrary from "effect/Arbitrary";
|
|
16
16
|
import * as Data from "effect/Data";
|
|
17
|
-
import * as Equal from "effect/Equal";
|
|
18
17
|
//#region src/internal/property/defaults.ts
|
|
19
18
|
/** @internal The `test.provide` key the shared config fills with this run's tier's check options. */
|
|
20
19
|
const checkDefaultsKey = "@systemfsoftware/vitest:property-check";
|
|
21
20
|
/** @internal The configured property-check defaults, or `undefined` when the run provided none. */
|
|
22
21
|
const providedCheckDefaults = () => inject(checkDefaultsKey);
|
|
23
22
|
//#endregion
|
|
23
|
+
//#region src/replay.schema.ts
|
|
24
|
+
/**
|
|
25
|
+
* The one replay grammar (KTD10, R6): the `CONFORMANCE_REPLAY` text a failure record's rerun line carries and
|
|
26
|
+
* the spec runtime reads back to re-run the same schedule. The text names the seed a generator chose and the
|
|
27
|
+
* decisions it took, in order — `seed=7;path=1,2,3` — and the path is empty when the run took no decision
|
|
28
|
+
* (`seed=1;path=`). A text that names neither is not a replay.
|
|
29
|
+
*
|
|
30
|
+
* The seed and every decision are branded whole numbers (CONST-D3), and the text is a codec rooted at
|
|
31
|
+
* `Schema.String`, so one declaration serves both the writer and the reader instead of a pattern each.
|
|
32
|
+
*
|
|
33
|
+
* @since 4.0.0
|
|
34
|
+
*/
|
|
35
|
+
/** The seed a replay names: the whole number a generator chose, never negative (CONST-D3). */
|
|
36
|
+
const ReplaySeed = Schema.Int.pipe(Schema.check(Schema.isGreaterThanOrEqualTo(0)), Schema.brand("ReplaySeed"));
|
|
37
|
+
/** One decision along a replay path: the index the scheduler picked at that step (CONST-D3). */
|
|
38
|
+
const ReplayStep = Schema.Int.pipe(Schema.check(Schema.isGreaterThanOrEqualTo(0)), Schema.brand("ReplayStep"));
|
|
39
|
+
/** The replay a generator chose: its seed and the decisions it took, in order (R6). */
|
|
40
|
+
const Replay = Schema.Struct({
|
|
41
|
+
seed: ReplaySeed,
|
|
42
|
+
path: Schema.Array(ReplayStep)
|
|
43
|
+
});
|
|
44
|
+
const SEED_PREFIX = "seed=";
|
|
45
|
+
const PATH_PREFIX = "path=";
|
|
46
|
+
const PAIR_SEPARATOR = ";";
|
|
47
|
+
const ENTRY_SEPARATOR = ",";
|
|
48
|
+
const WHOLE_NUMBER = /^\d+$/u;
|
|
49
|
+
const NOT_A_REPLAY = "a replay reads \"seed=<whole number>;path=<comma-separated whole numbers>\"";
|
|
50
|
+
const wholeNumberOf = (text) => WHOLE_NUMBER.test(text) ? Number(text) : void 0;
|
|
51
|
+
const seedDigitsOf = (text) => text.startsWith(SEED_PREFIX) ? text.slice(5) : void 0;
|
|
52
|
+
const pathDigitsOf = (text) => text.startsWith(PATH_PREFIX) ? text.slice(5) : void 0;
|
|
53
|
+
const entriesOf$1 = (text) => text.length === 0 ? [] : text.split(ENTRY_SEPARATOR);
|
|
54
|
+
const wholeNumbersOf = (entries) => {
|
|
55
|
+
const numbers = entries.map(wholeNumberOf);
|
|
56
|
+
return numbers.every((value) => value !== void 0) ? numbers : void 0;
|
|
57
|
+
};
|
|
58
|
+
const seedIn = (part) => Option.flatMap(Option.fromUndefinedOr(seedDigitsOf(part)), (digits) => Option.fromUndefinedOr(wholeNumberOf(digits)));
|
|
59
|
+
const decisionsIn = (part) => Option.flatMap(Option.fromUndefinedOr(pathDigitsOf(part)), (entries) => Option.fromUndefinedOr(wholeNumbersOf(entriesOf$1(entries))));
|
|
60
|
+
const pairPartsOf = (text) => {
|
|
61
|
+
const [seedPart, pathPart, ...rest] = text.split(PAIR_SEPARATOR);
|
|
62
|
+
return rest.length === 0 ? Option.all([Option.fromUndefinedOr(seedPart), Option.fromUndefinedOr(pathPart)]) : Option.none();
|
|
63
|
+
};
|
|
64
|
+
/** The seed and decisions a pair names, or nothing when the pair is not `seed=…;path=…`. */
|
|
65
|
+
const namedPairOf = (text) => Option.flatMap(pairPartsOf(text), ([seedPart, pathPart]) => Option.all([seedIn(seedPart), decisionsIn(pathPart)]));
|
|
66
|
+
/** The replay a seed and decision path name, or nothing when either is outside the grammar's domain. */
|
|
67
|
+
const replayOfParts = (parts) => Schema.decodeOption(Replay)(parts);
|
|
68
|
+
const replayOfName = (text) => Option.flatMap(namedPairOf(text), ([seed, path]) => replayOfParts({
|
|
69
|
+
seed,
|
|
70
|
+
path
|
|
71
|
+
}));
|
|
72
|
+
const textOfEncodedReplay = (replay) => `${SEED_PREFIX}${replay.seed}${PAIR_SEPARATOR}${PATH_PREFIX}${replay.path.join(ENTRY_SEPARATOR)}`;
|
|
73
|
+
const replayRefusal = (text) => /* @__PURE__ */ new Error(`CONFORMANCE_REPLAY names neither a seed nor a decision path: ${text}`);
|
|
74
|
+
/**
|
|
75
|
+
* The `CONFORMANCE_REPLAY` text as the replay it names. A text a seed and a path cannot be read out of is refused
|
|
76
|
+
* with the same prose the spec runtime has always thrown, so the grammar and its refusal share one home.
|
|
77
|
+
*
|
|
78
|
+
* @since 4.0.0
|
|
79
|
+
*/
|
|
80
|
+
const replayOfText = (text) => Option.match(replayOfName(text), {
|
|
81
|
+
onNone: () => {
|
|
82
|
+
throw replayRefusal(text);
|
|
83
|
+
},
|
|
84
|
+
onSome: (replay) => replay
|
|
85
|
+
});
|
|
86
|
+
/** The text a replay is written as: the `CONFORMANCE_REPLAY` value a rerun line carries (R6).
|
|
87
|
+
*
|
|
88
|
+
* @since 4.0.0
|
|
89
|
+
*/
|
|
90
|
+
const replayTextOf = (replay) => textOfEncodedReplay(replay);
|
|
91
|
+
/**
|
|
92
|
+
* The replay codec: `Schema.String` in, a replay out. A text that names no seed and path fails the decode, and
|
|
93
|
+
* every replay encodes back to the text it was read from.
|
|
94
|
+
*
|
|
95
|
+
* @since 4.0.0
|
|
96
|
+
*/
|
|
97
|
+
const ReplayFromText = Schema.String.pipe(Schema.decodeTo(Replay, {
|
|
98
|
+
decode: SchemaGetter.transformEffect((text, options) => Effect.fromOption(replayOfName(text), () => new SchemaIssue.InvalidValue({ message: NOT_A_REPLAY }, text, options))),
|
|
99
|
+
encode: SchemaGetter.transform(textOfEncodedReplay)
|
|
100
|
+
}));
|
|
101
|
+
//#endregion
|
|
24
102
|
//#region src/internal/errors.schema.ts
|
|
103
|
+
/**
|
|
104
|
+
* The contract rules a rendered failure record can break (R10, KTD7).
|
|
105
|
+
*
|
|
106
|
+
* @internal
|
|
107
|
+
*/
|
|
108
|
+
const Breach = Schema.Literals([
|
|
109
|
+
"R1",
|
|
110
|
+
"R2",
|
|
111
|
+
"R6"
|
|
112
|
+
]);
|
|
113
|
+
/** A record's breaches, in the order the renderer found them.
|
|
114
|
+
*
|
|
115
|
+
* @internal
|
|
116
|
+
*/
|
|
117
|
+
const Breaches = Schema.Array(Breach);
|
|
118
|
+
/** The fixed prose each breach is refused with; nothing ever reads a refusal back, so it cannot recurse. */
|
|
119
|
+
const REFUSED_BREACH_TEXT = {
|
|
120
|
+
R1: "the headline is empty",
|
|
121
|
+
R2: "the record names no source location",
|
|
122
|
+
R6: "a replay value names a run no generator chose, or the rerun line is missing"
|
|
123
|
+
};
|
|
124
|
+
/**
|
|
125
|
+
* The one detail a record refusal carries: every breach the renderer found, in the prose above (R10, KTD7). The
|
|
126
|
+
* breach letter is not printed: a reader acts on what is missing, not on which requirement numbered it.
|
|
127
|
+
*
|
|
128
|
+
* @internal
|
|
129
|
+
*/
|
|
130
|
+
const refusedRecordDetail = (breaches) => `✗ refused a failure record: ${breaches.map((breach) => REFUSED_BREACH_TEXT[breach]).join(", and ")}`;
|
|
25
131
|
/** @internal */
|
|
26
132
|
var NonBooleanVerdict = class extends Schema.TaggedError()("NonBooleanVerdict", { detail: Schema.String }) {
|
|
27
133
|
get message() {
|
|
@@ -48,11 +154,7 @@ var InvalidBudget = class extends Schema.TaggedError()("InvalidBudget", { detail
|
|
|
48
154
|
};
|
|
49
155
|
/** @internal */
|
|
50
156
|
var FailureRecordRefused = class extends Schema.TaggedError()("FailureRecordRefused", {
|
|
51
|
-
breaches:
|
|
52
|
-
"R1",
|
|
53
|
-
"R2",
|
|
54
|
-
"R6"
|
|
55
|
-
])),
|
|
157
|
+
breaches: Breaches,
|
|
56
158
|
cause: Schema.optional(Schema.Unknown)
|
|
57
159
|
}) {
|
|
58
160
|
get message() {
|
|
@@ -60,6 +162,52 @@ var FailureRecordRefused = class extends Schema.TaggedError()("FailureRecordRefu
|
|
|
60
162
|
}
|
|
61
163
|
};
|
|
62
164
|
//#endregion
|
|
165
|
+
//#region src/internal/provided.schema.ts
|
|
166
|
+
/**
|
|
167
|
+
* The npm name of the package under test, as its own `package.json` spells it.
|
|
168
|
+
*
|
|
169
|
+
* @internal
|
|
170
|
+
*/
|
|
171
|
+
const PackageName = Schema.NonEmptyString.pipe(Schema.brand("PackageName"));
|
|
172
|
+
/**
|
|
173
|
+
* The workspace root every rendered path is relativized against.
|
|
174
|
+
*
|
|
175
|
+
* @internal
|
|
176
|
+
*/
|
|
177
|
+
const WorkspaceRoot = Schema.NonEmptyString.pipe(Schema.brand("WorkspaceRoot"));
|
|
178
|
+
//#endregion
|
|
179
|
+
//#region src/internal/provided.ts
|
|
180
|
+
/**
|
|
181
|
+
* The values the shared vitest config provides for the fork: the package under test's npm name and the workspace
|
|
182
|
+
* root every rendered path is relativized against. Both are read out of the run's provided context (Vitest's
|
|
183
|
+
* `inject`), so no production source reads a Node built-in, and an absent value is simply `undefined` — a rerun
|
|
184
|
+
* line then drops its package filter, and paths print absolute (R6, KTD5).
|
|
185
|
+
*
|
|
186
|
+
* The values are branded (`provided.schema.ts`): a package name and a workspace root are not interchangeable
|
|
187
|
+
* text (CONST-D3).
|
|
188
|
+
*
|
|
189
|
+
* @since 4.0.0
|
|
190
|
+
*/
|
|
191
|
+
/** @internal */
|
|
192
|
+
const packageKey = "@systemfsoftware/vitest:package";
|
|
193
|
+
/** @internal */
|
|
194
|
+
const workspaceRootKey = "@systemfsoftware/vitest:workspace-root";
|
|
195
|
+
const isText$1 = (value) => typeof value === "string";
|
|
196
|
+
const nonEmpty = (value) => value.length === 0 ? void 0 : value;
|
|
197
|
+
const nonEmptyText$1 = (value) => isText$1(value) ? nonEmpty(value) : void 0;
|
|
198
|
+
const read = (key) => {
|
|
199
|
+
try {
|
|
200
|
+
return nonEmptyText$1(inject(key));
|
|
201
|
+
} catch {
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
};
|
|
205
|
+
const readNamed = (key, schema) => Option.getOrUndefined(Option.flatMap(Option.fromUndefinedOr(read(key)), (text) => Schema.decodeOption(schema)(text)));
|
|
206
|
+
/** @internal */
|
|
207
|
+
const providedPackage = () => readNamed(packageKey, PackageName);
|
|
208
|
+
/** @internal */
|
|
209
|
+
const providedRoot = () => readNamed(workspaceRootKey, WorkspaceRoot);
|
|
210
|
+
//#endregion
|
|
63
211
|
//#region src/internal/failure-record.ts
|
|
64
212
|
/**
|
|
65
213
|
* The one renderer for a spec failure: the failure and the spans its run recorded become the record Vitest
|
|
@@ -91,7 +239,7 @@ const FILE_PROTOCOL = "file://";
|
|
|
91
239
|
const UNKNOWN_SITE = "?";
|
|
92
240
|
const DEFAULT_FAILURE_NAME = "Error";
|
|
93
241
|
const NEVER_FINISHED = " (never finished)";
|
|
94
|
-
const CAUSE_DEPTH
|
|
242
|
+
const CAUSE_DEPTH = 6;
|
|
95
243
|
/** The fields a layer's own values exclude: the chain renders the cause, and the raise site names the stack. */
|
|
96
244
|
const SKIPPED_FIELDS = {
|
|
97
245
|
[TAG_FIELD]: true,
|
|
@@ -101,7 +249,7 @@ const SKIPPED_FIELDS = {
|
|
|
101
249
|
[CAUSE_FIELD]: true
|
|
102
250
|
};
|
|
103
251
|
/** The contract's "first location": any `<path>:<line>` the record names. */
|
|
104
|
-
const LOCATION
|
|
252
|
+
const LOCATION = /(?:[\w.@-]+\/)*[\w.@-]+\.[cm]?[jt]sx?:\d+/u;
|
|
105
253
|
const COLUMN_SUFFIX = /:\d+$/u;
|
|
106
254
|
const MARK = {
|
|
107
255
|
passed: "✓",
|
|
@@ -112,24 +260,24 @@ const not = (value) => !value;
|
|
|
112
260
|
const and = (left, right) => left && right;
|
|
113
261
|
const or = (left, right) => left || right;
|
|
114
262
|
const firstPresent = (values) => values.find((value) => value !== void 0);
|
|
115
|
-
const isObject
|
|
116
|
-
const isText
|
|
263
|
+
const isObject = (value) => typeof value === "object" && value !== null;
|
|
264
|
+
const isText = (value) => typeof value === "string";
|
|
117
265
|
const isArray = (value) => Array.isArray(value);
|
|
118
266
|
const isNumber = (value) => typeof value === "number";
|
|
119
267
|
const isBoolean = (value) => typeof value === "boolean";
|
|
120
268
|
const isBigInt = (value) => typeof value === "bigint";
|
|
121
269
|
const isNull = (value) => value === null;
|
|
122
270
|
const isPrimitive = (value) => or(or(isNumber(value), isBoolean(value)), isBigInt(value));
|
|
123
|
-
const objectOrUndefined
|
|
271
|
+
const objectOrUndefined = (value) => isObject(value) ? value : void 0;
|
|
124
272
|
const isFieldName = (name) => SKIPPED_FIELDS[name] !== true;
|
|
125
273
|
const presentOrUndefined = (text) => text.length === 0 ? void 0 : text;
|
|
126
|
-
const nonEmptyText
|
|
127
|
-
const fieldOf
|
|
274
|
+
const nonEmptyText = (text) => text === void 0 ? void 0 : presentOrUndefined(text);
|
|
275
|
+
const fieldOf = (value, key) => Reflect.get(value, key);
|
|
128
276
|
const textFieldOf = (value, key) => {
|
|
129
|
-
const field = fieldOf
|
|
130
|
-
return isText
|
|
277
|
+
const field = fieldOf(value, key);
|
|
278
|
+
return isText(field) ? field : void 0;
|
|
131
279
|
};
|
|
132
|
-
const nonEmptyFieldOf = (value, key) => nonEmptyText
|
|
280
|
+
const nonEmptyFieldOf = (value, key) => nonEmptyText(textFieldOf(value, key));
|
|
133
281
|
const tagFieldOf = (value) => nonEmptyFieldOf(value, TAG_FIELD);
|
|
134
282
|
const messageFieldOf = (value) => nonEmptyFieldOf(value, MESSAGE_FIELD);
|
|
135
283
|
const pairOf = (name, text) => ({
|
|
@@ -139,10 +287,10 @@ const pairOf = (name, text) => ({
|
|
|
139
287
|
const pairTextOf = (pair) => `${JSON.stringify(pair.name)}:${pair.text}`;
|
|
140
288
|
const pairTextsOf = (pairs) => pairs.map(pairTextOf);
|
|
141
289
|
const hasPair = (pairs, name) => pairs.some((pair) => pair.name === name);
|
|
142
|
-
const pairsOf = (value) => isObject
|
|
290
|
+
const pairsOf = (value) => isObject(value) ? Object.keys(value).map((key) => pairOf(key, renderValue(fieldOf(value, key)))) : [];
|
|
143
291
|
const fieldsOf = (value) => pairsOf(value).filter((pair) => isFieldName(pair.name));
|
|
144
|
-
const renderValue = (value) => isObject
|
|
145
|
-
const renderScalar = (value) => isText
|
|
292
|
+
const renderValue = (value) => isObject(value) ? renderObject(value) : renderScalar(value);
|
|
293
|
+
const renderScalar = (value) => isText(value) ? JSON.stringify(value) : renderPrimitive(value);
|
|
146
294
|
const renderPrimitive = (value) => isBigInt(value) ? `${value}n` : renderPlain(value);
|
|
147
295
|
const renderPlain = (value) => isPrimitive(value) ? `${value}` : renderOther(value);
|
|
148
296
|
const renderOther = (value) => isNull(value) ? "null" : renderUndefined(value);
|
|
@@ -154,9 +302,9 @@ const renderRecord$1 = (value) => `{${pairTextsOf(pairsOf(value)).join(",")}}`;
|
|
|
154
302
|
const bracesOf = (pairs) => ` {${pairTextsOf(pairs).join(",")}}`;
|
|
155
303
|
const renderFields = (value) => bracesOf(fieldsOf(value));
|
|
156
304
|
const textSummaryOf = (text) => text.length === 0 ? text : JSON.stringify(text);
|
|
157
|
-
const scalarSummaryOf = (value) => isText
|
|
305
|
+
const scalarSummaryOf = (value) => isText(value) ? textSummaryOf(value) : renderScalar(value);
|
|
158
306
|
/** @internal */
|
|
159
|
-
const summaryOf = (value) => isObject
|
|
307
|
+
const summaryOf = (value) => isObject(value) ? objectSummaryOf(value) : scalarSummaryOf(value);
|
|
160
308
|
const objectSummaryOf = (value) => {
|
|
161
309
|
const tag = tagFieldOf(value);
|
|
162
310
|
return tag === void 0 ? untaggedSummaryOf(value) : taggedSummaryOf(tag, value);
|
|
@@ -179,21 +327,21 @@ const objectNameOf = (value) => firstPresent([tagFieldOf(value), nonEmptyFieldOf
|
|
|
179
327
|
const headlineOf = (layers) => layers.length === 0 ? "" : summaryOf(layers[0]);
|
|
180
328
|
const nameOf = (layers) => {
|
|
181
329
|
const entry = layers[0];
|
|
182
|
-
return isObject
|
|
330
|
+
return isObject(entry) ? objectNameOf(entry) : DEFAULT_FAILURE_NAME;
|
|
183
331
|
};
|
|
184
332
|
const stripProtocol = (path) => path.startsWith(FILE_PROTOCOL) ? path.slice(7) : path;
|
|
185
333
|
const stripColumn = (site) => site.replace(COLUMN_SUFFIX, "");
|
|
186
|
-
const knownSiteOf = (site) => isText
|
|
334
|
+
const knownSiteOf = (site) => isText(site) ? stripColumn(stripProtocol(site)) : void 0;
|
|
187
335
|
const siteTextOf = (site) => knownSiteOf(site) ?? UNKNOWN_SITE;
|
|
336
|
+
const siteOfFrames = (frames) => Option$1.getOrUndefined(Option$1.map(Option$1.fromUndefinedOr(frames.find(isUserFrame)), siteOfFrame));
|
|
188
337
|
/** The author's site in a raw captured stack, the form a cell span records instead of a pre-resolved site. */
|
|
189
|
-
const cellStackSiteOf = (stack) => isText
|
|
338
|
+
const cellStackSiteOf = (stack) => isText(stack) ? siteOfFrames(framesOf$1(stack)) : void 0;
|
|
190
339
|
const stackSiteTextOf = (stack) => knownSiteOf(cellStackSiteOf(stack)) ?? UNKNOWN_SITE;
|
|
191
340
|
const stackIn = (value) => textFieldOf(value, STACK_FIELD) ?? "";
|
|
192
|
-
const stackOf
|
|
193
|
-
const framesOf = (value) => framesOf$1(stackOf
|
|
341
|
+
const stackOf = (value) => isObject(value) ? stackIn(value) : "";
|
|
342
|
+
const framesOf = (value) => framesOf$1(stackOf(value));
|
|
194
343
|
const isFrame = (frame) => frame !== void 0;
|
|
195
344
|
const usableFrameOf = (value) => framesOf(value).find(isUserFrame);
|
|
196
|
-
const isUserFrame = (frame) => isUserPath(frame.path);
|
|
197
345
|
const frameTextOf = (frame) => `${frame.path}:${frame.line}${frameNameSuffix(frame.fn)}`;
|
|
198
346
|
const isAuthorName = (fn) => fn !== void 0 && !fn.includes("~effect/");
|
|
199
347
|
const frameNameSuffix = (fn) => isAuthorName(fn) ? ` (${fn})` : "";
|
|
@@ -206,31 +354,31 @@ const chosenFrameOf = (layers) => {
|
|
|
206
354
|
const attrOf = (span, key) => span.attributes.get(key);
|
|
207
355
|
const textAttrOf = (span, key) => {
|
|
208
356
|
const value = attrOf(span, key);
|
|
209
|
-
return isText
|
|
357
|
+
return isText(value) ? value : void 0;
|
|
210
358
|
};
|
|
211
359
|
const ancestorsIn = (span) => span instanceof Tracer.NativeSpan ? [span, ...ancestorsOf(span.parent)] : [];
|
|
212
|
-
const ancestorsOf = (parent) => Option.isNone(parent) ? [] : ancestorsIn(parent.value);
|
|
360
|
+
const ancestorsOf = (parent) => Option$1.isNone(parent) ? [] : ancestorsIn(parent.value);
|
|
213
361
|
const stepAncestorOf = (span) => ancestorsOf(span.parent).find((ancestor) => ancestor.name === STEP_SPAN);
|
|
214
362
|
const stateOf = (span) => Match.value(span.status).pipe(Match.when({ _tag: "Started" }, () => "unfinished"), Match.when({ _tag: "Ended" }, (ended) => endedStateOf(ended.exit)), Match.exhaustive);
|
|
215
363
|
const endedStateOf = (exit) => Exit.isSuccess(exit) ? "passed" : "failed";
|
|
216
364
|
const stepSpansOf = (spans) => spans.filter(isTopStepSpan);
|
|
217
365
|
const isTopStepSpan = (span) => and(span.name === STEP_SPAN, stepAncestorOf(span) === void 0);
|
|
218
|
-
const isCellSpan = (span) => isText
|
|
366
|
+
const isCellSpan = (span) => isText(attrOf(span, CELL_STACKTRACE));
|
|
219
367
|
const cellSpansOf = (spans) => spans.filter(isCellSpan);
|
|
220
368
|
const cellNameOf = (cell) => textAttrOf(cell, CELL_NAME) ?? cell.name;
|
|
221
|
-
const causeFieldOf = (value) => isObject
|
|
369
|
+
const causeFieldOf = (value) => isObject(value) ? objectOrUndefined(fieldOf(value, CAUSE_FIELD)) : void 0;
|
|
222
370
|
/** One layer with whatever its own `cause` adds, depth-limited. */
|
|
223
371
|
const layerWithCauseOf = (value, depth) => [value, ...nestedCauseOf(value, depth - 1)];
|
|
224
372
|
/** The layers the reasons of an Effect `Cause` add, each rendered as any other layer. */
|
|
225
|
-
const reasonLayersOf = (cause, depth) => cause.reasons.flatMap((reason) => layerWithCauseOf(reasonPayloadOf
|
|
373
|
+
const reasonLayersOf = (cause, depth) => cause.reasons.flatMap((reason) => layerWithCauseOf(reasonPayloadOf(reason), depth));
|
|
226
374
|
const layersOfCause = (cause, depth) => Cause.isCause(cause) ? reasonLayersOf(cause, depth) : layerWithCauseOf(cause, depth);
|
|
227
375
|
const nestedOf = (cause, depth) => cause === void 0 ? [] : layersOfCause(cause, depth);
|
|
228
376
|
const nestedCauseOf = (value, depth) => depth === 0 ? [] : nestedOf(causeFieldOf(value), depth);
|
|
229
|
-
const causeChainOf
|
|
377
|
+
const causeChainOf = (value) => [value, ...nestedCauseOf(value, CAUSE_DEPTH)];
|
|
230
378
|
const interruptTextOf = (reason) => reason.fiberId === void 0 ? "interrupted" : `interrupted by fiber #${reason.fiberId}`;
|
|
231
|
-
const reasonPayloadOf
|
|
232
|
-
const reasonsOf = (cause) => cause.reasons.flatMap((reason) => causeChainOf
|
|
233
|
-
const layersOf = (failure) => Cause.isCause(failure) ? reasonsOf(failure) : causeChainOf
|
|
379
|
+
const reasonPayloadOf = (reason) => Match.value(reason).pipe(Match.when({ _tag: "Fail" }, (fail) => fail.error), Match.when({ _tag: "Die" }, (die) => die.defect), Match.when({ _tag: "Interrupt" }, (interrupt) => interruptTextOf(interrupt)), Match.exhaustive);
|
|
380
|
+
const reasonsOf = (cause) => cause.reasons.flatMap((reason) => causeChainOf(reasonPayloadOf(reason)));
|
|
381
|
+
const layersOf = (failure) => Cause.isCause(failure) ? reasonsOf(failure) : causeChainOf(failure);
|
|
234
382
|
const declineOf = (span) => stateOf(span) === "unfinished" ? NEVER_FINISHED : "";
|
|
235
383
|
const capitalize = (text) => text.length === 0 ? text : `${text.slice(0, 1).toUpperCase()}${text.slice(1)}`;
|
|
236
384
|
const keywordOf = (step) => capitalize(textAttrOf(step, STEP_KEYWORD) ?? "");
|
|
@@ -310,19 +458,16 @@ const chainContinuation = (line) => ` ${line}`;
|
|
|
310
458
|
const isMessageBearing = (layer) => or(tagFieldOf(layer) !== void 0, isErrorValue(layer));
|
|
311
459
|
const messageOf = (layer) => messageFieldOf(layer) ?? "";
|
|
312
460
|
const messageTailLines = (layer) => isMessageBearing(layer) ? restLines(messageOf(layer)).map(chainContinuation) : [];
|
|
313
|
-
const chainDetailLines = (layer) => isObject
|
|
461
|
+
const chainDetailLines = (layer) => isObject(layer) ? messageTailLines(layer) : [];
|
|
314
462
|
const chainLayerLines = (layer, chosen) => [chainLineOf(layer, chosen), ...chainDetailLines(layer)];
|
|
315
463
|
const chainLinesOf = (layers, chosen) => layers.slice(1).flatMap((layer) => chainLayerLines(layer, chosen));
|
|
316
464
|
const quoted = (text) => `"${text.replaceAll("\\", "\\\\").replaceAll("\"", "\\\"")}"`;
|
|
317
|
-
const
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
const renderEntryRecord = (value) => `{${Object.entries(value).map(([key, entry]) => `${key}: ${renderEntry(entry)}`).join(";")}}`;
|
|
322
|
-
const renderEntry = (value) => isText$2(value) ? quoted(value) : renderEntryNonNull(value);
|
|
323
|
-
const replayTextOf = (replay) => replay.seed === void 0 ? void 0 : `seed=${replay.seed};path=${replay.path.map(renderEntry).join(",")}`;
|
|
465
|
+
const rerunReplayTextOf = (replay) => Option$1.getOrUndefined(Option$1.flatMap(Option$1.fromUndefinedOr(replay.seed), (seed) => Option$1.map(replayOfParts({
|
|
466
|
+
seed,
|
|
467
|
+
path: replay.path
|
|
468
|
+
}), replayTextOf)));
|
|
324
469
|
const replayPrefixText = (text) => text === void 0 ? "" : `CONFORMANCE_REPLAY="${text}" `;
|
|
325
|
-
const replayPrefixOf = (replay) => replayPrefixText(replay === void 0 ? void 0 :
|
|
470
|
+
const replayPrefixOf = (replay) => replayPrefixText(replay === void 0 ? void 0 : rerunReplayTextOf(replay));
|
|
326
471
|
const isCompleteIdentity = (identity) => and(identity.file.length > 0, identity.name.length > 0);
|
|
327
472
|
const filterPrefixOf = (identity) => identity.package.length === 0 ? "" : `pnpm --filter ${identity.package} exec `;
|
|
328
473
|
const rerunLineOf = (identity, replay) => isCompleteIdentity(identity) ? ` ${replayPrefixOf(replay)}${filterPrefixOf(identity)}vitest run ${identity.file} -t ` + quoted(identity.name) : void 0;
|
|
@@ -334,7 +479,7 @@ const baselineReplay = (replay) => and(replay.seed === void 0, replay.path.lengt
|
|
|
334
479
|
const replayOnBaseline = (replay) => replay === void 0 ? false : baselineReplay(replay);
|
|
335
480
|
const headMessageOf = (layers) => {
|
|
336
481
|
const entry = layers[0];
|
|
337
|
-
return isObject
|
|
482
|
+
return isObject(entry) ? messageFieldOf(entry) : void 0;
|
|
338
483
|
};
|
|
339
484
|
const detailOf = (layers) => {
|
|
340
485
|
const message = headMessageOf(layers);
|
|
@@ -380,7 +525,7 @@ const breachIf = (holds, breach) => holds ? [breach] : [];
|
|
|
380
525
|
const r6Broken = (parts, input) => or(parts.rerun.length === 0, replayOnBaseline(input.replay));
|
|
381
526
|
const breachesOf = (parts, input, record) => [
|
|
382
527
|
...breachIf(parts.headline.length === 0, "R1"),
|
|
383
|
-
...breachIf(not(LOCATION
|
|
528
|
+
...breachIf(not(LOCATION.test(record)), "R2"),
|
|
384
529
|
...breachIf(r6Broken(parts, input), "R6")
|
|
385
530
|
];
|
|
386
531
|
const hasRoot = (root) => root !== void 0 && root.length > 0;
|
|
@@ -405,24 +550,7 @@ const renderFailureRecord = (input) => {
|
|
|
405
550
|
breaches: breachesOf(parts, input, record)
|
|
406
551
|
};
|
|
407
552
|
};
|
|
408
|
-
//#endregion
|
|
409
|
-
//#region src/internal/failure-error.ts
|
|
410
|
-
/**
|
|
411
|
-
* The Error Vitest prints for one record (R2, R7, R8): its `name` is the record's failure tag, its `message` is the
|
|
412
|
-
* record, and its `stack` leads with that message — Vitest's JSON reporter hands a consumer `stack || message`, so
|
|
413
|
-
* the record has to ride there too — followed by the record's first location, so no `effect` or library frame stays.
|
|
414
|
-
* The tag is left out of the message because Vitest prints `name: message`: the tag would otherwise lead twice.
|
|
415
|
-
*
|
|
416
|
-
* A failure that carries a diff — Chai's `actual`, `expected`, `showDiff`, `operator` and Vitest's `diff` — has
|
|
417
|
-
* those fields copied from the innermost layer that holds them, because Vitest renders its Expected/Received block
|
|
418
|
-
* from the thrown error, not from the record text.
|
|
419
|
-
*
|
|
420
|
-
* @since 4.0.0
|
|
421
|
-
*/
|
|
422
|
-
const LOCATION = /(?:[\w.@-]+\/)*[\w.@-]+\.[cm]?[jt]sx?:\d+/u;
|
|
423
|
-
/** The mark a rendered record's Error carries, so a throw site that receives one passes it through unchanged. */
|
|
424
553
|
const RECORD = Symbol.for("@systemfsoftware/vitest/FailureRecord");
|
|
425
|
-
/** The fields Vitest reads to render its diff; each is copied only when the layer actually holds one. */
|
|
426
554
|
const DIFF_FIELDS = [
|
|
427
555
|
"actual",
|
|
428
556
|
"expected",
|
|
@@ -430,52 +558,44 @@ const DIFF_FIELDS = [
|
|
|
430
558
|
"operator",
|
|
431
559
|
"diff"
|
|
432
560
|
];
|
|
433
|
-
const
|
|
434
|
-
const isObject = (value) => typeof value === "object" && value !== null;
|
|
435
|
-
const objectOrUndefined = (value) => isObject(value) ? value : void 0;
|
|
436
|
-
const fieldOf = (value, key) => Reflect.get(value, key);
|
|
561
|
+
const ERROR_CAUSE_DEPTH = 8;
|
|
437
562
|
const isDiffLayer = (value) => fieldOf(value, "actual") !== void 0;
|
|
438
563
|
const marked = (error) => {
|
|
439
564
|
Object.defineProperty(error, RECORD, { value: true });
|
|
440
565
|
return error;
|
|
441
566
|
};
|
|
442
|
-
const
|
|
567
|
+
const recordSiteOf = (text) => LOCATION.exec(text)?.[0];
|
|
443
568
|
const withoutTag = (record) => {
|
|
444
569
|
const prefix = `${record.name}: `;
|
|
445
570
|
return record.record.startsWith(prefix) ? record.record.slice(prefix.length) : record.record;
|
|
446
571
|
};
|
|
447
|
-
const
|
|
572
|
+
const recordStackOf = (record, message) => {
|
|
448
573
|
const head = `${record.name}: ${message}`;
|
|
449
|
-
const site =
|
|
574
|
+
const site = recordSiteOf(record.record);
|
|
450
575
|
return site === void 0 ? head : `${head}\n at ${site}`;
|
|
451
576
|
};
|
|
452
577
|
const withStack = (error, record, message) => {
|
|
453
|
-
error.stack =
|
|
578
|
+
error.stack = recordStackOf(record, message);
|
|
454
579
|
return error;
|
|
455
580
|
};
|
|
456
581
|
const withName = (error, name) => {
|
|
457
582
|
error.name = name;
|
|
458
583
|
return error;
|
|
459
584
|
};
|
|
460
|
-
const
|
|
585
|
+
const reasonFieldOf = (reason) => fieldOf(reason, "error") ?? fieldOf(reason, "defect");
|
|
461
586
|
const firstReasonOf = (cause) => {
|
|
462
587
|
const reason = cause.reasons[0];
|
|
463
|
-
|
|
464
|
-
return reasonPayloadOf(reason);
|
|
588
|
+
return reason === void 0 ? cause : reasonFieldOf(reason);
|
|
465
589
|
};
|
|
466
590
|
const payloadOf = (failure) => Cause.isCause(failure) ? firstReasonOf(failure) : failure;
|
|
467
|
-
const
|
|
591
|
+
const errorCauseChainOf = (value, depth) => depth <= 0 ? [] : [value, ...chainedCausesOf(value, depth)];
|
|
468
592
|
const chainedCausesOf = (value, depth) => {
|
|
469
|
-
const cause =
|
|
470
|
-
return cause === void 0 ? [] :
|
|
471
|
-
};
|
|
472
|
-
const causeChainOf = (value, depth) => {
|
|
473
|
-
if (depth <= 0) return [];
|
|
474
|
-
return [value, ...chainedCausesOf(value, depth)];
|
|
593
|
+
const cause = causeFieldOf(value);
|
|
594
|
+
return cause === void 0 ? [] : errorCauseChainOf(cause, depth - 1);
|
|
475
595
|
};
|
|
476
596
|
const layerChainOf = (failure) => {
|
|
477
597
|
const first = payloadOf(failure);
|
|
478
|
-
return [first, ...chainedCausesOf(first,
|
|
598
|
+
return [first, ...chainedCausesOf(first, ERROR_CAUSE_DEPTH)];
|
|
479
599
|
};
|
|
480
600
|
const diffCarrierOf = (failure) => layerChainOf(failure).map(objectOrUndefined).filter(isObject).find(isDiffLayer);
|
|
481
601
|
const copyField = (error, carrier, field) => {
|
|
@@ -496,7 +616,18 @@ const copyDiffFields = (error, failure) => {
|
|
|
496
616
|
const carrier = diffCarrierOf(failure);
|
|
497
617
|
return carrier === void 0 ? error : copyFields(error, carrier);
|
|
498
618
|
};
|
|
499
|
-
/**
|
|
619
|
+
/**
|
|
620
|
+
* The `Error` Vitest prints for one record (R2, R7, R8): its `name` is the record's failure tag, its `message` is
|
|
621
|
+
* the record, and its `stack` leads with that message — Vitest's JSON reporter hands a consumer `stack || message`,
|
|
622
|
+
* so the record has to ride there too — followed by the record's first location, so no `effect` or library frame
|
|
623
|
+
* stays. The tag is left out of the message because Vitest prints `name: message`: it would otherwise lead twice.
|
|
624
|
+
*
|
|
625
|
+
* A failure that carries a diff — Chai's `actual`, `expected`, `showDiff`, `operator` and Vitest's `diff` — has
|
|
626
|
+
* those fields copied from the innermost layer that holds them, because Vitest renders its Expected/Received
|
|
627
|
+
* block from the thrown error, not from the record text.
|
|
628
|
+
*
|
|
629
|
+
* @internal
|
|
630
|
+
*/
|
|
500
631
|
const failureRecordError = (record) => {
|
|
501
632
|
const message = withoutTag(record);
|
|
502
633
|
return marked(withStack(withName(new Error(message), record.name), record, message));
|
|
@@ -504,9 +635,9 @@ const failureRecordError = (record) => {
|
|
|
504
635
|
const isRefusalFailure = (value) => Schema$1.is(FailureRecordRefused)(value);
|
|
505
636
|
/**
|
|
506
637
|
* The refusal thrown in a record's place (R10, KTD7): fixed prose naming each breach, the original failure as its
|
|
507
|
-
* `cause`, and the record that failure would have printed beneath it. The record rides in the stack because
|
|
508
|
-
* JSON reporter hands a consumer `stack || message`, where a cause is invisible; the prose never carries
|
|
509
|
-
* and is never read back, so a refusal cannot recurse.
|
|
638
|
+
* `cause`, and the record that failure would have printed beneath it. The record rides in the stack because
|
|
639
|
+
* Vitest's JSON reporter hands a consumer `stack || message`, where a cause is invisible; the prose never carries
|
|
640
|
+
* record text and is never read back, so a refusal cannot recurse.
|
|
510
641
|
*/
|
|
511
642
|
const refusalError = (failure, record) => {
|
|
512
643
|
const refusal = new FailureRecordRefused({
|
|
@@ -517,81 +648,26 @@ const refusalError = (failure, record) => {
|
|
|
517
648
|
return refusal;
|
|
518
649
|
};
|
|
519
650
|
const printedError = (failure, record) => record.breaches.length > 0 ? refusalError(failure, record) : failureRecordError(record);
|
|
520
|
-
/**
|
|
521
|
-
*
|
|
522
|
-
* @internal
|
|
523
|
-
*/
|
|
651
|
+
/** @internal */
|
|
524
652
|
const isFailureRecordError = (value) => isObject(value) && fieldOf(value, RECORD) === true;
|
|
525
|
-
/**
|
|
526
|
-
* Renders the record and throws what Vitest prints for it: the record itself when it holds its contract, a
|
|
527
|
-
* `FailureRecordRefused` when it breaks one, and a refusal passed in unchanged, so refusing cannot recurse (R10).
|
|
528
|
-
*
|
|
529
|
-
* @internal
|
|
530
|
-
*/
|
|
653
|
+
/** @internal */
|
|
531
654
|
const throwFailureRecord = (input) => {
|
|
532
655
|
if (isRefusalFailure(input.failure)) throw input.failure;
|
|
533
656
|
const record = renderFailureRecord(input);
|
|
534
657
|
throw copyDiffFields(printedError(input.failure, record), input.failure);
|
|
535
658
|
};
|
|
536
|
-
//#endregion
|
|
537
|
-
//#region src/internal/provided.ts
|
|
538
|
-
/**
|
|
539
|
-
* The values the shared vitest config provides for the fork: the package under test's npm name and the workspace
|
|
540
|
-
* root every rendered path is relativized against. Both are read out of the run's provided context (Vitest's
|
|
541
|
-
* `inject`), so no production source reads a Node built-in, and an absent value is simply `undefined` — a rerun
|
|
542
|
-
* line then drops its package filter, and paths print absolute (R6, KTD5).
|
|
543
|
-
*
|
|
544
|
-
* @since 4.0.0
|
|
545
|
-
*/
|
|
546
|
-
/** @internal */
|
|
547
|
-
const packageKey = "@systemfsoftware/vitest:package";
|
|
548
|
-
/** @internal */
|
|
549
|
-
const workspaceRootKey = "@systemfsoftware/vitest:workspace-root";
|
|
550
|
-
const isText$1 = (value) => typeof value === "string";
|
|
551
|
-
const nonEmpty = (value) => value.length === 0 ? void 0 : value;
|
|
552
|
-
const nonEmptyText = (value) => isText$1(value) ? nonEmpty(value) : void 0;
|
|
553
|
-
const read = (key) => {
|
|
554
|
-
try {
|
|
555
|
-
return nonEmptyText(inject(key));
|
|
556
|
-
} catch {
|
|
557
|
-
return;
|
|
558
|
-
}
|
|
559
|
-
};
|
|
560
|
-
/** @internal */
|
|
561
|
-
const providedPackage = () => read(packageKey);
|
|
562
|
-
/** @internal */
|
|
563
|
-
const providedRoot = () => read(workspaceRootKey);
|
|
564
|
-
//#endregion
|
|
565
|
-
//#region src/internal/failure-identity.ts
|
|
566
|
-
/**
|
|
567
|
-
* The identity one record names: the package, the test file and the scenario the rerun command writes (KTD1, R6).
|
|
568
|
-
*
|
|
569
|
-
* The task comes from Vitest, `TestRunner.getCurrentTest()`, which Vitest maintains for the test being run, so it
|
|
570
|
-
* is readable wherever a failure is rendered — including from the promise a kernel run returns, where no Effect
|
|
571
|
-
* service is in reach. The package name comes from the shared config's provided context, so it is this package's
|
|
572
|
-
* real npm name and never a guess from a directory; a run that provided none renders a rerun line without a
|
|
573
|
-
* `pnpm --filter` prefix.
|
|
574
|
-
*
|
|
575
|
-
* @since 4.0.0
|
|
576
|
-
*/
|
|
577
659
|
const LEVEL_SEPARATOR = " > ";
|
|
578
|
-
const
|
|
579
|
-
const
|
|
580
|
-
const
|
|
581
|
-
const
|
|
582
|
-
const fileOf = (fullName) => textOrEmpty(fullName).split(LEVEL_SEPARATOR).at(0) ?? EMPTY;
|
|
660
|
+
const EMPTY_TEXT = "";
|
|
661
|
+
const textOrEmpty = (value) => isText(value) ? value : EMPTY_TEXT;
|
|
662
|
+
const firstNonEmptyText = (values) => textOrEmpty(values.find(isText));
|
|
663
|
+
const fileOf = (fullName) => textOrEmpty(fullName).split(LEVEL_SEPARATOR).at(0) ?? EMPTY_TEXT;
|
|
583
664
|
const identityOf = (task) => ({
|
|
584
|
-
package: providedPackage() ??
|
|
665
|
+
package: providedPackage() ?? EMPTY_TEXT,
|
|
585
666
|
file: fileOf(task.fullName),
|
|
586
|
-
name:
|
|
667
|
+
name: firstNonEmptyText([task.fullTestName, task.name])
|
|
587
668
|
});
|
|
588
669
|
const currentTask = () => TestRunner.getCurrentTest() ?? {};
|
|
589
|
-
/**
|
|
590
|
-
* The identity of the test being run, or of the task handed in. A run outside a test, or one whose task carries
|
|
591
|
-
* no file, yields an incomplete identity, which the renderer reports as the R6 breach it is.
|
|
592
|
-
*
|
|
593
|
-
* @internal
|
|
594
|
-
*/
|
|
670
|
+
/** @internal */
|
|
595
671
|
const testIdentityOf = (task) => identityOf(task ?? currentTask());
|
|
596
672
|
//#endregion
|
|
597
673
|
//#region src/internal/property/coverage.ts
|
|
@@ -902,15 +978,15 @@ const ReplayToken = Schema$1.fromJsonString(Schema$1.Tuple([
|
|
|
902
978
|
/** The token's leading kind that names a numeric seed. */
|
|
903
979
|
const NUMERIC_SEED = 0;
|
|
904
980
|
const numericSeedOf = (token) => token[0] === NUMERIC_SEED ? Number(token[1]) : void 0;
|
|
905
|
-
const replayOf = (token) => Option.map(Option.fromNullishOr(numericSeedOf(token)), (seed) => ({
|
|
981
|
+
const replayOf = (token) => Option$1.map(Option$1.fromNullishOr(numericSeedOf(token)), (seed) => ({
|
|
906
982
|
seed,
|
|
907
983
|
path: token[4]
|
|
908
984
|
}));
|
|
909
985
|
/** @internal */
|
|
910
|
-
const replayOfToken = (replay) => Option.getOrUndefined(Option.flatMap(Schema$1.decodeOption(ReplayToken)(replay), replayOf));
|
|
986
|
+
const replayOfToken = (replay) => Option$1.getOrUndefined(Option$1.flatMap(Schema$1.decodeOption(ReplayToken)(replay), replayOf));
|
|
911
987
|
const refutationOf = (value) => Schema$1.is(PropertyRefuted)(value) ? value : void 0;
|
|
912
988
|
/** @internal */
|
|
913
|
-
const replayOfFailure = (value) => Option.getOrUndefined(Option.flatMap(Option.fromNullishOr(refutationOf(value)), (failure) => Option.fromNullishOr(failure.replay)));
|
|
989
|
+
const replayOfFailure = (value) => Option$1.getOrUndefined(Option$1.flatMap(Option$1.fromNullishOr(refutationOf(value)), (failure) => Option$1.fromNullishOr(failure.replay)));
|
|
914
990
|
//#endregion
|
|
915
991
|
//#region src/internal/property/engine.ts
|
|
916
992
|
/**
|
|
@@ -985,7 +1061,7 @@ const observeRun = (classes, counter, entries, values) => {
|
|
|
985
1061
|
counter.runs = counter.runs + 1;
|
|
986
1062
|
for (const label of satisfiedLabels(entries, values)) countHit(classes, label);
|
|
987
1063
|
};
|
|
988
|
-
const drawFor = (entries, arbitrary) => ({ more: (count) => Effect.runSync(Arbitrary.sampleEffect(arbitrary, { count }).pipe(Effect.orDie)).map((values) => satisfiedLabels(entries, values)) });
|
|
1064
|
+
const drawFor = (entries, arbitrary) => ({ more: (count) => Effect$1.runSync(Arbitrary.sampleEffect(arbitrary, { count }).pipe(Effect$1.orDie)).map((values) => satisfiedLabels(entries, values)) });
|
|
989
1065
|
const noCoverage = () => ({
|
|
990
1066
|
observe: () => void 0,
|
|
991
1067
|
judge: () => void 0
|
|
@@ -1004,24 +1080,24 @@ const liveCoverage = (cover, arbitrary) => {
|
|
|
1004
1080
|
};
|
|
1005
1081
|
};
|
|
1006
1082
|
const makeCoverage = (cover, arbitrary) => cover === void 0 ? noCoverage() : liveCoverage(cover, arbitrary);
|
|
1007
|
-
const describeVerdict = (verdict) => Effect.isEffect(verdict) ? "an Effect, which this lane never runs" : `a ${typeof verdict}`;
|
|
1083
|
+
const describeVerdict = (verdict) => Effect$1.isEffect(verdict) ? "an Effect, which this lane never runs" : `a ${typeof verdict}`;
|
|
1008
1084
|
const nonBoolean = (verdict, violations) => {
|
|
1009
1085
|
violations.add(describeVerdict(verdict));
|
|
1010
1086
|
return true;
|
|
1011
1087
|
};
|
|
1012
1088
|
const literalVerdict = (verdict, violations) => typeof verdict === "boolean" ? verdict : nonBoolean(verdict, violations);
|
|
1013
|
-
const effectVerdict = (lane, verdict, violations) => lane === "sync" ? Effect.succeed(nonBoolean(verdict, violations)) : Effect.map(verdict, (value) => literalVerdict(value, violations));
|
|
1089
|
+
const effectVerdict = (lane, verdict, violations) => lane === "sync" ? Effect$1.succeed(nonBoolean(verdict, violations)) : Effect$1.map(verdict, (value) => literalVerdict(value, violations));
|
|
1014
1090
|
const verdictFor = (run, values, violations) => {
|
|
1015
1091
|
run.observe(values);
|
|
1016
1092
|
const verdict = run.holds(run.subject, values);
|
|
1017
|
-
return Effect.isEffect(verdict) ? effectVerdict(run.lane, verdict, violations) : Effect.succeed(literalVerdict(verdict, violations));
|
|
1093
|
+
return Effect$1.isEffect(verdict) ? effectVerdict(run.lane, verdict, violations) : Effect$1.succeed(literalVerdict(verdict, violations));
|
|
1018
1094
|
};
|
|
1019
|
-
const tolerateInterruption = (cause) => Cause.hasInterrupts(cause) ? Effect.interrupt : Effect.fail(cause);
|
|
1020
|
-
const guardedVerdict = (run, violations) => (values) => Effect.catchCause(Effect.suspend(() => verdictFor(run, values, violations)), tolerateInterruption);
|
|
1095
|
+
const tolerateInterruption = (cause) => Cause.hasInterrupts(cause) ? Effect$1.interrupt : Effect$1.fail(cause);
|
|
1096
|
+
const guardedVerdict = (run, violations) => (values) => Effect$1.catchCause(Effect$1.suspend(() => verdictFor(run, values, violations)), tolerateInterruption);
|
|
1021
1097
|
const violationMessage = (name, violations) => `${name}: the property returned no boolean; it returned ${violations.join(", ")}. A property must return a literal boolean verdict — asserting with expect(), or returning an Option, Result or object, is not a verdict; write ${REWRITE}.`;
|
|
1022
1098
|
const runCheck = (run) => {
|
|
1023
1099
|
const violations = /* @__PURE__ */ new Set();
|
|
1024
|
-
return Arbitrary.checkEffect(run.arbitrary, guardedVerdict(run, violations), run.options).pipe(Effect.map((result) => ({
|
|
1100
|
+
return Arbitrary.checkEffect(run.arbitrary, guardedVerdict(run, violations), run.options).pipe(Effect$1.map((result) => ({
|
|
1025
1101
|
violations,
|
|
1026
1102
|
result
|
|
1027
1103
|
})));
|
|
@@ -1029,7 +1105,7 @@ const runCheck = (run) => {
|
|
|
1029
1105
|
const reportOf = (checked) => Arbitrary.formatCheckFailure(checked.result);
|
|
1030
1106
|
const violationOf = (name, checked) => checked.violations.size === 0 ? void 0 : violationMessage(name, [...checked.violations]);
|
|
1031
1107
|
const isRefuted = (checked) => checked.violations.size > 0 || reportOf(checked) !== void 0;
|
|
1032
|
-
const dieWithSite = (error, site) => Effect.die(withRaisingFrame(error, site));
|
|
1108
|
+
const dieWithSite = (error, site) => Effect$1.die(withRaisingFrame(error, site));
|
|
1033
1109
|
const dieViolation = (detail, site) => dieWithSite(new NonBooleanVerdict({ detail }), site);
|
|
1034
1110
|
const dieReported = (name, report, replay, site) => {
|
|
1035
1111
|
const detail = `${name}: the property was falsified. ${report}`;
|
|
@@ -1055,16 +1131,16 @@ const impostorRun = (run, budget) => {
|
|
|
1055
1131
|
holds: impostorHolds(run.holds, impostor),
|
|
1056
1132
|
observe: noObserve
|
|
1057
1133
|
};
|
|
1058
|
-
return runCheck(retry).pipe(Effect.map((checked) => recordImpostor(retry, budget, impostor, checked)));
|
|
1134
|
+
return runCheck(retry).pipe(Effect$1.map((checked) => recordImpostor(retry, budget, impostor, checked)));
|
|
1059
1135
|
};
|
|
1060
1136
|
const noObserve = () => void 0;
|
|
1061
|
-
const gateRun = (run, budget, gate) => gate ? impostorRun(run, budget) : Effect.void;
|
|
1137
|
+
const gateRun = (run, budget, gate) => gate ? impostorRun(run, budget) : Effect$1.void;
|
|
1062
1138
|
const finishPassed = (run, budget, coverage, gate) => {
|
|
1063
1139
|
const failure = coverage.judge();
|
|
1064
1140
|
return failure === void 0 ? gateRun(run, budget, gate) : dieUncovered(`${run.name}: ${failure}`, run.site);
|
|
1065
1141
|
};
|
|
1066
1142
|
const falsifiedOf = (result) => "replay" in result ? result : void 0;
|
|
1067
|
-
const replayOfChecked = (checked) => Option.getOrUndefined(Option.flatMap(Option.fromNullishOr(falsifiedOf(checked.result)), (falsified) => Option.fromNullishOr(replayOfToken(falsified.replay))));
|
|
1143
|
+
const replayOfChecked = (checked) => Option$1.getOrUndefined(Option$1.flatMap(Option$1.fromNullishOr(falsifiedOf(checked.result)), (falsified) => Option$1.fromNullishOr(replayOfToken(falsified.replay))));
|
|
1068
1144
|
const settleReport = (run, budget, coverage, gate, report, replay) => report === void 0 ? finishPassed(run, budget, coverage, gate) : dieReported(run.name, report, replay, run.site);
|
|
1069
1145
|
const settle = (registration, run, budget, coverage, checked) => {
|
|
1070
1146
|
const violation = violationOf(registration.name, checked);
|
|
@@ -1080,7 +1156,7 @@ const checkOf = (registration, arbitrary, budget, observe) => ({
|
|
|
1080
1156
|
options: budget.options,
|
|
1081
1157
|
site: registration.site
|
|
1082
1158
|
});
|
|
1083
|
-
const program = (registration) => Effect.gen(function* () {
|
|
1159
|
+
const program = (registration) => Effect$1.gen(function* () {
|
|
1084
1160
|
const budget = resolveBudget(registration.name, registration.spec, providedCheckDefaults());
|
|
1085
1161
|
const arbitrary = arbitraryOf(registration.spec.of);
|
|
1086
1162
|
const coverage = makeCoverage(registration.spec.cover, arbitrary);
|
|
@@ -1178,11 +1254,11 @@ const renderRecord = (failure, spans, identity) => renderFailureRecord({
|
|
|
1178
1254
|
root: providedRoot()
|
|
1179
1255
|
});
|
|
1180
1256
|
const outcomeOf = (exit, recorder, identity) => Exit.isSuccess(exit) ? void 0 : renderRecord(Cause.squash(exit.cause), recorder.spans, identity);
|
|
1181
|
-
const provideRun = (effect, ledger, ctx) => effect.pipe(Effect.provideService(Asserted, ledger.asserted), Effect.provideService(VitestTestContext, ctx));
|
|
1257
|
+
const provideRun = (effect, ledger, ctx) => effect.pipe(Effect$1.provideService(Asserted, ledger.asserted), Effect$1.provideService(VitestTestContext, ctx));
|
|
1182
1258
|
const runRecorded = (ctx, program) => {
|
|
1183
1259
|
const ledger = makeLedger(ctx);
|
|
1184
1260
|
const recorder = createSpanRecorder();
|
|
1185
|
-
return Effect.runPromiseExit(provideRun(program(checksFor(ledger)), ledger, ctx).pipe(Effect.withTracer(recorder.tracer))).then((exit) => outcomeOf(exit, recorder, testIdentityOf()));
|
|
1261
|
+
return Effect$1.runPromiseExit(provideRun(program(checksFor(ledger)), ledger, ctx).pipe(Effect$1.withTracer(recorder.tracer))).then((exit) => outcomeOf(exit, recorder, testIdentityOf()));
|
|
1186
1262
|
};
|
|
1187
1263
|
/**
|
|
1188
1264
|
* Runs one program as the runner runs a lane, with a fresh ledger and its own recorder, and resolves with the
|
|
@@ -1201,7 +1277,7 @@ const capturingRuntime = (programs) => ({
|
|
|
1201
1277
|
},
|
|
1202
1278
|
provide: (effect) => effect
|
|
1203
1279
|
});
|
|
1204
|
-
const capturedProgram = (programs) => Option.getOrThrow(Option.fromNullishOr(programs[0]));
|
|
1280
|
+
const capturedProgram = (programs) => Option$1.getOrThrow(Option$1.fromNullishOr(programs[0]));
|
|
1205
1281
|
/**
|
|
1206
1282
|
* Runs one property the way the runner runs `it.prop`, with a fresh ledger and its own recorder, and resolves with
|
|
1207
1283
|
* the record its falsification rendered — or `undefined` when it held.
|
|
@@ -1214,4 +1290,4 @@ const recordOfProperty = (input) => {
|
|
|
1214
1290
|
return recordOfRun(capturedProgram(programs));
|
|
1215
1291
|
};
|
|
1216
1292
|
//#endregion
|
|
1217
|
-
export { replayOfFailure as a,
|
|
1293
|
+
export { ReplayFromText as _, replayOfFailure as a, summaryOf as c, providedRoot as d, InvalidBudget as f, Replay as g, Slop as h, makeProperty as i, testIdentityOf as l, NonBooleanVerdict as m, recordOfRun as n, isFailureRecordError as o, LeakedState as p, createSpanRecorder as r, renderFailureRecord as s, recordOfProperty as t, throwFailureRecord as u, replayOfText as v };
|