@shivaedev/vitest-rerun 0.1.3 → 0.2.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 +22 -0
- package/README.md +4 -0
- package/dist/cli.js +1 -1
- package/dist/cli.js.map +1 -1
- package/dist/internal/SnapshotFiles.d.ts +3 -0
- package/dist/internal/SnapshotFiles.d.ts.map +1 -0
- package/dist/internal/SnapshotFiles.js +29 -0
- package/dist/internal/SnapshotFiles.js.map +1 -0
- package/dist/internal/adapters/TimedJsonReporter.d.ts.map +1 -0
- package/dist/internal/adapters/TimedJsonReporter.js +16 -0
- package/dist/internal/adapters/TimedJsonReporter.js.map +1 -0
- package/dist/internal/attempt.js +8 -5
- package/dist/internal/attempt.js.map +1 -1
- package/dist/internal/main.d.ts +1 -1
- package/dist/internal/main.d.ts.map +1 -1
- package/dist/internal/mergeAttempt.d.ts +22 -3
- package/dist/internal/mergeAttempt.d.ts.map +1 -1
- package/dist/internal/mergeAttempt.js +41 -7
- package/dist/internal/mergeAttempt.js.map +1 -1
- package/dist/internal/runAttempt.js +2 -2
- package/dist/internal/runAttempt.js.map +1 -1
- package/dist/internal/snapshot.d.ts +52 -10
- package/dist/internal/snapshot.d.ts.map +1 -1
- package/dist/internal/snapshot.js +14 -3
- package/dist/internal/snapshot.js.map +1 -1
- package/dist/internal/writeTimedReport.d.ts +3 -0
- package/dist/internal/writeTimedReport.d.ts.map +1 -0
- package/dist/internal/writeTimedReport.js +14 -0
- package/dist/internal/writeTimedReport.js.map +1 -0
- package/dist/rerun.d.ts +1 -1
- package/dist/rerun.d.ts.map +1 -1
- package/dist/rerun.js +15 -9
- package/dist/rerun.js.map +1 -1
- package/package.json +4 -5
- package/src/cli.ts +1 -1
- package/src/internal/SnapshotFiles.ts +38 -0
- package/src/internal/adapters/TimedJsonReporter.ts +21 -0
- package/src/internal/attempt.ts +15 -10
- package/src/internal/mergeAttempt.ts +49 -8
- package/src/internal/runAttempt.ts +2 -2
- package/src/internal/snapshot.ts +19 -10
- package/src/internal/writeTimedReport.ts +21 -0
- package/src/rerun.ts +16 -9
- package/dist/internal/TimedJsonReporter.d.ts.map +0 -1
- package/dist/internal/TimedJsonReporter.js +0 -17
- package/dist/internal/TimedJsonReporter.js.map +0 -1
- package/src/internal/TimedJsonReporter.ts +0 -17
- /package/dist/internal/{TimedJsonReporter.d.ts → adapters/TimedJsonReporter.d.ts} +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,27 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.2.1 - 2026-11-01
|
|
4
|
+
|
|
5
|
+
### Fixed
|
|
6
|
+
|
|
7
|
+
- Report production imports of the `@effect/platform-node` barrel with module subpaths that avoid loading optional integrations such as redis.
|
|
8
|
+
- Recognize native Effect `catchTags` record keys regardless of the handler body while retaining diagnostics for actual nested component and hook factories.
|
|
9
|
+
- Keep a constant's matching filename valid when the constant becomes private.
|
|
10
|
+
- Name each conflicting fix and format pass's file and line/column range when `quality fix` cannot settle.
|
|
11
|
+
- Use Node platform module subpaths in package runtimes and commands instead of loading the barrel.
|
|
12
|
+
|
|
13
|
+
## 0.2.0 - 2026-10-30
|
|
14
|
+
|
|
15
|
+
### Added
|
|
16
|
+
|
|
17
|
+
- Export every engine module through the package's existing `.ts` wildcard, including modules under `internal/` in `test` and `vitest-rerun` and `server/internal/` in `test-story` and `test-sql`, so downstream kits can reuse them directly. Importing the rerun worker leaves test execution to its direct launch.
|
|
18
|
+
|
|
19
|
+
### Fixed
|
|
20
|
+
|
|
21
|
+
- Decode snapshots and timed JSON reports before using them, reporting malformed files as typed errors that name the file. Read and write timed reports through Effect FileSystem.
|
|
22
|
+
- A rerun that collects a test the attempt before it did not have, or no longer collects one it had, now fails the run with a `vitest-rerun:` message instead of crashing the attempt with an unhandled rejection. The final reports keep the results of the attempt before it.
|
|
23
|
+
- A run no longer leaves its internal `tests.attempt-<n>.bin` snapshots in the output directory.
|
|
24
|
+
|
|
3
25
|
## 0.1.3 - 2026-10-30
|
|
4
26
|
|
|
5
27
|
### Changed
|
package/README.md
CHANGED
|
@@ -34,6 +34,8 @@ The final JUnit and JSON reports still describe the whole run, so CI, coverage a
|
|
|
34
34
|
|
|
35
35
|
An unhandled error, such as an exception thrown after a test finished, cannot be fixed by running a test again, so a run with one is not rerun and fails.
|
|
36
36
|
|
|
37
|
+
A rerun must collect the same tests as the attempt before it. When a rerun collects a test that attempt did not have, or no longer collects one it had, for example because a test's name changes between runs, `vitest-rerun` refuses to merge it: it prints a `vitest-rerun:` message naming the test or file, the run fails with exit code `1`, and the final reports keep the results of the attempt before it.
|
|
38
|
+
|
|
37
39
|
### Options
|
|
38
40
|
|
|
39
41
|
```sh
|
|
@@ -80,6 +82,8 @@ const flaky = Schema.decodeUnknownSync(Schema.fromJsonString(FlakyTests))(conten
|
|
|
80
82
|
|
|
81
83
|
### From Effect
|
|
82
84
|
|
|
85
|
+
Every source module is available through its `.ts` subpath, including modules under `internal/`.
|
|
86
|
+
|
|
83
87
|
The command line is a thin wrapper over two Effect functions. `parseOptions(args, cwd)` from `@shivaedev/vitest-rerun/options.ts` turns command-line arguments into `RerunOptions`, with the output directory resolved against `cwd`, the directory every attempt runs in, failing with a `VitestRerunError` from `/error.ts` for an invalid rerun count. `rerun(options)` from `/rerun.ts` performs the run and succeeds with its exit code; it needs `FileSystem` and `ChildProcessSpawner`, which `NodeServices.layer` from `@effect/platform-node` provides.
|
|
84
88
|
|
|
85
89
|
### Install and limits
|
package/dist/cli.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import process from "node:process";
|
|
3
|
-
import
|
|
3
|
+
import * as NodeServices from "@effect/platform-node/NodeServices";
|
|
4
4
|
import { Effect } from "effect";
|
|
5
5
|
import { main } from "#internal/main.ts";
|
|
6
6
|
process.exitCode = await Effect.runPromise(main(process.argv.slice(2), process.cwd()).pipe(Effect.provide(NodeServices.layer)));
|
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA,OAAO,OAAO,MAAM,cAAc,CAAC;AACnC,OAAO,
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA,OAAO,OAAO,MAAM,cAAc,CAAC;AACnC,OAAO,KAAK,YAAY,MAAM,oCAAoC,CAAC;AACnE,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChC,OAAO,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAC;AAEzC,OAAO,CAAC,QAAQ,GAAG,MAAM,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SnapshotFiles.d.ts","sourceRoot":"","sources":["../../src/internal/SnapshotFiles.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAqChC,eAAO,MAAM,aAAa,sFAAkF,CAAC"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { Schema } from "effect";
|
|
2
|
+
const Result = Schema.Struct({
|
|
3
|
+
duration: Schema.optional(Schema.Number),
|
|
4
|
+
errors: Schema.optional(Schema.Array(Schema.Struct({ message: Schema.String }))),
|
|
5
|
+
startTime: Schema.optional(Schema.Number),
|
|
6
|
+
state: Schema.Literals(["run", "skip", "only", "todo", "queued", "pass", "fail"]),
|
|
7
|
+
});
|
|
8
|
+
const TaskFields = {
|
|
9
|
+
fullName: Schema.String,
|
|
10
|
+
id: Schema.String,
|
|
11
|
+
meta: Schema.Record(Schema.String, Schema.Unknown),
|
|
12
|
+
mode: Schema.Literals(["run", "skip", "only", "todo", "queued"]),
|
|
13
|
+
name: Schema.String,
|
|
14
|
+
result: Schema.optional(Result),
|
|
15
|
+
};
|
|
16
|
+
const TaskTree = Schema.suspend(() => Schema.Union([
|
|
17
|
+
Schema.Struct({ ...TaskFields, tasks: Schema.Array(TaskTree), type: Schema.Literal("suite") }),
|
|
18
|
+
Schema.Struct({ ...TaskFields, fullTestName: Schema.String, type: Schema.Literal("test") }),
|
|
19
|
+
]));
|
|
20
|
+
const FilesSchema = Schema.Array(Schema.Struct({
|
|
21
|
+
...TaskFields,
|
|
22
|
+
filepath: Schema.String,
|
|
23
|
+
projectName: Schema.optional(Schema.String),
|
|
24
|
+
tasks: Schema.Array(TaskTree),
|
|
25
|
+
type: Schema.Literal("suite"),
|
|
26
|
+
}));
|
|
27
|
+
// Decoding structs would copy the tree and break Vitest's circular file/suite references.
|
|
28
|
+
export const SnapshotFiles = Schema.declare((input) => Schema.is(FilesSchema)(input));
|
|
29
|
+
//# sourceMappingURL=SnapshotFiles.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SnapshotFiles.js","sourceRoot":"","sources":["../../src/internal/SnapshotFiles.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAGhC,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC;IAC5B,QAAQ,EAAE,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAC;IACxC,MAAM,EAAE,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;IAChF,SAAS,EAAE,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAC;IACzC,KAAK,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;CACjF,CAAC,CAAC;AAEH,MAAM,UAAU,GAAG;IAClB,QAAQ,EAAE,MAAM,CAAC,MAAM;IACvB,EAAE,EAAE,MAAM,CAAC,MAAM;IACjB,IAAI,EAAE,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,OAAO,CAAC;IAClD,IAAI,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC;IAChE,IAAI,EAAE,MAAM,CAAC,MAAM;IACnB,MAAM,EAAE,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC;CAC/B,CAAC;AAEF,MAAM,QAAQ,GAA0B,MAAM,CAAC,OAAO,CAAC,GAAG,EAAE,CAC3D,MAAM,CAAC,KAAK,CAAC;IACZ,MAAM,CAAC,MAAM,CAAC,EAAE,GAAG,UAAU,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;IAC9F,MAAM,CAAC,MAAM,CAAC,EAAE,GAAG,UAAU,EAAE,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;CAC3F,CAAC,CACF,CAAC;AAEF,MAAM,WAAW,GAAG,MAAM,CAAC,KAAK,CAC/B,MAAM,CAAC,MAAM,CAAC;IACb,GAAG,UAAU;IACb,QAAQ,EAAE,MAAM,CAAC,MAAM;IACvB,WAAW,EAAE,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAC;IAC3C,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC;IAC7B,IAAI,EAAE,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC;CAC7B,CAAC,CACF,CAAC;AAEF,0FAA0F;AAC1F,MAAM,CAAC,MAAM,aAAa,GAAG,MAAM,CAAC,OAAO,CAAQ,CAAC,KAAK,EAAkB,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,WAAW,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TimedJsonReporter.d.ts","sourceRoot":"","sources":["../../../src/internal/adapters/TimedJsonReporter.ts"],"names":[],"mappings":"AAEA,OAAO,EAA8B,YAAY,EAAE,KAAK,UAAU,EAAE,MAAM,aAAa,CAAC;AAIxF,qBAAa,iBAAkB,SAAQ,YAAY;IACnC,YAAY,CAAC,OAAO,EAAE,SAAS,UAAU,EAAE,iBAYzD;CACD"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import * as NodeServices from "@effect/platform-node/NodeServices";
|
|
2
|
+
import { Effect } from "effect";
|
|
3
|
+
import { experimental_getRunnerTask, JsonReporter } from "vitest/node";
|
|
4
|
+
import { VitestRerunError } from "#error.ts";
|
|
5
|
+
import { writeTimedReport } from "#internal/writeTimedReport.ts";
|
|
6
|
+
export class TimedJsonReporter extends JsonReporter {
|
|
7
|
+
async onTestRunEnd(modules) {
|
|
8
|
+
await super.onTestRunEnd([...modules]);
|
|
9
|
+
const path = this.options.outputFile;
|
|
10
|
+
if (path === undefined) {
|
|
11
|
+
throw new VitestRerunError({ message: "Timed JSON reports require an output file" });
|
|
12
|
+
}
|
|
13
|
+
await Effect.runPromise(writeTimedReport(path, modules.map((module) => experimental_getRunnerTask(module).result?.duration ?? 0)).pipe(Effect.provide(NodeServices.layer)));
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=TimedJsonReporter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TimedJsonReporter.js","sourceRoot":"","sources":["../../../src/internal/adapters/TimedJsonReporter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,YAAY,MAAM,oCAAoC,CAAC;AACnE,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChC,OAAO,EAAE,0BAA0B,EAAE,YAAY,EAAmB,MAAM,aAAa,CAAC;AACxF,OAAO,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AAEjE,MAAM,OAAO,iBAAkB,SAAQ,YAAY;IACzC,KAAK,CAAC,YAAY,CAAC,OAA8B;QACzD,MAAM,KAAK,CAAC,YAAY,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;QACvC,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC;QACrC,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;YACxB,MAAM,IAAI,gBAAgB,CAAC,EAAE,OAAO,EAAE,2CAA2C,EAAE,CAAC,CAAC;QACtF,CAAC;QACD,MAAM,MAAM,CAAC,UAAU,CACtB,gBAAgB,CACf,IAAI,EACJ,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,0BAA0B,CAAC,MAAM,CAAC,CAAC,MAAM,EAAE,QAAQ,IAAI,CAAC,CAAC,CACjF,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,CAC1C,CAAC;IACH,CAAC;CACD"}
|
package/dist/internal/attempt.js
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
import process from "node:process";
|
|
2
|
-
import {
|
|
2
|
+
import { fileURLToPath } from "node:url";
|
|
3
|
+
import * as NodeServices from "@effect/platform-node/NodeServices";
|
|
3
4
|
import { Console, Effect } from "effect";
|
|
4
5
|
import { runAttempt } from "#internal/runAttempt.ts";
|
|
5
|
-
|
|
6
|
-
const
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
if (fileURLToPath(import.meta.url) === process.argv[1]) {
|
|
7
|
+
const [attempt = "1", outputDir = ".", ...vitestArgs] = process.argv.slice(2);
|
|
8
|
+
const failed = await Effect.runPromise(runAttempt({ attempt: Number(attempt), outputDir, vitestArgs }).pipe(Effect.catchTag("VitestRerunError", (error) => Effect.as(Console.error(`vitest-rerun: ${error.message}`, ...(error.cause === undefined ? [] : [error.cause])), true)), Effect.provide(NodeServices.layer)));
|
|
9
|
+
if (failed) {
|
|
10
|
+
process.exitCode = 1;
|
|
11
|
+
}
|
|
9
12
|
}
|
|
10
13
|
//# sourceMappingURL=attempt.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"attempt.js","sourceRoot":"","sources":["../../src/internal/attempt.ts"],"names":[],"mappings":"AAAA,OAAO,OAAO,MAAM,cAAc,CAAC;AACnC,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"attempt.js","sourceRoot":"","sources":["../../src/internal/attempt.ts"],"names":[],"mappings":"AAAA,OAAO,OAAO,MAAM,cAAc,CAAC;AACnC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,KAAK,YAAY,MAAM,oCAAoC,CAAC;AACnE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AACzC,OAAO,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAErD,IAAI,aAAa,CAAC,OAAO,IAAI,CAAC,GAAG,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;IACxD,MAAM,CAAC,OAAO,GAAG,GAAG,EAAE,SAAS,GAAG,GAAG,EAAE,GAAG,UAAU,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IAC9E,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,UAAU,CACrC,UAAU,CAAC,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,CAAC,EAAE,SAAS,EAAE,UAAU,EAAE,CAAC,CAAC,IAAI,CACnE,MAAM,CAAC,QAAQ,CAAC,kBAAkB,EAAE,CAAC,KAAK,EAAE,EAAE,CAC7C,MAAM,CAAC,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,iBAAiB,KAAK,CAAC,OAAO,EAAE,EAAE,GAAG,CAAC,KAAK,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,CACrH,EACD,MAAM,CAAC,OAAO,CAAC,YAAY,CAAC,KAAK,CAAC,CAClC,CACD,CAAC;IACF,IAAI,MAAM,EAAE,CAAC;QACZ,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;IACtB,CAAC;AACF,CAAC"}
|
package/dist/internal/main.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import { Effect } from "effect";
|
|
2
|
-
export declare function main(args: readonly string[], cwd: string): Effect.Effect<number, import("effect/PlatformError").PlatformError
|
|
2
|
+
export declare function main(args: readonly string[], cwd: string): Effect.Effect<number, import("effect/PlatformError").PlatformError, import("effect/process/ChildProcessSpawner").ChildProcessSpawner | import("effect/FileSystem").FileSystem>;
|
|
3
3
|
//# sourceMappingURL=main.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../../src/internal/main.ts"],"names":[],"mappings":"AAAA,OAAO,EAAW,MAAM,EAAE,MAAM,QAAQ,CAAC;AAIzC,wBAAgB,IAAI,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,EAAE,GAAG,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../../src/internal/main.ts"],"names":[],"mappings":"AAAA,OAAO,EAAW,MAAM,EAAE,MAAM,QAAQ,CAAC;AAIzC,wBAAgB,IAAI,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,EAAE,GAAG,EAAE,MAAM,kLAKxD"}
|
|
@@ -1,9 +1,28 @@
|
|
|
1
|
+
import { Effect } from "effect";
|
|
2
|
+
import { VitestRerunError } from "#error.ts";
|
|
1
3
|
import { type FlakyTest } from "#flakyTests.ts";
|
|
2
|
-
import { type FailureHistory, type Files
|
|
3
|
-
|
|
4
|
+
import { type FailureHistory, type Files } from "#internal/snapshot.ts";
|
|
5
|
+
interface Merged {
|
|
4
6
|
readonly failures: Readonly<Record<string, FailureHistory>>;
|
|
5
7
|
readonly files: Files;
|
|
6
8
|
readonly flaky: readonly FlakyTest[];
|
|
7
9
|
}
|
|
8
|
-
export declare
|
|
10
|
+
export declare const mergeAttempt: (previous: {
|
|
11
|
+
readonly errors: readonly unknown[];
|
|
12
|
+
readonly failures: {
|
|
13
|
+
readonly [x: string]: {
|
|
14
|
+
readonly attempts: number;
|
|
15
|
+
readonly messages: readonly string[];
|
|
16
|
+
};
|
|
17
|
+
};
|
|
18
|
+
readonly files: import("vitest").RunnerTestFile[];
|
|
19
|
+
readonly flaky: readonly {
|
|
20
|
+
readonly attempts: number;
|
|
21
|
+
readonly classname: string;
|
|
22
|
+
readonly file: string;
|
|
23
|
+
readonly messages: readonly string[];
|
|
24
|
+
readonly name: string;
|
|
25
|
+
}[];
|
|
26
|
+
}, rerun: import("vitest").RunnerTestFile[], root: string, summary: (line: string) => void) => Effect.Effect<Merged, VitestRerunError, never>;
|
|
27
|
+
export {};
|
|
9
28
|
//# sourceMappingURL=mergeAttempt.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mergeAttempt.d.ts","sourceRoot":"","sources":["../../src/internal/mergeAttempt.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,SAAS,EAA6B,MAAM,gBAAgB,CAAC;AAE3E,OAAO,EAAE,KAAK,cAAc,EAAE,KAAK,KAAK,
|
|
1
|
+
{"version":3,"file":"mergeAttempt.d.ts","sourceRoot":"","sources":["../../src/internal/mergeAttempt.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChC,OAAO,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,EAAE,KAAK,SAAS,EAA6B,MAAM,gBAAgB,CAAC;AAE3E,OAAO,EAAE,KAAK,cAAc,EAAE,KAAK,KAAK,EAAmC,MAAM,uBAAuB,CAAC;AAiFzG,UAAU,MAAM;IACf,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC,CAAC;IAC5D,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC;IACtB,QAAQ,CAAC,KAAK,EAAE,SAAS,SAAS,EAAE,CAAC;CACrC;AAkCD,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;2EAIR,MAAM,KAAK,IAAI,mDAiB9B,CAAC"}
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { relative } from "node:path";
|
|
2
|
+
import { Effect } from "effect";
|
|
3
|
+
import { VitestRerunError } from "#error.ts";
|
|
2
4
|
import { failureMessage, testcases } from "#flakyTests.ts";
|
|
3
5
|
import { junitClassname } from "#internal/junit.ts";
|
|
4
6
|
import { tests } from "#internal/snapshot.ts";
|
|
@@ -17,7 +19,7 @@ function restorePassed(original, rerun) {
|
|
|
17
19
|
for (const task of rerun) {
|
|
18
20
|
const first = original.find((item) => item.id === task.id);
|
|
19
21
|
if (first === undefined) {
|
|
20
|
-
|
|
22
|
+
continue;
|
|
21
23
|
}
|
|
22
24
|
if (task.type === "suite" && first.type === "suite") {
|
|
23
25
|
restorePassed(first.tasks, task.tasks);
|
|
@@ -59,9 +61,6 @@ function recordAttempts(file, retried, outcome) {
|
|
|
59
61
|
function mergeFile(file, next, outcome) {
|
|
60
62
|
const original = tests(file.tasks);
|
|
61
63
|
const retried = tests(next.tasks);
|
|
62
|
-
if (original.some((test) => !retried.some((item) => item.id === test.id))) {
|
|
63
|
-
throw new Error(`Rerun did not collect every original test in ${file.filepath}`);
|
|
64
|
-
}
|
|
65
64
|
const ranTests = retried.some((test) => ["pass", "fail"].includes(test.result?.state ?? "") && original.some((item) => item.id === test.id && item.result?.state !== "pass"));
|
|
66
65
|
recordAttempts(file, retried, outcome);
|
|
67
66
|
if (original.length === 0 && next.result?.state === "pass") {
|
|
@@ -72,7 +71,41 @@ function mergeFile(file, next, outcome) {
|
|
|
72
71
|
}
|
|
73
72
|
finishFile(file, next, ranTests);
|
|
74
73
|
}
|
|
75
|
-
|
|
74
|
+
function unexpectedTask(original, rerun) {
|
|
75
|
+
for (const task of rerun) {
|
|
76
|
+
const first = original.find((item) => item.id === task.id);
|
|
77
|
+
if (first === undefined) {
|
|
78
|
+
return task;
|
|
79
|
+
}
|
|
80
|
+
const unexpected = first.type === "suite" && task.type === "suite" ? unexpectedTask(first.tasks, task.tasks) : undefined;
|
|
81
|
+
if (unexpected !== undefined) {
|
|
82
|
+
return unexpected;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return undefined;
|
|
86
|
+
}
|
|
87
|
+
function refusal(previous, rerun, root) {
|
|
88
|
+
for (const file of previous.files) {
|
|
89
|
+
const next = rerun.find((item) => item.id === file.id);
|
|
90
|
+
if (next === undefined) {
|
|
91
|
+
continue;
|
|
92
|
+
}
|
|
93
|
+
const original = tests(file.tasks);
|
|
94
|
+
if (original.some((test) => !tests(next.tasks).some((item) => item.id === test.id))) {
|
|
95
|
+
return `Rerun did not collect every original test in ${relative(root, file.filepath)}`;
|
|
96
|
+
}
|
|
97
|
+
const unexpected = original.length === 0 ? undefined : unexpectedTask(file.tasks, next.tasks);
|
|
98
|
+
if (unexpected !== undefined) {
|
|
99
|
+
return `Rerun collected an unexpected test: ${unexpected.name}`;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
return undefined;
|
|
103
|
+
}
|
|
104
|
+
export const mergeAttempt = Effect.fn("VitestRerun.mergeAttempt")(function* (previous, rerun, root, summary) {
|
|
105
|
+
const refused = refusal(previous, rerun, root);
|
|
106
|
+
if (refused !== undefined) {
|
|
107
|
+
return yield* new VitestRerunError({ message: refused });
|
|
108
|
+
}
|
|
76
109
|
const outcome = { failures: { ...previous.failures }, flaky: [...previous.flaky], root, summary };
|
|
77
110
|
const files = previous.files.map((file) => {
|
|
78
111
|
const next = rerun.find((item) => item.id === file.id);
|
|
@@ -82,6 +115,7 @@ export function mergeAttempt(previous, rerun, root, summary) {
|
|
|
82
115
|
mergeFile(file, next, outcome);
|
|
83
116
|
return next;
|
|
84
117
|
});
|
|
85
|
-
|
|
86
|
-
|
|
118
|
+
const merged = { failures: outcome.failures, files, flaky: outcome.flaky };
|
|
119
|
+
return merged;
|
|
120
|
+
});
|
|
87
121
|
//# sourceMappingURL=mergeAttempt.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mergeAttempt.js","sourceRoot":"","sources":["../../src/internal/mergeAttempt.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AACrC,OAAO,EAAkB,cAAc,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3E,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,EAA6D,KAAK,EAAE,MAAM,uBAAuB,CAAC;AAWzG,SAAS,SAAS,CAAC,KAAW,EAAE,IAAU;IACzC,MAAM,UAAU,GAAG,KAAK,CAAC,MAAM,EAAE,KAAK,KAAK,MAAM,IAAI,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC;IAC1G,IAAI,KAAK,CAAC,MAAM,KAAK,SAAS,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,KAAK,MAAM,IAAI,UAAU,CAAC,EAAE,CAAC;QACjF,IAAI,CAAC,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC;QACvB,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC;QAC3B,IAAI,CAAC,IAAI,GAAG,KAAK,CAAC,IAAI,IAAI,EAAE,CAAC;IAC9B,CAAC;SAAM,IAAI,IAAI,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;QACtC,IAAI,CAAC,MAAM,CAAC,QAAQ,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,IAAI,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,EAAE,QAAQ,IAAI,CAAC,CAAC,CAAC;IACpF,CAAC;AACF,CAAC;AAED,SAAS,aAAa,CAAC,QAAgB,EAAE,KAAa;IACrD,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QAC1B,MAAM,KAAK,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC,CAAC;QAC3D,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;YACzB,
|
|
1
|
+
{"version":3,"file":"mergeAttempt.js","sourceRoot":"","sources":["../../src/internal/mergeAttempt.ts"],"names":[],"mappings":"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"}
|
|
@@ -2,11 +2,11 @@ import { Config, Console, Effect, FileSystem, Schema } from "effect";
|
|
|
2
2
|
import * as VitestNode from "vitest/node";
|
|
3
3
|
import { failWith } from "#error.ts";
|
|
4
4
|
import { writeFlakyTests } from "#flakyTests.ts";
|
|
5
|
+
import { TimedJsonReporter } from "#internal/adapters/TimedJsonReporter.ts";
|
|
5
6
|
import { RerunJunitReporter } from "#internal/junit.ts";
|
|
6
7
|
import { mergeAttempt } from "#internal/mergeAttempt.ts";
|
|
7
8
|
import { attemptPaths, reportPaths } from "#internal/reportPaths.ts";
|
|
8
9
|
import { failedFiles, readSnapshot, saveSnapshot, tests } from "#internal/snapshot.ts";
|
|
9
|
-
import { TimedJsonReporter } from "#internal/TimedJsonReporter.ts";
|
|
10
10
|
const CoverageReport = Schema.Struct({ coverageMap: Schema.optional(Schema.Unknown) });
|
|
11
11
|
const decodeCoverage = Schema.decodeUnknownEffect(Schema.fromJsonString(CoverageReport));
|
|
12
12
|
function promise(message, run) {
|
|
@@ -62,7 +62,7 @@ const rerunFailed = Effect.fn("VitestRerun.rerunFailed")(function* (vitest, { at
|
|
|
62
62
|
}
|
|
63
63
|
yield* promise("Vitest could not rerun the failed tests", () => vitest.runTestSpecifications(specifications));
|
|
64
64
|
const lines = [];
|
|
65
|
-
const merged = mergeAttempt(previous, vitest.state.getFiles(), vitest.config.root, (line) => lines.push(line));
|
|
65
|
+
const merged = yield* mergeAttempt(previous, vitest.state.getFiles(), vitest.config.root, (line) => lines.push(line));
|
|
66
66
|
for (const file of merged.files) {
|
|
67
67
|
vitest.state.collectFiles(vitest.getProjectByName(file.projectName ?? ""), [file]);
|
|
68
68
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runAttempt.js","sourceRoot":"","sources":["../../src/internal/runAttempt.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAErE,OAAO,KAAK,UAAU,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AACrC,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AACxD,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AACzD,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AACrE,OAAO,EAAE,WAAW,EAAE,YAAY,EAAiB,YAAY,EAAE,KAAK,EAAE,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"runAttempt.js","sourceRoot":"","sources":["../../src/internal/runAttempt.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,20 +1,62 @@
|
|
|
1
1
|
import { Effect, FileSystem, Schema } from "effect";
|
|
2
2
|
import type { Vitest } from "vitest/node";
|
|
3
|
-
import type { FlakyTest } from "#flakyTests.ts";
|
|
4
3
|
export type Files = ReturnType<Vitest["state"]["getFiles"]>;
|
|
5
4
|
export type Task = Files[number]["tasks"][number];
|
|
6
5
|
export interface FailureHistory {
|
|
7
6
|
readonly attempts: number;
|
|
8
7
|
readonly messages: readonly string[];
|
|
9
8
|
}
|
|
10
|
-
|
|
11
|
-
readonly errors:
|
|
12
|
-
readonly failures:
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
}
|
|
16
|
-
|
|
9
|
+
declare const SnapshotSchema: Schema.Struct<{
|
|
10
|
+
readonly errors: Schema.$Array<Schema.Unknown>;
|
|
11
|
+
readonly failures: Schema.$Record<Schema.String, Schema.Struct<{
|
|
12
|
+
readonly attempts: Schema.Number;
|
|
13
|
+
readonly messages: Schema.$Array<Schema.String>;
|
|
14
|
+
}>>;
|
|
15
|
+
readonly files: Schema.declare<import("vitest/node").RunnerTestFile[], import("vitest/node").RunnerTestFile[]>;
|
|
16
|
+
readonly flaky: Schema.$Array<Schema.Struct<{
|
|
17
|
+
readonly attempts: Schema.Number;
|
|
18
|
+
readonly classname: Schema.String;
|
|
19
|
+
readonly file: Schema.String;
|
|
20
|
+
readonly messages: Schema.$Array<Schema.String>;
|
|
21
|
+
readonly name: Schema.String;
|
|
22
|
+
}>>;
|
|
23
|
+
}>;
|
|
24
|
+
export type Snapshot = typeof SnapshotSchema.Type;
|
|
25
|
+
export declare const failedFiles: (path: string) => Effect.Effect<string[], import("effect/PlatformError").PlatformError | import("#error.ts").VitestRerunError, FileSystem.FileSystem>;
|
|
17
26
|
export declare function tests(tasks: readonly Task[]): Task[];
|
|
18
|
-
export declare const saveSnapshot: (path: string, snapshot:
|
|
19
|
-
|
|
27
|
+
export declare const saveSnapshot: (path: string, snapshot: {
|
|
28
|
+
readonly errors: readonly unknown[];
|
|
29
|
+
readonly failures: {
|
|
30
|
+
readonly [x: string]: {
|
|
31
|
+
readonly attempts: number;
|
|
32
|
+
readonly messages: readonly string[];
|
|
33
|
+
};
|
|
34
|
+
};
|
|
35
|
+
readonly files: import("vitest/node").RunnerTestFile[];
|
|
36
|
+
readonly flaky: readonly {
|
|
37
|
+
readonly attempts: number;
|
|
38
|
+
readonly classname: string;
|
|
39
|
+
readonly file: string;
|
|
40
|
+
readonly messages: readonly string[];
|
|
41
|
+
readonly name: string;
|
|
42
|
+
}[];
|
|
43
|
+
}) => Effect.Effect<void, import("effect/PlatformError").PlatformError, FileSystem.FileSystem>;
|
|
44
|
+
export declare const readSnapshot: (path: string) => Effect.Effect<{
|
|
45
|
+
readonly errors: readonly unknown[];
|
|
46
|
+
readonly failures: {
|
|
47
|
+
readonly [x: string]: {
|
|
48
|
+
readonly attempts: number;
|
|
49
|
+
readonly messages: readonly string[];
|
|
50
|
+
};
|
|
51
|
+
};
|
|
52
|
+
readonly files: import("vitest/node").RunnerTestFile[];
|
|
53
|
+
readonly flaky: readonly {
|
|
54
|
+
readonly attempts: number;
|
|
55
|
+
readonly classname: string;
|
|
56
|
+
readonly file: string;
|
|
57
|
+
readonly messages: readonly string[];
|
|
58
|
+
readonly name: string;
|
|
59
|
+
}[];
|
|
60
|
+
}, import("effect/PlatformError").PlatformError | import("#error.ts").VitestRerunError, FileSystem.FileSystem>;
|
|
61
|
+
export {};
|
|
20
62
|
//# sourceMappingURL=snapshot.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"snapshot.d.ts","sourceRoot":"","sources":["../../src/internal/snapshot.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AACpD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"snapshot.d.ts","sourceRoot":"","sources":["../../src/internal/snapshot.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AACpD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAK1C,MAAM,MAAM,KAAK,GAAG,UAAU,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC;AAC5D,MAAM,MAAM,IAAI,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC;AAElD,MAAM,WAAW,cAAc;IAC9B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAC;CACrC;AAED,QAAA,MAAM,cAAc;;;;;;;;;;;;;;EAKlB,CAAC;AACH,MAAM,MAAM,QAAQ,GAAG,OAAO,cAAc,CAAC,IAAI,CAAC;AAOlD,eAAO,MAAM,WAAW,uJAKtB,CAAC;AAEH,wBAAgB,KAAK,CAAC,KAAK,EAAE,SAAS,IAAI,EAAE,GAAG,IAAI,EAAE,CAEpD;AAED,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;8FAGvB,CAAC;AAEH,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;8GAOvB,CAAC"}
|
|
@@ -1,10 +1,21 @@
|
|
|
1
1
|
import { deserialize, serialize } from "node:v8";
|
|
2
2
|
import { Effect, FileSystem, Schema } from "effect";
|
|
3
|
+
import { failWith } from "#error.ts";
|
|
4
|
+
import { FlakyTest } from "#flakyTests.ts";
|
|
5
|
+
import { SnapshotFiles } from "./SnapshotFiles.js";
|
|
6
|
+
const SnapshotSchema = Schema.Struct({
|
|
7
|
+
errors: Schema.Array(Schema.Unknown),
|
|
8
|
+
failures: Schema.Record(Schema.String, Schema.Struct({ attempts: Schema.Number, messages: Schema.Array(Schema.String) })),
|
|
9
|
+
files: SnapshotFiles,
|
|
10
|
+
flaky: Schema.Array(FlakyTest),
|
|
11
|
+
});
|
|
12
|
+
const decodeSnapshot = Schema.decodeUnknownEffect(SnapshotSchema);
|
|
3
13
|
const Report = Schema.Struct({ testResults: Schema.Array(Schema.Struct({ name: Schema.String, status: Schema.Literals(["failed", "passed"]) })) });
|
|
4
14
|
const decodeReport = Schema.decodeUnknownEffect(Schema.fromJsonString(Report));
|
|
5
15
|
export const failedFiles = Effect.fn("VitestRerun.failedFiles")(function* (path) {
|
|
6
16
|
const fs = yield* FileSystem.FileSystem;
|
|
7
|
-
const
|
|
17
|
+
const contents = yield* fs.readFileString(path);
|
|
18
|
+
const report = yield* decodeReport(contents).pipe(Effect.mapError(failWith(`Could not decode report ${path}`)));
|
|
8
19
|
return [...new Set(report.testResults.filter((file) => file.status === "failed").map((file) => file.name))];
|
|
9
20
|
});
|
|
10
21
|
export function tests(tasks) {
|
|
@@ -16,7 +27,7 @@ export const saveSnapshot = Effect.fn("VitestRerun.saveSnapshot")(function* (pat
|
|
|
16
27
|
});
|
|
17
28
|
export const readSnapshot = Effect.fn("VitestRerun.readSnapshot")(function* (path) {
|
|
18
29
|
const fs = yield* FileSystem.FileSystem;
|
|
19
|
-
const
|
|
20
|
-
return snapshot;
|
|
30
|
+
const bytes = yield* fs.readFile(path);
|
|
31
|
+
return yield* Effect.try({ catch: (cause) => cause, try: () => deserialize(bytes) }).pipe(Effect.flatMap(decodeSnapshot), Effect.mapError(failWith(`Could not decode snapshot ${path}`)));
|
|
21
32
|
});
|
|
22
33
|
//# sourceMappingURL=snapshot.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"snapshot.js","sourceRoot":"","sources":["../../src/internal/snapshot.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACjD,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;
|
|
1
|
+
{"version":3,"file":"snapshot.js","sourceRoot":"","sources":["../../src/internal/snapshot.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { Effect, FileSystem } from "effect";
|
|
2
|
+
export declare const writeTimedReport: (path: string, durations: readonly number[]) => Effect.Effect<void, import("effect/PlatformError").PlatformError | import("#error.ts").VitestRerunError, FileSystem.FileSystem>;
|
|
3
|
+
//# sourceMappingURL=writeTimedReport.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"writeTimedReport.d.ts","sourceRoot":"","sources":["../../src/internal/writeTimedReport.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,UAAU,EAAU,MAAM,QAAQ,CAAC;AASpD,eAAO,MAAM,gBAAgB,iLAW3B,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { Effect, FileSystem, Schema } from "effect";
|
|
2
|
+
import { failWith } from "#error.ts";
|
|
3
|
+
const ExtraFields = Schema.Record(Schema.String, Schema.Unknown);
|
|
4
|
+
const TestResult = Schema.StructWithRest(Schema.Struct({ assertionResults: Schema.Array(Schema.Unknown), name: Schema.String, status: Schema.Literals(["failed", "passed"]) }), [ExtraFields]);
|
|
5
|
+
export const writeTimedReport = Effect.fn("VitestRerun.writeTimedReport")(function* (path, durations) {
|
|
6
|
+
const fs = yield* FileSystem.FileSystem;
|
|
7
|
+
const contents = yield* fs.readFileString(path);
|
|
8
|
+
const Report = Schema.StructWithRest(Schema.Struct({ testResults: Schema.Array(TestResult).check(Schema.isBetweenLength(durations.length, durations.length)) }), [ExtraFields]);
|
|
9
|
+
const decodeReport = Schema.decodeUnknownEffect(Schema.fromJsonString(Report));
|
|
10
|
+
const report = yield* decodeReport(contents).pipe(Effect.mapError(failWith(`Could not decode timed report ${path}`)));
|
|
11
|
+
const testResults = report.testResults.map((result, index) => ({ ...result, durationMs: durations[index] }));
|
|
12
|
+
yield* fs.writeFileString(path, JSON.stringify({ ...report, testResults }));
|
|
13
|
+
});
|
|
14
|
+
//# sourceMappingURL=writeTimedReport.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"writeTimedReport.js","sourceRoot":"","sources":["../../src/internal/writeTimedReport.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AACpD,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAErC,MAAM,WAAW,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC;AACjE,MAAM,UAAU,GAAG,MAAM,CAAC,cAAc,CACvC,MAAM,CAAC,MAAM,CAAC,EAAE,gBAAgB,EAAE,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC,EAAE,CAAC,EACrI,CAAC,WAAW,CAAC,CACb,CAAC;AAEF,MAAM,CAAC,MAAM,gBAAgB,GAAG,MAAM,CAAC,EAAE,CAAC,8BAA8B,CAAC,CAAC,QAAQ,CAAC,EAAE,IAAY,EAAE,SAA4B;IAC9H,MAAM,EAAE,GAAG,KAAK,CAAC,CAAC,UAAU,CAAC,UAAU,CAAC;IACxC,MAAM,QAAQ,GAAG,KAAK,CAAC,CAAC,EAAE,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC;IAChD,MAAM,MAAM,GAAG,MAAM,CAAC,cAAc,CACnC,MAAM,CAAC,MAAM,CAAC,EAAE,WAAW,EAAE,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,eAAe,CAAC,SAAS,CAAC,MAAM,EAAE,SAAS,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAC1H,CAAC,WAAW,CAAC,CACb,CAAC;IACF,MAAM,YAAY,GAAG,MAAM,CAAC,mBAAmB,CAAC,MAAM,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC,CAAC;IAC/E,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,iCAAiC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;IACtH,MAAM,WAAW,GAAG,MAAM,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,MAAM,EAAE,UAAU,EAAE,SAAS,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC;IAC7G,KAAK,CAAC,CAAC,EAAE,CAAC,eAAe,CAAC,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,GAAG,MAAM,EAAE,WAAW,EAAE,CAAC,CAAC,CAAC;AAC7E,CAAC,CAAC,CAAC"}
|
package/dist/rerun.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Effect, FileSystem } from "effect";
|
|
2
2
|
import { ChildProcessSpawner } from "effect/process";
|
|
3
3
|
import type { RerunOptions } from "#options.ts";
|
|
4
|
-
export declare const rerun: (options: RerunOptions) => Effect.Effect<number, import("effect/PlatformError").PlatformError | import("
|
|
4
|
+
export declare const rerun: (options: RerunOptions) => Effect.Effect<number, import("effect/PlatformError").PlatformError | import("./error.ts").VitestRerunError, ChildProcessSpawner.ChildProcessSpawner | FileSystem.FileSystem>;
|
|
5
5
|
//# sourceMappingURL=rerun.d.ts.map
|
package/dist/rerun.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rerun.d.ts","sourceRoot":"","sources":["../src/rerun.ts"],"names":[],"mappings":"AAGA,OAAO,EAAW,MAAM,EAAE,UAAU,EAAU,MAAM,QAAQ,CAAC;AAC7D,OAAO,EAAgB,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAGnE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"rerun.d.ts","sourceRoot":"","sources":["../src/rerun.ts"],"names":[],"mappings":"AAGA,OAAO,EAAW,MAAM,EAAE,UAAU,EAAU,MAAM,QAAQ,CAAC;AAC7D,OAAO,EAAgB,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAGnE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAkDhD,eAAO,MAAM,KAAK,yMAahB,CAAC"}
|
package/dist/rerun.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { join } from "node:path";
|
|
2
2
|
import process from "node:process";
|
|
3
3
|
import { fileURLToPath } from "node:url";
|
|
4
4
|
import { Console, Effect, FileSystem, Option } from "effect";
|
|
5
5
|
import { ChildProcess, ChildProcessSpawner } from "effect/process";
|
|
6
6
|
import { ATTEMPT_REPORT, attemptPaths, reportPaths } from "#internal/reportPaths.ts";
|
|
7
7
|
import { failedFiles, readSnapshot } from "#internal/snapshot.ts";
|
|
8
|
-
const ATTEMPT_MODULE = fileURLToPath(
|
|
8
|
+
const ATTEMPT_MODULE = fileURLToPath(import.meta.resolve("#internal/attempt.ts"));
|
|
9
9
|
const removeReports = Effect.fn("VitestRerun.removeReports")(function* (outputDir) {
|
|
10
10
|
const fs = yield* FileSystem.FileSystem;
|
|
11
11
|
yield* fs.makeDirectory(outputDir, { recursive: true });
|
|
@@ -34,18 +34,24 @@ const keepFirstAttempt = Effect.fn("VitestRerun.keepFirstAttempt")(function* (ou
|
|
|
34
34
|
yield* fs.copyFile(final.json, first.json);
|
|
35
35
|
yield* fs.copyFile(final.junit, first.junit);
|
|
36
36
|
});
|
|
37
|
+
const removeSnapshots = Effect.fn("VitestRerun.removeSnapshots")(function* (outputDir, attempts) {
|
|
38
|
+
const fs = yield* FileSystem.FileSystem;
|
|
39
|
+
for (let attempt = 1; attempt <= attempts; attempt += 1) {
|
|
40
|
+
yield* fs.remove(attemptPaths(outputDir, attempt).snapshot, { force: true });
|
|
41
|
+
}
|
|
42
|
+
});
|
|
37
43
|
export const rerun = Effect.fn("VitestRerun.rerun")(function* (options) {
|
|
38
44
|
yield* removeReports(options.outputDir);
|
|
39
|
-
let
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
}
|
|
44
|
-
if (attempt === 1) {
|
|
45
|
+
let attempts = 1;
|
|
46
|
+
let code = yield* spawnAttempt(options, attempts);
|
|
47
|
+
while (attempts <= options.reruns && Option.exists(code, (status) => status !== 0) && (yield* rerunnable(options.outputDir, attempts))) {
|
|
48
|
+
if (attempts === 1) {
|
|
45
49
|
yield* keepFirstAttempt(options.outputDir);
|
|
46
50
|
}
|
|
47
|
-
|
|
51
|
+
attempts += 1;
|
|
52
|
+
code = yield* spawnAttempt(options, attempts);
|
|
48
53
|
}
|
|
54
|
+
yield* removeSnapshots(options.outputDir, attempts);
|
|
49
55
|
return Option.getOrElse(code, () => 1);
|
|
50
56
|
});
|
|
51
57
|
//# sourceMappingURL=rerun.js.map
|
package/dist/rerun.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rerun.js","sourceRoot":"","sources":["../src/rerun.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"rerun.js","sourceRoot":"","sources":["../src/rerun.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@shivaedev/vitest-rerun",
|
|
3
|
-
"version": "0.1
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"description": "Reruns failed Vitest tests in a fresh process and reports which tests were flaky",
|
|
5
5
|
"homepage": "https://github.com/ShivaeDev/platform/tree/main/packages/vitest-rerun#readme",
|
|
6
6
|
"bugs": {
|
|
@@ -28,7 +28,6 @@
|
|
|
28
28
|
"types": "./dist/*.d.ts",
|
|
29
29
|
"default": "./dist/*.js"
|
|
30
30
|
},
|
|
31
|
-
"./internal/*": null,
|
|
32
31
|
"./package.json": "./package.json"
|
|
33
32
|
},
|
|
34
33
|
"bin": {
|
|
@@ -47,9 +46,9 @@
|
|
|
47
46
|
"@effect/platform-node": "4.0.6",
|
|
48
47
|
"@effect/platform-node-shared": "4.0.6",
|
|
49
48
|
"@effect/vitest": "4.0.6",
|
|
50
|
-
"@shivaedev/quality": "0.
|
|
51
|
-
"@shivaedev/test": "0.
|
|
52
|
-
"@shivaedev/test-story": "0.
|
|
49
|
+
"@shivaedev/quality": "0.54.0",
|
|
50
|
+
"@shivaedev/test": "0.12.0",
|
|
51
|
+
"@shivaedev/test-story": "0.32.0",
|
|
53
52
|
"@types/node": "24.19.2",
|
|
54
53
|
"@vitest/coverage-v8": "5.0.5",
|
|
55
54
|
"effect": "4.0.6",
|
package/src/cli.ts
CHANGED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { Schema } from "effect";
|
|
2
|
+
import type { Files } from "./snapshot.ts";
|
|
3
|
+
|
|
4
|
+
const Result = Schema.Struct({
|
|
5
|
+
duration: Schema.optional(Schema.Number),
|
|
6
|
+
errors: Schema.optional(Schema.Array(Schema.Struct({ message: Schema.String }))),
|
|
7
|
+
startTime: Schema.optional(Schema.Number),
|
|
8
|
+
state: Schema.Literals(["run", "skip", "only", "todo", "queued", "pass", "fail"]),
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
const TaskFields = {
|
|
12
|
+
fullName: Schema.String,
|
|
13
|
+
id: Schema.String,
|
|
14
|
+
meta: Schema.Record(Schema.String, Schema.Unknown),
|
|
15
|
+
mode: Schema.Literals(["run", "skip", "only", "todo", "queued"]),
|
|
16
|
+
name: Schema.String,
|
|
17
|
+
result: Schema.optional(Result),
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
const TaskTree: Schema.Codec<unknown> = Schema.suspend(() =>
|
|
21
|
+
Schema.Union([
|
|
22
|
+
Schema.Struct({ ...TaskFields, tasks: Schema.Array(TaskTree), type: Schema.Literal("suite") }),
|
|
23
|
+
Schema.Struct({ ...TaskFields, fullTestName: Schema.String, type: Schema.Literal("test") }),
|
|
24
|
+
]),
|
|
25
|
+
);
|
|
26
|
+
|
|
27
|
+
const FilesSchema = Schema.Array(
|
|
28
|
+
Schema.Struct({
|
|
29
|
+
...TaskFields,
|
|
30
|
+
filepath: Schema.String,
|
|
31
|
+
projectName: Schema.optional(Schema.String),
|
|
32
|
+
tasks: Schema.Array(TaskTree),
|
|
33
|
+
type: Schema.Literal("suite"),
|
|
34
|
+
}),
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
// Decoding structs would copy the tree and break Vitest's circular file/suite references.
|
|
38
|
+
export const SnapshotFiles = Schema.declare<Files>((input): input is Files => Schema.is(FilesSchema)(input));
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import * as NodeServices from "@effect/platform-node/NodeServices";
|
|
2
|
+
import { Effect } from "effect";
|
|
3
|
+
import { experimental_getRunnerTask, JsonReporter, type TestModule } from "vitest/node";
|
|
4
|
+
import { VitestRerunError } from "#error.ts";
|
|
5
|
+
import { writeTimedReport } from "#internal/writeTimedReport.ts";
|
|
6
|
+
|
|
7
|
+
export class TimedJsonReporter extends JsonReporter {
|
|
8
|
+
override async onTestRunEnd(modules: readonly TestModule[]) {
|
|
9
|
+
await super.onTestRunEnd([...modules]);
|
|
10
|
+
const path = this.options.outputFile;
|
|
11
|
+
if (path === undefined) {
|
|
12
|
+
throw new VitestRerunError({ message: "Timed JSON reports require an output file" });
|
|
13
|
+
}
|
|
14
|
+
await Effect.runPromise(
|
|
15
|
+
writeTimedReport(
|
|
16
|
+
path,
|
|
17
|
+
modules.map((module) => experimental_getRunnerTask(module).result?.duration ?? 0),
|
|
18
|
+
).pipe(Effect.provide(NodeServices.layer)),
|
|
19
|
+
);
|
|
20
|
+
}
|
|
21
|
+
}
|
package/src/internal/attempt.ts
CHANGED
|
@@ -1,15 +1,20 @@
|
|
|
1
1
|
import process from "node:process";
|
|
2
|
-
import {
|
|
2
|
+
import { fileURLToPath } from "node:url";
|
|
3
|
+
import * as NodeServices from "@effect/platform-node/NodeServices";
|
|
3
4
|
import { Console, Effect } from "effect";
|
|
4
5
|
import { runAttempt } from "#internal/runAttempt.ts";
|
|
5
6
|
|
|
6
|
-
|
|
7
|
-
const
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
)
|
|
13
|
-
|
|
14
|
-
|
|
7
|
+
if (fileURLToPath(import.meta.url) === process.argv[1]) {
|
|
8
|
+
const [attempt = "1", outputDir = ".", ...vitestArgs] = process.argv.slice(2);
|
|
9
|
+
const failed = await Effect.runPromise(
|
|
10
|
+
runAttempt({ attempt: Number(attempt), outputDir, vitestArgs }).pipe(
|
|
11
|
+
Effect.catchTag("VitestRerunError", (error) =>
|
|
12
|
+
Effect.as(Console.error(`vitest-rerun: ${error.message}`, ...(error.cause === undefined ? [] : [error.cause])), true),
|
|
13
|
+
),
|
|
14
|
+
Effect.provide(NodeServices.layer),
|
|
15
|
+
),
|
|
16
|
+
);
|
|
17
|
+
if (failed) {
|
|
18
|
+
process.exitCode = 1;
|
|
19
|
+
}
|
|
15
20
|
}
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { relative } from "node:path";
|
|
2
|
+
import { Effect } from "effect";
|
|
3
|
+
import { VitestRerunError } from "#error.ts";
|
|
2
4
|
import { type FlakyTest, failureMessage, testcases } from "#flakyTests.ts";
|
|
3
5
|
import { junitClassname } from "#internal/junit.ts";
|
|
4
6
|
import { type FailureHistory, type Files, type Snapshot, type Task, tests } from "#internal/snapshot.ts";
|
|
@@ -27,7 +29,7 @@ function restorePassed(original: Task[], rerun: Task[]) {
|
|
|
27
29
|
for (const task of rerun) {
|
|
28
30
|
const first = original.find((item) => item.id === task.id);
|
|
29
31
|
if (first === undefined) {
|
|
30
|
-
|
|
32
|
+
continue;
|
|
31
33
|
}
|
|
32
34
|
if (task.type === "suite" && first.type === "suite") {
|
|
33
35
|
restorePassed(first.tasks, task.tasks);
|
|
@@ -70,9 +72,6 @@ function recordAttempts(file: File, retried: Task[], outcome: Outcome) {
|
|
|
70
72
|
function mergeFile(file: File, next: File, outcome: Outcome) {
|
|
71
73
|
const original = tests(file.tasks);
|
|
72
74
|
const retried = tests(next.tasks);
|
|
73
|
-
if (original.some((test) => !retried.some((item) => item.id === test.id))) {
|
|
74
|
-
throw new Error(`Rerun did not collect every original test in ${file.filepath}`);
|
|
75
|
-
}
|
|
76
75
|
const ranTests = retried.some(
|
|
77
76
|
(test) => ["pass", "fail"].includes(test.result?.state ?? "") && original.some((item) => item.id === test.id && item.result?.state !== "pass"),
|
|
78
77
|
);
|
|
@@ -85,13 +84,54 @@ function mergeFile(file: File, next: File, outcome: Outcome) {
|
|
|
85
84
|
finishFile(file, next, ranTests);
|
|
86
85
|
}
|
|
87
86
|
|
|
88
|
-
|
|
87
|
+
interface Merged {
|
|
89
88
|
readonly failures: Readonly<Record<string, FailureHistory>>;
|
|
90
89
|
readonly files: Files;
|
|
91
90
|
readonly flaky: readonly FlakyTest[];
|
|
92
91
|
}
|
|
93
92
|
|
|
94
|
-
|
|
93
|
+
function unexpectedTask(original: readonly Task[], rerun: readonly Task[]): Task | undefined {
|
|
94
|
+
for (const task of rerun) {
|
|
95
|
+
const first = original.find((item) => item.id === task.id);
|
|
96
|
+
if (first === undefined) {
|
|
97
|
+
return task;
|
|
98
|
+
}
|
|
99
|
+
const unexpected = first.type === "suite" && task.type === "suite" ? unexpectedTask(first.tasks, task.tasks) : undefined;
|
|
100
|
+
if (unexpected !== undefined) {
|
|
101
|
+
return unexpected;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
return undefined;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function refusal(previous: Snapshot, rerun: Files, root: string): string | undefined {
|
|
108
|
+
for (const file of previous.files) {
|
|
109
|
+
const next = rerun.find((item) => item.id === file.id);
|
|
110
|
+
if (next === undefined) {
|
|
111
|
+
continue;
|
|
112
|
+
}
|
|
113
|
+
const original = tests(file.tasks);
|
|
114
|
+
if (original.some((test) => !tests(next.tasks).some((item) => item.id === test.id))) {
|
|
115
|
+
return `Rerun did not collect every original test in ${relative(root, file.filepath)}`;
|
|
116
|
+
}
|
|
117
|
+
const unexpected = original.length === 0 ? undefined : unexpectedTask(file.tasks, next.tasks);
|
|
118
|
+
if (unexpected !== undefined) {
|
|
119
|
+
return `Rerun collected an unexpected test: ${unexpected.name}`;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
return undefined;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
export const mergeAttempt = Effect.fn("VitestRerun.mergeAttempt")(function* (
|
|
126
|
+
previous: Snapshot,
|
|
127
|
+
rerun: Files,
|
|
128
|
+
root: string,
|
|
129
|
+
summary: (line: string) => void,
|
|
130
|
+
) {
|
|
131
|
+
const refused = refusal(previous, rerun, root);
|
|
132
|
+
if (refused !== undefined) {
|
|
133
|
+
return yield* new VitestRerunError({ message: refused });
|
|
134
|
+
}
|
|
95
135
|
const outcome: Outcome = { failures: { ...previous.failures }, flaky: [...previous.flaky], root, summary };
|
|
96
136
|
const files = previous.files.map((file) => {
|
|
97
137
|
const next = rerun.find((item) => item.id === file.id);
|
|
@@ -101,5 +141,6 @@ export function mergeAttempt(previous: Snapshot, rerun: Files, root: string, sum
|
|
|
101
141
|
mergeFile(file, next, outcome);
|
|
102
142
|
return next;
|
|
103
143
|
});
|
|
104
|
-
|
|
105
|
-
|
|
144
|
+
const merged: Merged = { failures: outcome.failures, files, flaky: outcome.flaky };
|
|
145
|
+
return merged;
|
|
146
|
+
});
|
|
@@ -3,11 +3,11 @@ import type { CliOptions, Vitest } from "vitest/node";
|
|
|
3
3
|
import * as VitestNode from "vitest/node";
|
|
4
4
|
import { failWith } from "#error.ts";
|
|
5
5
|
import { writeFlakyTests } from "#flakyTests.ts";
|
|
6
|
+
import { TimedJsonReporter } from "#internal/adapters/TimedJsonReporter.ts";
|
|
6
7
|
import { RerunJunitReporter } from "#internal/junit.ts";
|
|
7
8
|
import { mergeAttempt } from "#internal/mergeAttempt.ts";
|
|
8
9
|
import { attemptPaths, reportPaths } from "#internal/reportPaths.ts";
|
|
9
10
|
import { failedFiles, readSnapshot, type Snapshot, saveSnapshot, tests } from "#internal/snapshot.ts";
|
|
10
|
-
import { TimedJsonReporter } from "#internal/TimedJsonReporter.ts";
|
|
11
11
|
|
|
12
12
|
export interface Attempt {
|
|
13
13
|
readonly attempt: number;
|
|
@@ -84,7 +84,7 @@ const rerunFailed = Effect.fn("VitestRerun.rerunFailed")(function* (vitest: Vite
|
|
|
84
84
|
}
|
|
85
85
|
yield* promise("Vitest could not rerun the failed tests", () => vitest.runTestSpecifications(specifications));
|
|
86
86
|
const lines: string[] = [];
|
|
87
|
-
const merged = mergeAttempt(previous, vitest.state.getFiles(), vitest.config.root, (line) => lines.push(line));
|
|
87
|
+
const merged = yield* mergeAttempt(previous, vitest.state.getFiles(), vitest.config.root, (line) => lines.push(line));
|
|
88
88
|
for (const file of merged.files) {
|
|
89
89
|
vitest.state.collectFiles(vitest.getProjectByName(file.projectName ?? ""), [file]);
|
|
90
90
|
}
|
package/src/internal/snapshot.ts
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { deserialize, serialize } from "node:v8";
|
|
2
2
|
import { Effect, FileSystem, Schema } from "effect";
|
|
3
3
|
import type { Vitest } from "vitest/node";
|
|
4
|
-
import
|
|
4
|
+
import { failWith } from "#error.ts";
|
|
5
|
+
import { FlakyTest } from "#flakyTests.ts";
|
|
6
|
+
import { SnapshotFiles } from "./SnapshotFiles.ts";
|
|
5
7
|
|
|
6
8
|
export type Files = ReturnType<Vitest["state"]["getFiles"]>;
|
|
7
9
|
export type Task = Files[number]["tasks"][number];
|
|
@@ -11,19 +13,23 @@ export interface FailureHistory {
|
|
|
11
13
|
readonly messages: readonly string[];
|
|
12
14
|
}
|
|
13
15
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
}
|
|
16
|
+
const SnapshotSchema = Schema.Struct({
|
|
17
|
+
errors: Schema.Array(Schema.Unknown),
|
|
18
|
+
failures: Schema.Record(Schema.String, Schema.Struct({ attempts: Schema.Number, messages: Schema.Array(Schema.String) })),
|
|
19
|
+
files: SnapshotFiles,
|
|
20
|
+
flaky: Schema.Array(FlakyTest),
|
|
21
|
+
});
|
|
22
|
+
export type Snapshot = typeof SnapshotSchema.Type;
|
|
23
|
+
|
|
24
|
+
const decodeSnapshot = Schema.decodeUnknownEffect(SnapshotSchema);
|
|
20
25
|
|
|
21
26
|
const Report = Schema.Struct({ testResults: Schema.Array(Schema.Struct({ name: Schema.String, status: Schema.Literals(["failed", "passed"]) })) });
|
|
22
27
|
const decodeReport = Schema.decodeUnknownEffect(Schema.fromJsonString(Report));
|
|
23
28
|
|
|
24
29
|
export const failedFiles = Effect.fn("VitestRerun.failedFiles")(function* (path: string) {
|
|
25
30
|
const fs = yield* FileSystem.FileSystem;
|
|
26
|
-
const
|
|
31
|
+
const contents = yield* fs.readFileString(path);
|
|
32
|
+
const report = yield* decodeReport(contents).pipe(Effect.mapError(failWith(`Could not decode report ${path}`)));
|
|
27
33
|
return [...new Set(report.testResults.filter((file) => file.status === "failed").map((file) => file.name))];
|
|
28
34
|
});
|
|
29
35
|
|
|
@@ -38,6 +44,9 @@ export const saveSnapshot = Effect.fn("VitestRerun.saveSnapshot")(function* (pat
|
|
|
38
44
|
|
|
39
45
|
export const readSnapshot = Effect.fn("VitestRerun.readSnapshot")(function* (path: string) {
|
|
40
46
|
const fs = yield* FileSystem.FileSystem;
|
|
41
|
-
const
|
|
42
|
-
return
|
|
47
|
+
const bytes = yield* fs.readFile(path);
|
|
48
|
+
return yield* Effect.try({ catch: (cause) => cause, try: (): unknown => deserialize(bytes) }).pipe(
|
|
49
|
+
Effect.flatMap(decodeSnapshot),
|
|
50
|
+
Effect.mapError(failWith(`Could not decode snapshot ${path}`)),
|
|
51
|
+
);
|
|
43
52
|
});
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { Effect, FileSystem, Schema } from "effect";
|
|
2
|
+
import { failWith } from "#error.ts";
|
|
3
|
+
|
|
4
|
+
const ExtraFields = Schema.Record(Schema.String, Schema.Unknown);
|
|
5
|
+
const TestResult = Schema.StructWithRest(
|
|
6
|
+
Schema.Struct({ assertionResults: Schema.Array(Schema.Unknown), name: Schema.String, status: Schema.Literals(["failed", "passed"]) }),
|
|
7
|
+
[ExtraFields],
|
|
8
|
+
);
|
|
9
|
+
|
|
10
|
+
export const writeTimedReport = Effect.fn("VitestRerun.writeTimedReport")(function* (path: string, durations: readonly number[]) {
|
|
11
|
+
const fs = yield* FileSystem.FileSystem;
|
|
12
|
+
const contents = yield* fs.readFileString(path);
|
|
13
|
+
const Report = Schema.StructWithRest(
|
|
14
|
+
Schema.Struct({ testResults: Schema.Array(TestResult).check(Schema.isBetweenLength(durations.length, durations.length)) }),
|
|
15
|
+
[ExtraFields],
|
|
16
|
+
);
|
|
17
|
+
const decodeReport = Schema.decodeUnknownEffect(Schema.fromJsonString(Report));
|
|
18
|
+
const report = yield* decodeReport(contents).pipe(Effect.mapError(failWith(`Could not decode timed report ${path}`)));
|
|
19
|
+
const testResults = report.testResults.map((result, index) => ({ ...result, durationMs: durations[index] }));
|
|
20
|
+
yield* fs.writeFileString(path, JSON.stringify({ ...report, testResults }));
|
|
21
|
+
});
|
package/src/rerun.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { join } from "node:path";
|
|
2
2
|
import process from "node:process";
|
|
3
3
|
import { fileURLToPath } from "node:url";
|
|
4
4
|
import { Console, Effect, FileSystem, Option } from "effect";
|
|
@@ -7,7 +7,7 @@ import { ATTEMPT_REPORT, attemptPaths, reportPaths } from "#internal/reportPaths
|
|
|
7
7
|
import { failedFiles, readSnapshot } from "#internal/snapshot.ts";
|
|
8
8
|
import type { RerunOptions } from "#options.ts";
|
|
9
9
|
|
|
10
|
-
const ATTEMPT_MODULE = fileURLToPath(
|
|
10
|
+
const ATTEMPT_MODULE = fileURLToPath(import.meta.resolve("#internal/attempt.ts"));
|
|
11
11
|
|
|
12
12
|
const removeReports = Effect.fn("VitestRerun.removeReports")(function* (outputDir: string) {
|
|
13
13
|
const fs = yield* FileSystem.FileSystem;
|
|
@@ -48,17 +48,24 @@ const keepFirstAttempt = Effect.fn("VitestRerun.keepFirstAttempt")(function* (ou
|
|
|
48
48
|
yield* fs.copyFile(final.junit, first.junit);
|
|
49
49
|
});
|
|
50
50
|
|
|
51
|
+
const removeSnapshots = Effect.fn("VitestRerun.removeSnapshots")(function* (outputDir: string, attempts: number) {
|
|
52
|
+
const fs = yield* FileSystem.FileSystem;
|
|
53
|
+
for (let attempt = 1; attempt <= attempts; attempt += 1) {
|
|
54
|
+
yield* fs.remove(attemptPaths(outputDir, attempt).snapshot, { force: true });
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
|
|
51
58
|
export const rerun = Effect.fn("VitestRerun.rerun")(function* (options: RerunOptions) {
|
|
52
59
|
yield* removeReports(options.outputDir);
|
|
53
|
-
let
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
}
|
|
58
|
-
if (attempt === 1) {
|
|
60
|
+
let attempts = 1;
|
|
61
|
+
let code = yield* spawnAttempt(options, attempts);
|
|
62
|
+
while (attempts <= options.reruns && Option.exists(code, (status) => status !== 0) && (yield* rerunnable(options.outputDir, attempts))) {
|
|
63
|
+
if (attempts === 1) {
|
|
59
64
|
yield* keepFirstAttempt(options.outputDir);
|
|
60
65
|
}
|
|
61
|
-
|
|
66
|
+
attempts += 1;
|
|
67
|
+
code = yield* spawnAttempt(options, attempts);
|
|
62
68
|
}
|
|
69
|
+
yield* removeSnapshots(options.outputDir, attempts);
|
|
63
70
|
return Option.getOrElse(code, () => 1);
|
|
64
71
|
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"TimedJsonReporter.d.ts","sourceRoot":"","sources":["../../src/internal/TimedJsonReporter.ts"],"names":[],"mappings":"AACA,OAAO,EAA8B,YAAY,EAAE,KAAK,UAAU,EAAE,MAAM,aAAa,CAAC;AAExF,qBAAa,iBAAkB,SAAQ,YAAY;IACnC,YAAY,CAAC,OAAO,EAAE,SAAS,UAAU,EAAE,iBAWzD;CACD"}
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import { readFileSync, writeFileSync } from "node:fs";
|
|
2
|
-
import { experimental_getRunnerTask, JsonReporter } from "vitest/node";
|
|
3
|
-
export class TimedJsonReporter extends JsonReporter {
|
|
4
|
-
async onTestRunEnd(modules) {
|
|
5
|
-
await super.onTestRunEnd([...modules]);
|
|
6
|
-
const path = this.options.outputFile;
|
|
7
|
-
if (path === undefined) {
|
|
8
|
-
throw new Error("Timed JSON reports require an output file");
|
|
9
|
-
}
|
|
10
|
-
const report = JSON.parse(readFileSync(path, "utf8"));
|
|
11
|
-
for (const [index, module] of modules.entries()) {
|
|
12
|
-
report.testResults[index].durationMs = experimental_getRunnerTask(module).result?.duration ?? 0;
|
|
13
|
-
}
|
|
14
|
-
writeFileSync(path, JSON.stringify(report));
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
//# sourceMappingURL=TimedJsonReporter.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"TimedJsonReporter.js","sourceRoot":"","sources":["../../src/internal/TimedJsonReporter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AACtD,OAAO,EAAE,0BAA0B,EAAE,YAAY,EAAmB,MAAM,aAAa,CAAC;AAExF,MAAM,OAAO,iBAAkB,SAAQ,YAAY;IACzC,KAAK,CAAC,YAAY,CAAC,OAA8B;QACzD,MAAM,KAAK,CAAC,YAAY,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;QACvC,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC;QACrC,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;YACxB,MAAM,IAAI,KAAK,CAAC,2CAA2C,CAAC,CAAC;QAC9D,CAAC;QACD,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC;QACtD,KAAK,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,IAAI,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC;YACjD,MAAM,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,UAAU,GAAG,0BAA0B,CAAC,MAAM,CAAC,CAAC,MAAM,EAAE,QAAQ,IAAI,CAAC,CAAC;QACjG,CAAC;QACD,aAAa,CAAC,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC;IAC7C,CAAC;CACD"}
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import { readFileSync, writeFileSync } from "node:fs";
|
|
2
|
-
import { experimental_getRunnerTask, JsonReporter, type TestModule } from "vitest/node";
|
|
3
|
-
|
|
4
|
-
export class TimedJsonReporter extends JsonReporter {
|
|
5
|
-
override async onTestRunEnd(modules: readonly TestModule[]) {
|
|
6
|
-
await super.onTestRunEnd([...modules]);
|
|
7
|
-
const path = this.options.outputFile;
|
|
8
|
-
if (path === undefined) {
|
|
9
|
-
throw new Error("Timed JSON reports require an output file");
|
|
10
|
-
}
|
|
11
|
-
const report = JSON.parse(readFileSync(path, "utf8"));
|
|
12
|
-
for (const [index, module] of modules.entries()) {
|
|
13
|
-
report.testResults[index].durationMs = experimental_getRunnerTask(module).result?.duration ?? 0;
|
|
14
|
-
}
|
|
15
|
-
writeFileSync(path, JSON.stringify(report));
|
|
16
|
-
}
|
|
17
|
-
}
|
|
File without changes
|