@systemfsoftware/stryker-js-vitest-runner 4.0.0 → 4.0.1
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/index.d.mts +1 -1
- package/dist/index.mjs +228 -282
- package/package.json +9 -9
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# @systemfsoftware/stryker-js-vitest-runner
|
|
2
2
|
|
|
3
|
+
## 4.0.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Re-released against @systemfsoftware/stryker-js without the removed --llms manifest. The Run stream no longer carries a manifest terminal event, and the RunEvent / RunTerminalEvent unions no longer include the manifest arm, so any exhaustive consumer of those types must drop that case.
|
|
8
|
+
|
|
9
|
+
- Rebuilds against updated workspace dependencies, including the new
|
|
10
|
+
`@systemfsoftware/stryker-js` reporter protocol major.
|
|
11
|
+
|
|
12
|
+
- Updated dependencies:
|
|
13
|
+
- @systemfsoftware/stryker-js@3.0.0
|
|
14
|
+
|
|
3
15
|
## 4.0.0
|
|
4
16
|
|
|
5
17
|
### Major Changes
|
package/dist/index.d.mts
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* in, so the requirement is visible in the type and an engine that does not
|
|
7
7
|
* provide it fails to compile.
|
|
8
8
|
*/
|
|
9
|
-
declare const strykerPlugins: import("@systemfsoftware/stryker-js/Plugin").
|
|
9
|
+
declare const strykerPlugins: import("@systemfsoftware/stryker-js/Plugin").PluginLayerContribution<"TestRunner">[];
|
|
10
10
|
/**
|
|
11
11
|
* The `vitest` option section as a JSON Schema document, for Stryker's option
|
|
12
12
|
* validation — derived from the declaration, never read from a file. It is built
|
package/dist/index.mjs
CHANGED
|
@@ -12,6 +12,7 @@ import * as FileSystem from "effect/FileSystem";
|
|
|
12
12
|
import * as Match from "effect/Match";
|
|
13
13
|
import * as Option from "effect/Option";
|
|
14
14
|
import * as Path from "effect/Path";
|
|
15
|
+
import * as Predicate from "effect/Predicate";
|
|
15
16
|
import * as Ref from "effect/Ref";
|
|
16
17
|
import * as Result from "effect/Result";
|
|
17
18
|
import { Effect } from "effect";
|
|
@@ -110,17 +111,15 @@ const toRawTestIdRaw$1 = (test) => {
|
|
|
110
111
|
onSome: (file) => Option.getOrElse(Option.fromNullishOr(getFilepath$1(file)), () => "unknown.js")
|
|
111
112
|
})}#${collectTestNameRaw$1(test)}`;
|
|
112
113
|
};
|
|
114
|
+
const stripProjectRoot = (file, projectRoot) => Match.value(file.startsWith(projectRoot)).pipe(Match.when(true, () => file.slice(projectRoot.length)), Match.when(false, () => file), Match.exhaustive);
|
|
115
|
+
const toProjectRelativePath = (file) => file.replace(/^[/\\]+/, "").replaceAll("\\", "/");
|
|
113
116
|
const normalizeTestIdRaw$1 = (id, projectRoot) => {
|
|
114
117
|
const hash = id.indexOf("#");
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
return `${(() => {
|
|
119
|
-
if (file.startsWith(projectRoot)) return file.slice(projectRoot.length);
|
|
120
|
-
return file;
|
|
121
|
-
})().replace(/^[/\\]+/, "").replaceAll("\\", "/")}#${rest}`;
|
|
118
|
+
return Match.value(hash === -1).pipe(Match.when(true, () => id), Match.when(false, () => {
|
|
119
|
+
return `${toProjectRelativePath(stripProjectRoot(id.slice(0, hash), projectRoot))}#${id.slice(hash + 1)}`;
|
|
120
|
+
}), Match.exhaustive);
|
|
122
121
|
};
|
|
123
|
-
const toTestStatus$1 = (taskState, mode) => Match.value(mode === "skip").pipe(Match.when(true, () => "skipped"), Match.when(false, () => Match.value(taskState).pipe(Match.when("pass", () => "success"), Match.when("
|
|
122
|
+
const toTestStatus$1 = (taskState, mode) => Match.value(mode === "skip").pipe(Match.when(true, () => "skipped"), Match.when(false, () => Match.value(taskState).pipe(Match.when("pass", () => "success"), Match.when("skip", () => "skipped"), Match.when("todo", () => "skipped"), Match.orElse(() => "failed"))), Match.exhaustive);
|
|
124
123
|
const findSuiteErrorRaw$1 = (suite) => Option.match(Option.fromNullishOr(suite), {
|
|
125
124
|
onNone: () => void 0,
|
|
126
125
|
onSome: (current) => Option.match(recordOption$1(current), {
|
|
@@ -194,7 +193,12 @@ const convertTestRaw$1 = (test, projectRoot) => {
|
|
|
194
193
|
status
|
|
195
194
|
})));
|
|
196
195
|
};
|
|
197
|
-
|
|
196
|
+
/**
|
|
197
|
+
* A run whose tests all passed yet reported an error outside the test files: the shape a dry
|
|
198
|
+
* run reports as `Error` rather than `Complete`.
|
|
199
|
+
*/
|
|
200
|
+
const isSilentExternalError = (tests, command) => Match.value(tests.some((test) => test.status === "failed")).pipe(Match.when(true, () => false), Match.when(false, () => command.hasExternalError), Match.exhaustive);
|
|
201
|
+
const decideVitestDryRun$1 = (command) => Match.value(command.rawTests.map((t) => convertTestRaw$1(t, command.projectRoot))).pipe(Match.when((tests) => isSilentExternalError(tests, command), (tests) => Result.succeed(VitestDryRunOutput.make({
|
|
198
202
|
status: "Error",
|
|
199
203
|
testsJson: JSON.stringify(tests),
|
|
200
204
|
errorMessage: `An error occurred outside of a test run: ${command.externalErrorText}`
|
|
@@ -203,11 +207,7 @@ const decideVitestDryRun$1 = (command) => Match.value(command.rawTests.map((t) =
|
|
|
203
207
|
testsJson: JSON.stringify(tests),
|
|
204
208
|
errorMessage: void 0
|
|
205
209
|
}))));
|
|
206
|
-
const hitLimitReason = (hitCount, hitLimit) => {
|
|
207
|
-
if (hitCount === void 0 || hitLimit === void 0) return Option.none();
|
|
208
|
-
if (hitCount > hitLimit) return Option.some(`Hit limit reached (${hitCount}/${hitLimit})`);
|
|
209
|
-
return Option.none();
|
|
210
|
-
};
|
|
210
|
+
const hitLimitReason = (hitCount, hitLimit) => Option.flatMap(Option.fromNullishOr(hitCount), (count) => Option.flatMap(Option.fromNullishOr(hitLimit), (limit) => Match.value(count > limit).pipe(Match.when(true, () => Option.some(`Hit limit reached (${count}/${limit})`)), Match.when(false, () => Option.none()), Match.exhaustive)));
|
|
211
211
|
const decideVitestMutantRun = (command) => Match.value(hitLimitReason(command.hitCount, command.hitLimit)).pipe(Match.when(Option.isSome, (hit) => Result.succeed(MutantTimeout.make({
|
|
212
212
|
testsJson: "[]",
|
|
213
213
|
reason: hit.value
|
|
@@ -290,7 +290,7 @@ const PackageManifest = S.StructWithRest(S.Struct({
|
|
|
290
290
|
name: S.optional(S.String),
|
|
291
291
|
exports: S.optional(S.Record(S.String, ExportEntry))
|
|
292
292
|
}), [S.Record(S.String, S.Unknown)]);
|
|
293
|
-
const VitestNodeModuleSchema = S.declare((input) =>
|
|
293
|
+
const VitestNodeModuleSchema = S.declare((input) => Predicate.isObject(input), { description: "The project-local vitest/node module" });
|
|
294
294
|
const VitestPackageSchema = S.Struct({ version: S.String });
|
|
295
295
|
var VitestDryRunCommand = class extends S.TaggedClass()("VitestDryRunCommand", {
|
|
296
296
|
rawTests: S.Array(S.Unknown),
|
|
@@ -330,8 +330,7 @@ function collectTestsFromSuite(suite) {
|
|
|
330
330
|
});
|
|
331
331
|
}
|
|
332
332
|
function isErrorCodeError(error) {
|
|
333
|
-
|
|
334
|
-
return false;
|
|
333
|
+
return error instanceof Error && typeof Reflect.get(error, "code") === "string";
|
|
335
334
|
}
|
|
336
335
|
const VITEST_ERROR_CODES = Object.freeze({ FILES_NOT_FOUND: "VITEST_FILES_NOT_FOUND" });
|
|
337
336
|
const recordOption = (value) => S.decodeUnknownOption(S.Record(S.String, S.Unknown))(value);
|
|
@@ -392,7 +391,7 @@ const normalizeTestIdRaw = (id, projectRoot) => {
|
|
|
392
391
|
return file;
|
|
393
392
|
})().replace(/^[/\\]+/, "").replaceAll("\\", "/")}#${rest}`;
|
|
394
393
|
};
|
|
395
|
-
const toTestStatus = (taskState, mode) => Match.value(mode === "skip").pipe(Match.when(true, () => "skipped"), Match.when(false, () => Match.value(taskState).pipe(Match.when("pass", () => "success"), Match.when("
|
|
394
|
+
const toTestStatus = (taskState, mode) => Match.value(mode === "skip").pipe(Match.when(true, () => "skipped"), Match.when(false, () => Match.value(taskState).pipe(Match.when("pass", () => "success"), Match.when("skip", () => "skipped"), Match.when("todo", () => "skipped"), Match.orElse(() => "failed"))), Match.exhaustive);
|
|
396
395
|
const findSuiteErrorRaw = (suite) => Option.match(Option.fromNullishOr(suite), {
|
|
397
396
|
onNone: () => void 0,
|
|
398
397
|
onSome: (current) => Option.match(recordOption(current), {
|
|
@@ -468,55 +467,48 @@ const convertTestRaw = (test, projectRoot) => {
|
|
|
468
467
|
};
|
|
469
468
|
const decideVitestDryRun = (command) => {
|
|
470
469
|
const tests = command.rawTests.map((t) => convertTestRaw(t, command.projectRoot));
|
|
471
|
-
|
|
472
|
-
|
|
470
|
+
const testsJson = JSON.stringify(tests);
|
|
471
|
+
const hasFailure = tests.some((t) => t.status === "failed");
|
|
472
|
+
return Match.value(hasFailure).pipe(Match.when(true, () => DryRunComplete.make({ testsJson })), Match.orElse(() => Match.value(command.hasExternalError).pipe(Match.when(true, () => DryRunExternalError.make({
|
|
473
|
+
testsJson,
|
|
473
474
|
errorMessage: `An error occurred outside of a test run: ${command.externalErrorText}`
|
|
474
|
-
});
|
|
475
|
-
return DryRunComplete.make({ testsJson: JSON.stringify(tests) });
|
|
475
|
+
})), Match.orElse(() => DryRunComplete.make({ testsJson })))));
|
|
476
476
|
};
|
|
477
477
|
const SOURCE_CONDITION = "@systemfsoftware/source";
|
|
478
|
-
const
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
};
|
|
487
|
-
const specifierForExport = (packageName, exportKey) =>
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
};
|
|
492
|
-
const
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
478
|
+
const TYPESCRIPT_SOURCE_EXTENSIONS = [
|
|
479
|
+
".ts",
|
|
480
|
+
".tsx",
|
|
481
|
+
".mts"
|
|
482
|
+
];
|
|
483
|
+
const isTypescriptSourcePath = (filePath) => TYPESCRIPT_SOURCE_EXTENSIONS.some((extension) => filePath.endsWith(extension));
|
|
484
|
+
const typescriptSourcePath = (filePath) => Option.getOrUndefined(Option.filter(Option.some(filePath), isTypescriptSourcePath));
|
|
485
|
+
const sourceTargetOf = (entry) => Match.value(entry).pipe(Match.when(Match.string, (filePath) => typescriptSourcePath(filePath)), Match.orElse((conditions) => Option.getOrUndefined(Option.flatMap(recordOption(conditions), (record) => getStringField(record, SOURCE_CONDITION)))));
|
|
486
|
+
const subpathSpecifier = (packageName, exportKey) => Match.value(exportKey.startsWith("./")).pipe(Match.when(true, () => `${packageName}/${exportKey.slice(2)}`), Match.orElse(() => void 0));
|
|
487
|
+
const specifierForExport = (packageName, exportKey) => Match.value(exportKey).pipe(Match.when(".", () => packageName), Match.when("./package.json", () => void 0), Match.orElse((key) => subpathSpecifier(packageName, key)));
|
|
488
|
+
const namedExports = (manifest) => Option.flatMap(Option.filter(Option.fromNullishOr(manifest.name), (name) => name.length > 0), (name) => Option.map(Option.fromNullishOr(manifest.exports), (exportMap) => ({
|
|
489
|
+
name,
|
|
490
|
+
exports: exportMap
|
|
491
|
+
})));
|
|
492
|
+
const exportAlias = (packageName, projectRoot, pathService, [exportKey, entry]) => Option.flatMap(Option.fromNullishOr(specifierForExport(packageName, exportKey)), (spec) => Option.map(Option.fromNullishOr(sourceTargetOf(entry)), (target) => ({
|
|
493
|
+
find: new RegExp(`^${RegExp.escape(spec)}$`),
|
|
494
|
+
replacement: pathService.resolve(projectRoot, target)
|
|
495
|
+
})));
|
|
496
|
+
const sandboxSelfAliases = (manifest, projectRoot, pathService) => Option.match(namedExports(manifest), {
|
|
497
|
+
onNone: () => [],
|
|
498
|
+
onSome: ({ name, exports: exportMap }) => Object.entries(exportMap).flatMap((entry) => Option.toArray(exportAlias(name, projectRoot, pathService, entry)))
|
|
499
|
+
});
|
|
500
|
+
const parseJson = (text) => {
|
|
501
|
+
try {
|
|
502
|
+
return JSON.parse(text);
|
|
503
|
+
} catch {
|
|
504
|
+
return;
|
|
505
505
|
}
|
|
506
|
-
return aliases;
|
|
507
506
|
};
|
|
508
507
|
const readSandboxSelfAliases = (projectRoot) => Effect$1.gen(function* () {
|
|
509
508
|
const fs = yield* FileSystem.FileSystem;
|
|
510
509
|
const pathService = yield* Path.Path;
|
|
511
510
|
const raw = yield* fs.readFileString(pathService.join(projectRoot, "package.json")).pipe(Effect$1.orElseSucceed(() => null));
|
|
512
|
-
|
|
513
|
-
let parsed;
|
|
514
|
-
try {
|
|
515
|
-
parsed = JSON.parse(raw);
|
|
516
|
-
} catch {
|
|
517
|
-
return [];
|
|
518
|
-
}
|
|
519
|
-
return Option.match(S.decodeUnknownOption(PackageManifest)(parsed), {
|
|
511
|
+
return Option.match(Option.flatMap(Option.fromNullishOr(raw), (content) => S.decodeUnknownOption(PackageManifest)(parseJson(content))), {
|
|
520
512
|
onNone: () => [],
|
|
521
513
|
onSome: (manifest) => sandboxSelfAliases(manifest, projectRoot, pathService)
|
|
522
514
|
});
|
|
@@ -525,10 +517,10 @@ const sandboxSelfPlugin = (aliases) => ({
|
|
|
525
517
|
name: "stryker-sandbox-self-exports",
|
|
526
518
|
enforce: "pre",
|
|
527
519
|
resolveId(source) {
|
|
528
|
-
|
|
520
|
+
return Option.getOrUndefined(Option.map(Option.fromNullishOr(aliases.find((alias) => alias.find.test(source))), (alias) => alias.replacement));
|
|
529
521
|
}
|
|
530
522
|
});
|
|
531
|
-
const isRunnerTestSuite = (value) =>
|
|
523
|
+
const isRunnerTestSuite = (value) => Predicate.isObject(value) && Array.isArray(value["tasks"]);
|
|
532
524
|
const STRYKER_SETUP_URL = new URL("./stryker-setup.mjs", import.meta.url);
|
|
533
525
|
const resolveVitest = (_dir) => Effect$1.gen(function* () {
|
|
534
526
|
const fallback = Effect$1.gen(function* () {
|
|
@@ -561,72 +553,81 @@ const resolveVitest = (_dir) => Effect$1.gen(function* () {
|
|
|
561
553
|
};
|
|
562
554
|
}).pipe(Effect$1.catchCause(() => fallback), Effect$1.catchDefect(() => fallback));
|
|
563
555
|
}).pipe(Effect$1.orDie);
|
|
556
|
+
const versionPart = (parts, index) => Option.getOrElse(Option.map(Option.fromNullishOr(parts[index]), (part) => Number(part)), () => 0);
|
|
557
|
+
const minimumMinorForMajor = (major) => Match.value(major).pipe(Match.when((value) => value > 4, () => Option.some(0)), Match.when(4, () => Option.some(1)), Match.orElse(() => Option.none()));
|
|
564
558
|
const shouldUseSuiteMetaSecondArg = (version) => {
|
|
565
559
|
const parts = version.split(".");
|
|
566
|
-
const major =
|
|
567
|
-
const minor =
|
|
568
|
-
|
|
569
|
-
return major > 4 || major === 4 && minor >= 1;
|
|
560
|
+
const major = versionPart(parts, 0);
|
|
561
|
+
const minor = versionPart(parts, 1);
|
|
562
|
+
return Match.value(Number.isNaN(major) || Number.isNaN(minor)).pipe(Match.when(true, () => false), Match.orElse(() => Option.exists(minimumMinorForMajor(major), (minimumMinor) => minor >= minimumMinor)));
|
|
570
563
|
};
|
|
571
|
-
const
|
|
572
|
-
const
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
};
|
|
585
|
-
const experimentalStateHasExternalErrors = (vitest) => {
|
|
586
|
-
if (typeof vitest === "object" && vitest !== null && "state" in vitest) {
|
|
587
|
-
const state = Reflect.get(vitest, "state");
|
|
588
|
-
if (typeof state === "object" && state !== null && "errorsSet" in state) {
|
|
589
|
-
const errorsSet = Reflect.get(state, "errorsSet");
|
|
590
|
-
if (errorsSet instanceof Set) return errorsSet.size > 0;
|
|
591
|
-
if (typeof errorsSet === "object" && errorsSet !== null && "size" in errorsSet) {
|
|
592
|
-
const size = Reflect.get(errorsSet, "size");
|
|
593
|
-
return (() => {
|
|
594
|
-
if (typeof size === "number") return size > 0;
|
|
595
|
-
return false;
|
|
596
|
-
})();
|
|
597
|
-
}
|
|
598
|
-
}
|
|
599
|
-
}
|
|
600
|
-
return false;
|
|
564
|
+
const relatedFilesOf = (relatedValue, relatedFiles) => Match.value(relatedValue !== false).pipe(Match.when(true, () => Option.getOrUndefined(Option.map(Option.fromNullishOr(relatedFiles), (files) => files.map(normalizeFileName)))), Match.orElse(() => void 0));
|
|
565
|
+
const testIdPlan = (testIds, projectRoot, pathService) => Option.map(Option.filter(Option.fromNullishOr(testIds), (ids) => ids.length > 0), (ids) => ({
|
|
566
|
+
testNamePattern: new RegExp(ids.map((id) => RegExp.escape(fromTestId(id).test)).join("|")),
|
|
567
|
+
testFiles: ids.map((id) => pathService.resolve(projectRoot, fromTestId(id).file))
|
|
568
|
+
}));
|
|
569
|
+
const runFilterPlan = (filter, projectRoot, pathService) => {
|
|
570
|
+
const plan = testIdPlan(filter.testIds, projectRoot, pathService);
|
|
571
|
+
return {
|
|
572
|
+
testNamePattern: Option.getOrUndefined(Option.map(plan, (value) => value.testNamePattern)),
|
|
573
|
+
testFiles: Option.match(plan, {
|
|
574
|
+
onNone: () => Option.getOrUndefined(Option.map(Option.fromNullishOr(filter.testFiles), (files) => [...files])),
|
|
575
|
+
onSome: (value) => value.testFiles
|
|
576
|
+
})
|
|
577
|
+
};
|
|
601
578
|
};
|
|
602
|
-
const
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
579
|
+
const isMissingTestFilesCause = (cause) => Match.value(isErrorCodeError(cause)).pipe(Match.when(true, () => typeof cause === "string" && cause.includes(VITEST_ERROR_CODES.FILES_NOT_FOUND)), Match.orElse(() => false));
|
|
580
|
+
const experimentalStateGetFiles = (vitest) => vitest.state.getFiles();
|
|
581
|
+
const propertyOf = (value, key) => Option.flatMap(Option.filter(Option.fromNullishOr(value), Predicate.isObject), (record) => Option.fromNullishOr(record[key]));
|
|
582
|
+
const vitestStateOf = (vitest) => propertyOf(vitest, "state");
|
|
583
|
+
const errorsSetOf = (vitest) => Option.flatMap(vitestStateOf(vitest), (state) => propertyOf(state, "errorsSet"));
|
|
584
|
+
const invokeMethod = (holder, name) => Option.match(Option.filter(propertyOf(holder, name), Predicate.isFunction), {
|
|
585
|
+
onNone: () => void 0,
|
|
586
|
+
onSome: (method) => {
|
|
587
|
+
Reflect.apply(method, holder, []);
|
|
611
588
|
}
|
|
612
|
-
|
|
613
|
-
|
|
589
|
+
});
|
|
590
|
+
const clearFilesMap = (filesMap) => Match.value(filesMap).pipe(Match.when(Match.instanceOf(Map), (map) => {
|
|
591
|
+
map.clear();
|
|
592
|
+
}), Match.orElse((value) => invokeMethod(value, "clear")));
|
|
593
|
+
const experimentalStateClearFiles = (vitest) => Option.match(Option.flatMap(vitestStateOf(vitest), (state) => propertyOf(state, "filesMap")), {
|
|
594
|
+
onNone: () => void 0,
|
|
595
|
+
onSome: (filesMap) => clearFilesMap(filesMap)
|
|
596
|
+
});
|
|
597
|
+
const entryCountOf = (collection) => Match.value(collection).pipe(Match.when(Match.instanceOf(Set), (set) => Option.some(set.size)), Match.orElse((value) => Option.filter(propertyOf(value, "size"), Predicate.isNumber)));
|
|
598
|
+
const experimentalStateHasExternalErrors = (vitest) => Option.exists(Option.flatMap(errorsSetOf(vitest), entryCountOf), (count) => count > 0);
|
|
599
|
+
const experimentalStateGetExternalErrorText = (vitest) => Option.match(errorsSetOf(vitest), {
|
|
600
|
+
onNone: () => "",
|
|
601
|
+
onSome: (errorsSet) => Match.value(errorsSet).pipe(Match.when(Predicate.isIterable, (errors) => [...errors].map(errorToString).join("\n")), Match.orElse(() => ""))
|
|
602
|
+
});
|
|
603
|
+
const applyHarnessValue = (ctx, key, value) => Match.value(key).pipe(Match.when("hitLimit", () => {
|
|
604
|
+
ctx.provide("hitLimit", Option.getOrUndefined(Option.filter(Option.fromNullishOr(value), Predicate.isNumber)));
|
|
605
|
+
}), Match.when("mutantActivation", () => {
|
|
606
|
+
Match.value(value).pipe(Match.when(Match.is("runtime", "static"), (activation) => {
|
|
607
|
+
ctx.provide("mutantActivation", activation);
|
|
608
|
+
}), Match.orElse(() => void 0));
|
|
609
|
+
}), Match.orElse(() => {
|
|
610
|
+
Match.value(value).pipe(Match.when(Predicate.isString, (activeMutant) => {
|
|
611
|
+
ctx.provide("activeMutant", activeMutant);
|
|
612
|
+
}), Match.orElse(() => void 0));
|
|
613
|
+
}));
|
|
614
614
|
const applyRunFilterToConfig = (vitest, options) => {
|
|
615
615
|
Reflect.set(vitest.config, "related", options.related);
|
|
616
616
|
for (const project of vitest.projects) Reflect.set(project.config, "testNamePattern", options.testNamePattern);
|
|
617
617
|
};
|
|
618
|
+
const disableScreenshotFailures = (value) => Option.match(Option.filter(Option.fromNullishOr(value), Predicate.isObject), {
|
|
619
|
+
onNone: () => void 0,
|
|
620
|
+
onSome: (browser) => {
|
|
621
|
+
Reflect.set(browser, "screenshotFailures", false);
|
|
622
|
+
}
|
|
623
|
+
});
|
|
624
|
+
const setupFilePathsOf = (value) => Match.value(value).pipe(Match.when(Array.isArray, (setupFiles) => setupFiles.filter(Predicate.isString)), Match.orElse(() => []));
|
|
618
625
|
const applySetupFilesToProjects = (vitest, localSetupFile) => {
|
|
619
|
-
|
|
620
|
-
if (typeof browser === "object" && browser !== null) Reflect.set(browser, "screenshotFailures", false);
|
|
626
|
+
disableScreenshotFailures(Reflect.get(vitest.config, "browser"));
|
|
621
627
|
for (const project of vitest.projects) {
|
|
622
|
-
const
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
return [];
|
|
626
|
-
})();
|
|
627
|
-
Reflect.set(project.config, "setupFiles", [localSetupFile, ...files]);
|
|
628
|
-
const pBrowser = Reflect.get(project.config, "browser");
|
|
629
|
-
if (typeof pBrowser === "object" && pBrowser !== null) Reflect.set(pBrowser, "screenshotFailures", false);
|
|
628
|
+
const setupFiles = setupFilePathsOf(Reflect.get(project.config, "setupFiles"));
|
|
629
|
+
Reflect.set(project.config, "setupFiles", [localSetupFile, ...setupFiles]);
|
|
630
|
+
disableScreenshotFailures(Reflect.get(project.config, "browser"));
|
|
630
631
|
}
|
|
631
632
|
};
|
|
632
633
|
const makeVitestRunnerLayer = (input) => Layer.effect(TestRunner, Effect$1.gen(function* () {
|
|
@@ -677,17 +678,18 @@ const makeVitestRunnerLayer = (input) => Layer.effect(TestRunner, Effect$1.gen(f
|
|
|
677
678
|
phase: "init",
|
|
678
679
|
cause: errorToString(cause)
|
|
679
680
|
})));
|
|
680
|
-
|
|
681
|
+
const setupFilePath = Option.getOrElse(Option.fromNullishOr(input.setupFilePath), () => defaultSetupPath);
|
|
682
|
+
yield* fsService.copyFile(setupFilePath, localSetupFile).pipe(Effect$1.mapError((cause) => new TestRunnerFailed({
|
|
681
683
|
runnerName: "vitest",
|
|
682
684
|
phase: "init",
|
|
683
685
|
cause: errorToString(cause)
|
|
684
686
|
})));
|
|
685
|
-
const { createVitest, version } = yield* (input.resolveVitestFor
|
|
687
|
+
const { createVitest, version } = yield* Option.getOrElse(Option.fromNullishOr(input.resolveVitestFor), () => resolveVitest)(projectRoot).pipe(Effect$1.provideService(Module, moduleService), Effect$1.provideService(FileSystem.FileSystem, fsService), Effect$1.provideService(Path.Path, pathService), Effect$1.catchDefect((cause) => Effect$1.fail(new TestRunnerFailed({
|
|
686
688
|
runnerName: "vitest",
|
|
687
689
|
phase: "init",
|
|
688
690
|
cause: errorToString(cause)
|
|
689
691
|
}))));
|
|
690
|
-
const namespace = input.globalNamespace
|
|
692
|
+
const namespace = Option.getOrElse(Option.fromNullishOr(input.globalNamespace), () => INSTRUMENTER_CONSTANTS.NAMESPACE);
|
|
691
693
|
const scanDir = (() => {
|
|
692
694
|
if (typeof options.vitest.dir === "string") return pathService.resolve(projectRoot, options.vitest.dir);
|
|
693
695
|
})();
|
|
@@ -744,60 +746,42 @@ const makeVitestRunnerLayer = (input) => Layer.effect(TestRunner, Effect$1.gen(f
|
|
|
744
746
|
const ctx = yield* requireCtx;
|
|
745
747
|
experimentalStateClearFiles(ctx);
|
|
746
748
|
});
|
|
747
|
-
const getFileMeta = (file) => (()
|
|
748
|
-
if (file !== null && typeof file === "object" && "meta" in file) return Reflect.get(file, "meta");
|
|
749
|
-
})();
|
|
749
|
+
const getFileMeta = (file) => Option.getOrUndefined(propertyOf(file, "meta"));
|
|
750
750
|
const readHitCount = Effect$1.gen(function* () {
|
|
751
751
|
const ctx = yield* requireCtx.pipe(Effect$1.mapError((cause) => new CoverageDecodeFailed({ cause })));
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
752
|
+
return (yield* Effect$1.forEach(experimentalStateGetFiles(ctx), (file) => Effect$1.map(S.decodeUnknownEffect(HitCountMetaSchema)(getFileMeta(file)).pipe(Effect$1.mapError((cause) => new CoverageDecodeFailed({ cause })), Effect$1.orElseSucceed(() => ({ hitCount: void 0 }))), (decoded) => Option.getOrElse(Option.fromNullishOr(decoded.hitCount), () => 0)))).reduce((total, count) => total + count, 0);
|
|
753
|
+
});
|
|
754
|
+
const stringProperty = (value, key) => Option.getOrElse(Option.filter(propertyOf(value, key), Predicate.isString), () => "");
|
|
755
|
+
const dedupeFilesByName = (files) => Object.fromEntries(files.map((file) => [`${stringProperty(file, "projectName")}-${stringProperty(file, "name")}`, file]));
|
|
756
|
+
const validateCoverage = (mutantCoverage) => {
|
|
757
|
+
const normalized = normalizeCoverage(mutantCoverage, input.sandboxDirectory, pathService);
|
|
758
|
+
return S.decodeEffect(MutantCoverageShapeSchema)(normalized).pipe(Effect$1.mapError((cause) => new CoverageDecodeFailed({ cause })), Effect$1.map(() => normalized));
|
|
759
|
+
};
|
|
760
|
+
const coverageOfFile = (file) => Effect$1.gen(function* () {
|
|
761
|
+
const decoded = yield* S.decodeUnknownEffect(MutantCoverageMetaSchema)(getFileMeta(file)).pipe(Effect$1.mapError((cause) => new CoverageDecodeFailed({ cause })), Effect$1.orElseSucceed(() => ({ mutantCoverage: void 0 })));
|
|
762
|
+
return yield* Option.match(Option.fromNullishOr(decoded.mutantCoverage), {
|
|
763
|
+
onNone: () => Effect$1.succeed(void 0),
|
|
764
|
+
onSome: (mutantCoverage) => validateCoverage(mutantCoverage)
|
|
765
|
+
});
|
|
766
|
+
});
|
|
767
|
+
const mergeTestCoverage = (perTest, testId, coverage) => Option.match(Option.fromNullishOr(perTest[testId]), {
|
|
768
|
+
onNone: () => {
|
|
769
|
+
perTest[testId] = coverage;
|
|
770
|
+
},
|
|
771
|
+
onSome: (existing) => {
|
|
772
|
+
mergeCoverage(existing, coverage);
|
|
758
773
|
}
|
|
759
|
-
return total;
|
|
760
774
|
});
|
|
775
|
+
const mergeProjectCoverage = (acc, projectCoverage) => {
|
|
776
|
+
for (const [testId, testCoverage] of Object.entries(projectCoverage.perTest)) mergeTestCoverage(acc.perTest, testId, testCoverage);
|
|
777
|
+
mergeCoverage(acc.static, projectCoverage.static);
|
|
778
|
+
return acc;
|
|
779
|
+
};
|
|
761
780
|
const readMutantCoverage = Effect$1.gen(function* () {
|
|
762
781
|
const ctx = yield* requireCtx.pipe(Effect$1.mapError((cause) => new CoverageDecodeFailed({ cause })));
|
|
763
|
-
const files = experimentalStateGetFiles(ctx);
|
|
764
|
-
const
|
|
765
|
-
|
|
766
|
-
const projectNameValue = (() => {
|
|
767
|
-
if (typeof file === "object" && file !== null && "projectName" in file) return Reflect.get(file, "projectName");
|
|
768
|
-
})();
|
|
769
|
-
const projectName = (() => {
|
|
770
|
-
if (typeof projectNameValue === "string") return projectNameValue;
|
|
771
|
-
return "";
|
|
772
|
-
})();
|
|
773
|
-
const nameValue = (() => {
|
|
774
|
-
if (typeof file === "object" && file !== null && "name" in file) return Reflect.get(file, "name");
|
|
775
|
-
})();
|
|
776
|
-
const name = (() => {
|
|
777
|
-
if (typeof nameValue === "string") return nameValue;
|
|
778
|
-
return "";
|
|
779
|
-
})();
|
|
780
|
-
deduped[`${projectName}-${name}`] = file;
|
|
781
|
-
}
|
|
782
|
-
const coverages = [];
|
|
783
|
-
for (const file of Object.values(deduped)) {
|
|
784
|
-
const rawMeta = getFileMeta(file);
|
|
785
|
-
const decoded = yield* S.decodeUnknownEffect(MutantCoverageMetaSchema)(rawMeta).pipe(Effect$1.mapError((cause) => new CoverageDecodeFailed({ cause })), Effect$1.orElseSucceed(() => ({ mutantCoverage: void 0 })));
|
|
786
|
-
if (decoded.mutantCoverage !== void 0) {
|
|
787
|
-
const normalized = normalizeCoverage(decoded.mutantCoverage, input.sandboxDirectory, pathService);
|
|
788
|
-
const validated = yield* S.decodeEffect(MutantCoverageShapeSchema)(normalized).pipe(Effect$1.mapError((cause) => new CoverageDecodeFailed({ cause })), Effect$1.map(() => normalized));
|
|
789
|
-
coverages.push(validated);
|
|
790
|
-
}
|
|
791
|
-
}
|
|
792
|
-
if (coverages.length === 0) return void 0;
|
|
793
|
-
if (coverages.length === 1) return coverages[0];
|
|
794
|
-
const first = coverages[0];
|
|
795
|
-
return coverages.slice(1).reduce((acc, projectCoverage) => {
|
|
796
|
-
for (const [testId, testCoverage] of Object.entries(projectCoverage.perTest)) if (testId in acc.perTest) mergeCoverage(acc.perTest[testId], testCoverage);
|
|
797
|
-
else acc.perTest[testId] = testCoverage;
|
|
798
|
-
mergeCoverage(acc.static, projectCoverage.static);
|
|
799
|
-
return acc;
|
|
800
|
-
}, first);
|
|
782
|
+
const files = Object.values(dedupeFilesByName(experimentalStateGetFiles(ctx)));
|
|
783
|
+
const coverages = (yield* Effect$1.forEach(files, coverageOfFile)).filter(Predicate.isNotNullish);
|
|
784
|
+
return Option.getOrUndefined(Option.map(Option.fromNullishOr(coverages[0]), (first) => coverages.slice(1).reduce(mergeProjectCoverage, first)));
|
|
801
785
|
});
|
|
802
786
|
const collectRaw = (filter) => Effect$1.gen(function* () {
|
|
803
787
|
const ctx = yield* requireCtx;
|
|
@@ -808,31 +792,20 @@ const makeVitestRunnerLayer = (input) => Layer.effect(TestRunner, Effect$1.gen(f
|
|
|
808
792
|
cause: errorToString(cause)
|
|
809
793
|
})));
|
|
810
794
|
const vitestInRun = Reflect.get(options, "vitest");
|
|
811
|
-
const
|
|
812
|
-
const
|
|
813
|
-
if (relatedValue !== false && filter.relatedFiles !== void 0) return filter.relatedFiles.map(normalizeFileName);
|
|
814
|
-
})();
|
|
815
|
-
let testFilesToRun = (() => {
|
|
816
|
-
if (filter.testFiles !== void 0) return [...filter.testFiles];
|
|
817
|
-
})();
|
|
818
|
-
let pattern;
|
|
819
|
-
if ((filter.testIds ?? []).length > 0) {
|
|
820
|
-
const parsedTests = (filter.testIds ?? []).map(fromTestId);
|
|
821
|
-
pattern = new RegExp(parsedTests.map(({ test: name }) => RegExp.escape(name)).join("|"));
|
|
822
|
-
testFilesToRun = parsedTests.map(({ file }) => pathService.resolve(input.sandboxDirectory, file));
|
|
823
|
-
}
|
|
795
|
+
const related = relatedFilesOf(Reflect.get(vitestInRun, "related"), filter.relatedFiles);
|
|
796
|
+
const plan = runFilterPlan(filter, input.sandboxDirectory, pathService);
|
|
824
797
|
applyRunFilterToConfig(ctx, {
|
|
825
798
|
related,
|
|
826
|
-
testNamePattern:
|
|
799
|
+
testNamePattern: plan.testNamePattern
|
|
827
800
|
});
|
|
828
801
|
yield* Effect$1.tryPromise({
|
|
829
|
-
try: () => ctx.start(
|
|
802
|
+
try: () => ctx.start(plan.testFiles),
|
|
830
803
|
catch: (cause) => new TestRunnerFailed({
|
|
831
804
|
runnerName: "vitest",
|
|
832
805
|
phase: "dryRun",
|
|
833
806
|
cause: errorToString(cause)
|
|
834
807
|
})
|
|
835
|
-
}).pipe(Effect$1.catchIf((error) =>
|
|
808
|
+
}).pipe(Effect$1.catchIf((error) => isMissingTestFilesCause(error.cause), () => Effect$1.void));
|
|
836
809
|
const rawTests = experimentalStateGetFiles(ctx).flatMap((file) => (() => {
|
|
837
810
|
if (isRunnerTestSuite(file)) return collectTestsFromSuite(file);
|
|
838
811
|
return [];
|
|
@@ -841,10 +814,7 @@ const makeVitestRunnerLayer = (input) => Layer.effect(TestRunner, Effect$1.gen(f
|
|
|
841
814
|
return {
|
|
842
815
|
rawTests,
|
|
843
816
|
hasExternalError,
|
|
844
|
-
externalErrorText: (() =>
|
|
845
|
-
if (hasExternalError) return experimentalStateGetExternalErrorText(ctx);
|
|
846
|
-
return "";
|
|
847
|
-
})()
|
|
817
|
+
externalErrorText: Match.value(hasExternalError).pipe(Match.when(true, () => experimentalStateGetExternalErrorText(ctx)), Match.orElse(() => ""))
|
|
848
818
|
};
|
|
849
819
|
});
|
|
850
820
|
const harnessImpl = {
|
|
@@ -853,12 +823,7 @@ const makeVitestRunnerLayer = (input) => Layer.effect(TestRunner, Effect$1.gen(f
|
|
|
853
823
|
}),
|
|
854
824
|
provide: (key, value) => Effect$1.gen(function* () {
|
|
855
825
|
const ctx = yield* requireCtx;
|
|
856
|
-
|
|
857
|
-
if (typeof value === "number" || value === void 0) ctx.provide("hitLimit", value);
|
|
858
|
-
else ctx.provide("hitLimit", void 0);
|
|
859
|
-
} else if (key === "mutantActivation") {
|
|
860
|
-
if (value === "runtime" || value === "static") ctx.provide("mutantActivation", value);
|
|
861
|
-
} else if (typeof value === "string") ctx.provide("activeMutant", value);
|
|
826
|
+
applyHarnessValue(ctx, key, value);
|
|
862
827
|
})
|
|
863
828
|
};
|
|
864
829
|
const mutantRunCell = Cell.layer({
|
|
@@ -901,31 +866,15 @@ const makeVitestRunnerLayer = (input) => Layer.effect(TestRunner, Effect$1.gen(f
|
|
|
901
866
|
reportAllKillers
|
|
902
867
|
};
|
|
903
868
|
}),
|
|
904
|
-
decode: (raw) => {
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
if (raw.hitLimit !== void 0) return Result.succeed(new VitestMutantRunCommand({
|
|
914
|
-
...base,
|
|
915
|
-
hitCount: raw.hitCount,
|
|
916
|
-
hitLimit: raw.hitLimit
|
|
917
|
-
}));
|
|
918
|
-
return Result.succeed(new VitestMutantRunCommand({
|
|
919
|
-
...base,
|
|
920
|
-
hitCount: raw.hitCount
|
|
921
|
-
}));
|
|
922
|
-
}
|
|
923
|
-
if (raw.hitLimit !== void 0) return Result.succeed(new VitestMutantRunCommand({
|
|
924
|
-
...base,
|
|
925
|
-
hitLimit: raw.hitLimit
|
|
926
|
-
}));
|
|
927
|
-
return Result.succeed(new VitestMutantRunCommand(base));
|
|
928
|
-
},
|
|
869
|
+
decode: (raw) => Result.succeed(new VitestMutantRunCommand({
|
|
870
|
+
rawTests: raw.rawTests,
|
|
871
|
+
projectRoot: raw.projectRoot,
|
|
872
|
+
hasExternalError: raw.hasExternalError,
|
|
873
|
+
externalErrorText: raw.externalErrorText,
|
|
874
|
+
hitCount: raw.hitCount,
|
|
875
|
+
hitLimit: raw.hitLimit,
|
|
876
|
+
reportAllKillers: raw.reportAllKillers
|
|
877
|
+
})),
|
|
929
878
|
decide: interpretVitestRun,
|
|
930
879
|
encode: (outcome) => Result.match(outcome, {
|
|
931
880
|
onFailure: (e) => ({
|
|
@@ -933,15 +882,7 @@ const makeVitestRunnerLayer = (input) => Layer.effect(TestRunner, Effect$1.gen(f
|
|
|
933
882
|
errorMessage: e.message
|
|
934
883
|
}),
|
|
935
884
|
onSuccess: (out) => {
|
|
936
|
-
const nrOfTests = () =>
|
|
937
|
-
try {
|
|
938
|
-
const raw = JSON.parse(out.testsJson);
|
|
939
|
-
if (Array.isArray(raw)) return raw.filter(isIdRecord).length;
|
|
940
|
-
return 0;
|
|
941
|
-
} catch {
|
|
942
|
-
return 0;
|
|
943
|
-
}
|
|
944
|
-
};
|
|
885
|
+
const nrOfTests = () => countIdRecords(parseJson(out.testsJson));
|
|
945
886
|
return Match.value(out).pipe(Match.tag("Error", (error) => ({
|
|
946
887
|
status: "error",
|
|
947
888
|
errorMessage: error.errorMessage ?? "unknown"
|
|
@@ -967,20 +908,32 @@ const makeVitestRunnerLayer = (input) => Layer.effect(TestRunner, Effect$1.gen(f
|
|
|
967
908
|
}),
|
|
968
909
|
write: (output, _raw) => Effect$1.succeed(output)
|
|
969
910
|
});
|
|
911
|
+
const dryRunFilter = (options) => {
|
|
912
|
+
const relatedFiles = Option.getOrUndefined(Option.map(Option.fromNullishOr(options.files), (files) => [...files]));
|
|
913
|
+
return Match.value(testFilesProvided(options)).pipe(Match.when(true, () => ({
|
|
914
|
+
testFiles: Option.getOrElse(Option.map(Option.fromNullishOr(options.testFiles), (files) => [...files]), () => []),
|
|
915
|
+
relatedFiles
|
|
916
|
+
})), Match.orElse(() => ({ relatedFiles })));
|
|
917
|
+
};
|
|
918
|
+
const completeDryRun = (testsJson) => Effect$1.gen(function* () {
|
|
919
|
+
const tests = Match.value(parseJson(testsJson)).pipe(Match.when(Array.isArray, (entries) => entries.filter(isTestResultLike)), Match.orElse(() => []));
|
|
920
|
+
const mutantCoverage = yield* readMutantCoverage.pipe(Effect$1.mapError((cause) => new TestRunnerFailed({
|
|
921
|
+
runnerName: "vitest",
|
|
922
|
+
phase: "dryRun",
|
|
923
|
+
cause: errorToString(cause)
|
|
924
|
+
})));
|
|
925
|
+
return Match.value(mutantCoverage).pipe(Match.when(Match.defined, (coverage) => ({
|
|
926
|
+
status: "complete",
|
|
927
|
+
tests,
|
|
928
|
+
mutantCoverage: coverage
|
|
929
|
+
})), Match.orElse(() => ({
|
|
930
|
+
status: "complete",
|
|
931
|
+
tests
|
|
932
|
+
})));
|
|
933
|
+
});
|
|
970
934
|
const dryRun = (options) => Effect$1.gen(function* () {
|
|
971
935
|
yield* (yield* VitestHarness).setMode("dry-run");
|
|
972
|
-
const
|
|
973
|
-
const filter = (() => {
|
|
974
|
-
if (hasTestFiles) return {
|
|
975
|
-
testFiles: [...options.testFiles ?? []],
|
|
976
|
-
relatedFiles: (() => {
|
|
977
|
-
if (options.files !== void 0) return [...options.files];
|
|
978
|
-
})()
|
|
979
|
-
};
|
|
980
|
-
return { relatedFiles: (() => {
|
|
981
|
-
if (options.files !== void 0) return [...options.files];
|
|
982
|
-
})() };
|
|
983
|
-
})();
|
|
936
|
+
const filter = dryRunFilter(options);
|
|
984
937
|
const { rawTests, hasExternalError, externalErrorText } = yield* collectRaw(filter);
|
|
985
938
|
const decision = decideVitestDryRun(new VitestDryRunCommand({
|
|
986
939
|
rawTests,
|
|
@@ -988,31 +941,10 @@ const makeVitestRunnerLayer = (input) => Layer.effect(TestRunner, Effect$1.gen(f
|
|
|
988
941
|
hasExternalError,
|
|
989
942
|
externalErrorText
|
|
990
943
|
}));
|
|
991
|
-
|
|
944
|
+
return yield* Match.value(decision).pipe(Match.tag("Error", (error) => Effect$1.succeed({
|
|
992
945
|
status: "error",
|
|
993
946
|
errorMessage: error.errorMessage
|
|
994
|
-
})), Match.tag("Complete", (complete) =>
|
|
995
|
-
const raw = JSON.parse(complete.testsJson);
|
|
996
|
-
let tests;
|
|
997
|
-
if (Array.isArray(raw)) tests = raw.filter(isTestResultLike);
|
|
998
|
-
else tests = [];
|
|
999
|
-
return {
|
|
1000
|
-
status: "complete",
|
|
1001
|
-
tests
|
|
1002
|
-
};
|
|
1003
|
-
}), Match.exhaustive);
|
|
1004
|
-
if (result.status === "complete") {
|
|
1005
|
-
const mutantCoverage = yield* readMutantCoverage.pipe(Effect$1.mapError((cause) => new TestRunnerFailed({
|
|
1006
|
-
runnerName: "vitest",
|
|
1007
|
-
phase: "dryRun",
|
|
1008
|
-
cause: errorToString(cause)
|
|
1009
|
-
})));
|
|
1010
|
-
if (mutantCoverage !== void 0) return {
|
|
1011
|
-
...result,
|
|
1012
|
-
mutantCoverage
|
|
1013
|
-
};
|
|
1014
|
-
}
|
|
1015
|
-
return result;
|
|
947
|
+
})), Match.tag("Complete", (complete) => completeDryRun(complete.testsJson)), Match.exhaustive);
|
|
1016
948
|
}).pipe(Effect$1.provideService(VitestHarness, harnessImpl), Effect$1.mapError((cause) => (() => {
|
|
1017
949
|
if (cause instanceof TestRunnerFailed) return cause;
|
|
1018
950
|
return new TestRunnerFailed({
|
|
@@ -1029,24 +961,31 @@ const makeVitestRunnerLayer = (input) => Layer.effect(TestRunner, Effect$1.gen(f
|
|
|
1029
961
|
cause: errorToString(cause)
|
|
1030
962
|
});
|
|
1031
963
|
})()));
|
|
964
|
+
const disposeContext = (ctx, localSetupFile) => Effect$1.gen(function* () {
|
|
965
|
+
Option.match(Option.fromNullishOr(localSetupFile), {
|
|
966
|
+
onNone: () => void 0,
|
|
967
|
+
onSome: (file) => {
|
|
968
|
+
ctx.onClose(() => Effect$1.runPromise(fsService.remove(file, {
|
|
969
|
+
recursive: true,
|
|
970
|
+
force: true
|
|
971
|
+
}).pipe(Effect$1.orElseSucceed(() => void 0))));
|
|
972
|
+
}
|
|
973
|
+
});
|
|
974
|
+
yield* Effect$1.tryPromise({
|
|
975
|
+
try: () => ctx.close(),
|
|
976
|
+
catch: (cause) => new TestRunnerFailed({
|
|
977
|
+
runnerName: "vitest",
|
|
978
|
+
phase: "dispose",
|
|
979
|
+
cause: errorToString(cause)
|
|
980
|
+
})
|
|
981
|
+
});
|
|
982
|
+
});
|
|
1032
983
|
const dispose = Effect$1.gen(function* () {
|
|
1033
984
|
const state = yield* getState;
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
force: true
|
|
1039
|
-
}).pipe(Effect$1.orElseSucceed(() => void 0))));
|
|
1040
|
-
const currentCtx = state.ctx;
|
|
1041
|
-
yield* Effect$1.tryPromise({
|
|
1042
|
-
try: () => currentCtx.close(),
|
|
1043
|
-
catch: (cause) => new TestRunnerFailed({
|
|
1044
|
-
runnerName: "vitest",
|
|
1045
|
-
phase: "dispose",
|
|
1046
|
-
cause: errorToString(cause)
|
|
1047
|
-
})
|
|
1048
|
-
});
|
|
1049
|
-
}
|
|
985
|
+
return yield* Option.match(Option.fromNullishOr(state.ctx), {
|
|
986
|
+
onNone: () => Effect$1.void,
|
|
987
|
+
onSome: (ctx) => disposeContext(ctx, state.localSetupFile)
|
|
988
|
+
});
|
|
1050
989
|
});
|
|
1051
990
|
return TestRunner.of({
|
|
1052
991
|
capabilities,
|
|
@@ -1057,14 +996,21 @@ const makeVitestRunnerLayer = (input) => Layer.effect(TestRunner, Effect$1.gen(f
|
|
|
1057
996
|
});
|
|
1058
997
|
}));
|
|
1059
998
|
function isTestResultLike(value) {
|
|
1060
|
-
return
|
|
999
|
+
return Predicate.isObject(value) && typeof value["id"] === "string";
|
|
1061
1000
|
}
|
|
1062
|
-
function
|
|
1063
|
-
return
|
|
1001
|
+
function countIdRecords(raw) {
|
|
1002
|
+
return Match.value(raw).pipe(Match.when(Array.isArray, (entries) => entries.filter(isTestResultLike).length), Match.orElse(() => 0));
|
|
1064
1003
|
}
|
|
1004
|
+
const mergeHitCount = (to, mutantId, hitCount) => Option.match(Option.fromNullishOr(to[mutantId]), {
|
|
1005
|
+
onNone: () => {
|
|
1006
|
+
to[mutantId] = hitCount;
|
|
1007
|
+
},
|
|
1008
|
+
onSome: (existing) => {
|
|
1009
|
+
to[mutantId] = existing + hitCount;
|
|
1010
|
+
}
|
|
1011
|
+
});
|
|
1065
1012
|
function mergeCoverage(to, from) {
|
|
1066
|
-
for (const [mutantId, hitCount] of Object.entries(from))
|
|
1067
|
-
else to[mutantId] = hitCount;
|
|
1013
|
+
for (const [mutantId, hitCount] of Object.entries(from)) mergeHitCount(to, mutantId, hitCount);
|
|
1068
1014
|
}
|
|
1069
1015
|
//#endregion
|
|
1070
1016
|
//#region src/index.ts
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@systemfsoftware/stryker-js-vitest-runner",
|
|
3
|
-
"version": "4.0.
|
|
3
|
+
"version": "4.0.1",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "git+https://github.com/systemfsoftware/systemfsoftware.git",
|
|
@@ -32,29 +32,29 @@
|
|
|
32
32
|
},
|
|
33
33
|
"dependencies": {
|
|
34
34
|
"@systemfsoftware/effect-cell-types": "^6.0.1",
|
|
35
|
-
"@systemfsoftware/stryker-js": "^
|
|
35
|
+
"@systemfsoftware/stryker-js": "^3.0.0"
|
|
36
36
|
},
|
|
37
37
|
"peerDependencies": {
|
|
38
|
-
"effect": "
|
|
38
|
+
"effect": "4.0.0-rc.112",
|
|
39
39
|
"vitest": ">=2.0.0"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
|
-
"@effect/platform-node": "
|
|
42
|
+
"@effect/platform-node": "4.0.0-rc.112",
|
|
43
43
|
"@effect/vitest": "4.0.0-rc.112",
|
|
44
44
|
"@systemfsoftware/arethetypeswrong-cli": "^1.1.1",
|
|
45
45
|
"@types/node": "^24",
|
|
46
46
|
"@vitest/browser-playwright": "^4",
|
|
47
|
-
"effect": "
|
|
47
|
+
"effect": "4.0.0-rc.112",
|
|
48
48
|
"oxlint": "^1.77.0",
|
|
49
49
|
"rimraf": "^6.1.3",
|
|
50
50
|
"tsdown": "^0.22.14",
|
|
51
51
|
"typescript": "^7",
|
|
52
52
|
"vitest": "^4",
|
|
53
|
-
"@systemfsoftware/
|
|
54
|
-
"@systemfsoftware/oxlint-config": "^0.1.0",
|
|
53
|
+
"@systemfsoftware/all": "^2.0.0",
|
|
55
54
|
"@systemfsoftware/tsconfig": "^1.3.3",
|
|
56
|
-
"@systemfsoftware/
|
|
57
|
-
"@systemfsoftware/
|
|
55
|
+
"@systemfsoftware/oxlint-config": "^0.1.0",
|
|
56
|
+
"@systemfsoftware/effect-gherkin-spec": "^4.0.1",
|
|
57
|
+
"@systemfsoftware/vitest-config": "^0.1.0"
|
|
58
58
|
},
|
|
59
59
|
"publishConfig": {
|
|
60
60
|
"provenance": true
|