@vitest-agent/plugin 2.5.4 → 2.5.6
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/index.d.ts +67 -31
- package/layers/CoverageAnalyzerLive.js +1 -0
- package/package.json +6 -6
- package/plugin.js +39 -1
- package/reporter.js +83 -9
- package/utils/discover-projects.js +1 -1
- package/utils/discover-strategy.js +1 -1
- package/utils/find-test-files.js +1 -1
- package/utils/is-partial-run.js +26 -0
- package/utils/is-test-shaped-package.js +1 -1
- package/utils/process-failure.js +1 -1
- package/utils/resolve-coverage-dir-isolation.js +44 -0
- package/utils/run-script-lock.js +2 -2
package/index.d.ts
CHANGED
|
@@ -17,7 +17,7 @@ type TagOptions = Omit<TestTagDefinition, "name">;
|
|
|
17
17
|
* A validated Vitest tag with its `name` string and a `TestTagDefinition` for registration.
|
|
18
18
|
* @public
|
|
19
19
|
*/
|
|
20
|
-
declare class Tag {
|
|
20
|
+
export declare class Tag {
|
|
21
21
|
/** The tag name string (validated on construction). */
|
|
22
22
|
readonly name: string;
|
|
23
23
|
/** The full `TestTagDefinition` object to pass to Vitest's `test.tags` config. */
|
|
@@ -109,7 +109,7 @@ interface WalkerEntryStat {
|
|
|
109
109
|
* an explicit port.
|
|
110
110
|
* @public
|
|
111
111
|
*/
|
|
112
|
-
declare const nodeWalkerFs: WalkerFileSystem;
|
|
112
|
+
export declare const nodeWalkerFs: WalkerFileSystem;
|
|
113
113
|
//#endregion
|
|
114
114
|
//#region src/utils/discover-strategy.d.ts
|
|
115
115
|
/**
|
|
@@ -209,7 +209,7 @@ interface DiscoverStrategyExtendOptions {
|
|
|
209
209
|
* the built-in unit/int/e2e heuristics.
|
|
210
210
|
* @public
|
|
211
211
|
*/
|
|
212
|
-
declare abstract class DiscoverStrategy {
|
|
212
|
+
export declare abstract class DiscoverStrategy {
|
|
213
213
|
abstract readonly tags: ReadonlyArray<Tag>;
|
|
214
214
|
abstract get tagDefinitions(): ReadonlyArray<TestTagDefinition>;
|
|
215
215
|
abstract buildProject(input: DiscoverInput): Promise<TestProjectInlineConfiguration | null>;
|
|
@@ -226,7 +226,7 @@ declare abstract class DiscoverStrategy {
|
|
|
226
226
|
* (`.int.test.*` → `"int"`, `.e2e.test.*` → `"e2e"`, everything else → `"unit"`).
|
|
227
227
|
* @public
|
|
228
228
|
*/
|
|
229
|
-
declare class DefaultDiscoverStrategy extends DiscoverStrategy {
|
|
229
|
+
export declare class DefaultDiscoverStrategy extends DiscoverStrategy {
|
|
230
230
|
readonly tags: ReadonlyArray<Tag>;
|
|
231
231
|
get tagDefinitions(): ReadonlyArray<TestTagDefinition>;
|
|
232
232
|
classify(ctx: {
|
|
@@ -297,7 +297,7 @@ interface AgentPluginConstructorOptions extends AgentPluginOptions {
|
|
|
297
297
|
*
|
|
298
298
|
* @public
|
|
299
299
|
*/
|
|
300
|
-
declare const CURRENT_PLUGIN_VERSION: string;
|
|
300
|
+
export declare const CURRENT_PLUGIN_VERSION: string;
|
|
301
301
|
/**
|
|
302
302
|
* Vitest plugin that injects `AgentReporter` into the reporter chain.
|
|
303
303
|
*
|
|
@@ -307,7 +307,7 @@ declare const CURRENT_PLUGIN_VERSION: string;
|
|
|
307
307
|
*
|
|
308
308
|
* @public
|
|
309
309
|
*/
|
|
310
|
-
declare function AgentPlugin(options?: AgentPluginConstructorOptions, _layer?: Layer.Layer<EnvironmentDetector>): {
|
|
310
|
+
export declare function AgentPlugin(options?: AgentPluginConstructorOptions, _layer?: Layer.Layer<EnvironmentDetector>): {
|
|
311
311
|
name: "vitest-agent";
|
|
312
312
|
configResolved: (resolvedConfig: {
|
|
313
313
|
logger: {
|
|
@@ -378,7 +378,7 @@ interface DiscoverBuilder extends PromiseLike<DiscoverResult> {
|
|
|
378
378
|
* Exposes coverage-level preset maps, auto-update tolerance functions, and the `discover` thenable builder.
|
|
379
379
|
* @public
|
|
380
380
|
*/
|
|
381
|
-
declare namespace AgentPlugin {
|
|
381
|
+
export declare namespace AgentPlugin {
|
|
382
382
|
const COVERAGE_LEVELS: Readonly<Record<CoverageLevelName$1, CoverageLevelPreset>>;
|
|
383
383
|
const COVERAGE_LEVELS_PER_FILE: Readonly<Record<CoverageLevelName$1, CoverageLevelPreset>>;
|
|
384
384
|
/**
|
|
@@ -576,7 +576,7 @@ interface AgentReporterConstructorOptions extends AgentReporterOptions {
|
|
|
576
576
|
* @see {@link https://vitest.dev/api/advanced/reporters.html | Vitest Reporter API}
|
|
577
577
|
* @public
|
|
578
578
|
*/
|
|
579
|
-
declare class AgentReporter {
|
|
579
|
+
export declare class AgentReporter {
|
|
580
580
|
private options;
|
|
581
581
|
private dbPath;
|
|
582
582
|
/**
|
|
@@ -643,6 +643,35 @@ declare class AgentReporter {
|
|
|
643
643
|
* @internal
|
|
644
644
|
*/
|
|
645
645
|
private hookStartedAt;
|
|
646
|
+
/**
|
|
647
|
+
* Count of test specifications Vitest started for the current run,
|
|
648
|
+
* captured from `onTestRunStart`'s `specifications` argument. Used
|
|
649
|
+
* alongside a fresh `globTestSpecifications()` total in `onTestRunEnd`
|
|
650
|
+
* as one of `isPartialRun`'s signals (issue #160 gap 2) — a tags-only
|
|
651
|
+
* `run_tests` filter narrows the run without setting `filenamePattern`
|
|
652
|
+
* or `projectFilter`, so the spec-count comparison is the only signal
|
|
653
|
+
* that catches it. `undefined` when `onTestRunStart` never fired
|
|
654
|
+
* (tests invoking `onTestRunEnd` directly); `onTestRunEnd` falls back
|
|
655
|
+
* to the executed module count in that case.
|
|
656
|
+
*
|
|
657
|
+
* @internal
|
|
658
|
+
*/
|
|
659
|
+
private startedSpecCount;
|
|
660
|
+
/**
|
|
661
|
+
* Original values of coverage-threshold keys deleted from
|
|
662
|
+
* `vitest.coverageProvider.options.thresholds` while neutralizing a
|
|
663
|
+
* partial run (issue #160). In `run` mode Vitest re-initializes the
|
|
664
|
+
* provider on every `vitest.start`, so the snapshot is moot — but in
|
|
665
|
+
* watch mode the provider is created once and scoped reruns go through
|
|
666
|
+
* `rerunFiles` without re-initializing it, so a deleted key would stay
|
|
667
|
+
* gone for the rest of the watch session. `onTestRunStart` restores
|
|
668
|
+
* these keys (only if still absent — a legitimately re-initialized
|
|
669
|
+
* provider is left alone) and clears the map. Empty when the last run
|
|
670
|
+
* was not partial.
|
|
671
|
+
*
|
|
672
|
+
* @internal
|
|
673
|
+
*/
|
|
674
|
+
private neutralizedThresholdSnapshot;
|
|
646
675
|
constructor(options?: AgentReporterConstructorOptions);
|
|
647
676
|
/**
|
|
648
677
|
* The resolved reporter config built at construction time. Exposed for
|
|
@@ -1049,7 +1078,7 @@ interface DiscoverProjectsOptions {
|
|
|
1049
1078
|
* @returns Resolved projects and tag definitions
|
|
1050
1079
|
* @public
|
|
1051
1080
|
*/
|
|
1052
|
-
declare function discoverProjects(options?: DiscoverProjectsOptions): Promise<DiscoverProjectsResult>;
|
|
1081
|
+
export declare function discoverProjects(options?: DiscoverProjectsOptions): Promise<DiscoverProjectsResult>;
|
|
1053
1082
|
//#endregion
|
|
1054
1083
|
//#region src/utils/classify-helpers.d.ts
|
|
1055
1084
|
/**
|
|
@@ -1066,7 +1095,7 @@ declare function discoverProjects(options?: DiscoverProjectsOptions): Promise<Di
|
|
|
1066
1095
|
* No match returns an empty array.
|
|
1067
1096
|
* @public
|
|
1068
1097
|
*/
|
|
1069
|
-
declare function classifyByFilename(suffixMap: Record<string, ReadonlyArray<string>> | ReadonlyArray<readonly [RegExp, ReadonlyArray<string>]>): ClassifyFn;
|
|
1098
|
+
export declare function classifyByFilename(suffixMap: Record<string, ReadonlyArray<string>> | ReadonlyArray<readonly [RegExp, ReadonlyArray<string>]>): ClassifyFn;
|
|
1070
1099
|
/**
|
|
1071
1100
|
* Creates a ClassifyFn that maps directory segment paths to tag arrays.
|
|
1072
1101
|
*
|
|
@@ -1078,7 +1107,7 @@ declare function classifyByFilename(suffixMap: Record<string, ReadonlyArray<stri
|
|
|
1078
1107
|
* No match returns `[]`.
|
|
1079
1108
|
* @public
|
|
1080
1109
|
*/
|
|
1081
|
-
declare function classifyByDirectory(dirMap: Record<string, ReadonlyArray<string>>): ClassifyFn;
|
|
1110
|
+
export declare function classifyByDirectory(dirMap: Record<string, ReadonlyArray<string>>): ClassifyFn;
|
|
1082
1111
|
/**
|
|
1083
1112
|
* Composes multiple `ClassifyFn` values into one. Each classifier is called with
|
|
1084
1113
|
* the same context; results are concatenated in order and deduplicated by tag
|
|
@@ -1086,7 +1115,7 @@ declare function classifyByDirectory(dirMap: Record<string, ReadonlyArray<string
|
|
|
1086
1115
|
* returns `[]`.
|
|
1087
1116
|
* @public
|
|
1088
1117
|
*/
|
|
1089
|
-
declare function combineClassifiers(...fns: ReadonlyArray<ClassifyFn>): ClassifyFn;
|
|
1118
|
+
export declare function combineClassifiers(...fns: ReadonlyArray<ClassifyFn>): ClassifyFn;
|
|
1090
1119
|
//#endregion
|
|
1091
1120
|
//#region src/utils/find-test-files.d.ts
|
|
1092
1121
|
/**
|
|
@@ -1110,14 +1139,14 @@ declare function combineClassifiers(...fns: ReadonlyArray<ClassifyFn>): Classify
|
|
|
1110
1139
|
* @returns Absolute paths of matched test files
|
|
1111
1140
|
* @public
|
|
1112
1141
|
*/
|
|
1113
|
-
declare function findTestFiles(dir: string, patterns: ReadonlyArray<string>, fs?: WalkerFileSystem): Promise<ReadonlyArray<string>>;
|
|
1142
|
+
export declare function findTestFiles(dir: string, patterns: ReadonlyArray<string>, fs?: WalkerFileSystem): Promise<ReadonlyArray<string>>;
|
|
1114
1143
|
//#endregion
|
|
1115
1144
|
//#region src/layers/ReporterLive.d.ts
|
|
1116
1145
|
/**
|
|
1117
1146
|
* Composition layer for a single `AgentReporter` run. Wires SQLite, migrations, and all service layers.
|
|
1118
1147
|
* @public
|
|
1119
1148
|
*/
|
|
1120
|
-
declare const ReporterLive: (dbPath: string, logLevel?: LogLevel.LogLevel, logFile?: string) => Layer.Layer<CoverageAnalyzer | import("@vitest-agent/sdk").DataReader | import("@vitest-agent/sdk").DataStore | import("@vitest-agent/sdk").DetailResolver | import("@vitest-agent/sdk").EnvironmentDetector | import("@vitest-agent/sdk").ExecutorResolver | import("@vitest-agent/sdk").FormatSelector | import("@vitest-agent/sdk").HistoryTracker | import("@vitest-agent/sdk").OutputRenderer | import("effect/unstable/sql/SqlClient").SqlClient | import("@effect/sql-sqlite-node/SqliteClient").SqliteClient | NodeServices.NodeServices, SqliteMigrator.MigrationError | import("effect/unstable/sql/SqlError").SqlError, never>;
|
|
1149
|
+
export declare const ReporterLive: (dbPath: string, logLevel?: LogLevel.LogLevel, logFile?: string) => Layer.Layer<CoverageAnalyzer | import("@vitest-agent/sdk").DataReader | import("@vitest-agent/sdk").DataStore | import("@vitest-agent/sdk").DetailResolver | import("@vitest-agent/sdk").EnvironmentDetector | import("@vitest-agent/sdk").ExecutorResolver | import("@vitest-agent/sdk").FormatSelector | import("@vitest-agent/sdk").HistoryTracker | import("@vitest-agent/sdk").OutputRenderer | import("effect/unstable/sql/SqlClient").SqlClient | import("@effect/sql-sqlite-node/SqliteClient").SqliteClient | NodeServices.NodeServices, SqliteMigrator.MigrationError | import("effect/unstable/sql/SqlError").SqlError, never>;
|
|
1121
1150
|
//#endregion
|
|
1122
1151
|
//#region src/services/CoverageAnalyzer.d.ts
|
|
1123
1152
|
/**
|
|
@@ -1134,6 +1163,13 @@ interface CoverageOptions {
|
|
|
1134
1163
|
readonly baselines?: CoverageBaselines;
|
|
1135
1164
|
/** When true, include files with zero coverage rather than omitting them. */
|
|
1136
1165
|
readonly includeBareZero: boolean;
|
|
1166
|
+
/**
|
|
1167
|
+
* Total test-file count for the project, when known (issue #160 gap 1).
|
|
1168
|
+
* Only meaningful on a scoped run — threaded onto the returned
|
|
1169
|
+
* `CoverageReport.totalFiles` so the scoped-coverage note can render
|
|
1170
|
+
* "N of M test files" instead of just "N".
|
|
1171
|
+
*/
|
|
1172
|
+
readonly totalFiles?: number;
|
|
1137
1173
|
}
|
|
1138
1174
|
declare const CoverageAnalyzer_base: Context.ServiceClass<CoverageAnalyzer, "vitest-agent/CoverageAnalyzer", {
|
|
1139
1175
|
readonly process: (coverage: unknown, options: CoverageOptions) => Effect.Effect<Option.Option<CoverageReport>>;
|
|
@@ -1143,21 +1179,21 @@ declare const CoverageAnalyzer_base: Context.ServiceClass<CoverageAnalyzer, "vit
|
|
|
1143
1179
|
* Effect service for processing istanbul coverage maps into structured reports.
|
|
1144
1180
|
* @public
|
|
1145
1181
|
*/
|
|
1146
|
-
declare class CoverageAnalyzer extends CoverageAnalyzer_base {}
|
|
1182
|
+
export declare class CoverageAnalyzer extends CoverageAnalyzer_base {}
|
|
1147
1183
|
//#endregion
|
|
1148
1184
|
//#region src/layers/CoverageAnalyzerLive.d.ts
|
|
1149
1185
|
/**
|
|
1150
1186
|
* Live implementation of the CoverageAnalyzer service backed by istanbul.
|
|
1151
1187
|
* @public
|
|
1152
1188
|
*/
|
|
1153
|
-
declare const CoverageAnalyzerLive: Layer.Layer<CoverageAnalyzer>;
|
|
1189
|
+
export declare const CoverageAnalyzerLive: Layer.Layer<CoverageAnalyzer>;
|
|
1154
1190
|
//#endregion
|
|
1155
1191
|
//#region src/layers/CoverageAnalyzerTest.d.ts
|
|
1156
1192
|
/**
|
|
1157
1193
|
* Test-double layer factory for CoverageAnalyzer. Pass a pre-built `CoverageReport` to inject.
|
|
1158
1194
|
* @public
|
|
1159
1195
|
*/
|
|
1160
|
-
declare const CoverageAnalyzerTest: {
|
|
1196
|
+
export declare const CoverageAnalyzerTest: {
|
|
1161
1197
|
readonly layer: (data?: CoverageReport) => Layer.Layer<CoverageAnalyzer>;
|
|
1162
1198
|
};
|
|
1163
1199
|
//#endregion
|
|
@@ -1214,21 +1250,21 @@ declare const ConfigValidation_base: Context.ServiceClass<ConfigValidation, "vit
|
|
|
1214
1250
|
* Effect service for validating Vitest + plugin coverage configuration.
|
|
1215
1251
|
* @public
|
|
1216
1252
|
*/
|
|
1217
|
-
declare class ConfigValidation extends ConfigValidation_base {}
|
|
1253
|
+
export declare class ConfigValidation extends ConfigValidation_base {}
|
|
1218
1254
|
//#endregion
|
|
1219
1255
|
//#region src/layers/ConfigValidationLive.d.ts
|
|
1220
1256
|
/**
|
|
1221
1257
|
* Live implementation of the ConfigValidation service running the built-in rule registry.
|
|
1222
1258
|
* @public
|
|
1223
1259
|
*/
|
|
1224
|
-
declare const ConfigValidationLive: Layer.Layer<ConfigValidation>;
|
|
1260
|
+
export declare const ConfigValidationLive: Layer.Layer<ConfigValidation>;
|
|
1225
1261
|
//#endregion
|
|
1226
1262
|
//#region src/layers/ConfigValidationTest.d.ts
|
|
1227
1263
|
/**
|
|
1228
1264
|
* Test-double layer factory for ConfigValidation. Pass a pre-built `ValidationResult` to inject.
|
|
1229
1265
|
* @public
|
|
1230
1266
|
*/
|
|
1231
|
-
declare const ConfigValidationTest: {
|
|
1267
|
+
export declare const ConfigValidationTest: {
|
|
1232
1268
|
readonly layer: (override?: ValidationResult) => Layer.Layer<ConfigValidation>;
|
|
1233
1269
|
};
|
|
1234
1270
|
//#endregion
|
|
@@ -1239,7 +1275,7 @@ declare const ConfigValidationTest: {
|
|
|
1239
1275
|
* @returns A filtered map of relevant environment variable keys and values
|
|
1240
1276
|
* @public
|
|
1241
1277
|
*/
|
|
1242
|
-
declare function captureEnvVars(env: Record<string, string | undefined>): Record<string, string>;
|
|
1278
|
+
export declare function captureEnvVars(env: Record<string, string | undefined>): Record<string, string>;
|
|
1243
1279
|
//#endregion
|
|
1244
1280
|
//#region src/utils/capture-settings.d.ts
|
|
1245
1281
|
/**
|
|
@@ -1249,14 +1285,14 @@ declare function captureEnvVars(env: Record<string, string | undefined>): Record
|
|
|
1249
1285
|
* @returns A `SettingsInput` ready for persistence
|
|
1250
1286
|
* @public
|
|
1251
1287
|
*/
|
|
1252
|
-
declare function captureSettings(config: Record<string, unknown>, vitestVersion: string): SettingsInput;
|
|
1288
|
+
export declare function captureSettings(config: Record<string, unknown>, vitestVersion: string): SettingsInput;
|
|
1253
1289
|
/**
|
|
1254
1290
|
* Compute a stable SHA-256 hash of a settings record for change detection.
|
|
1255
1291
|
* @param settings - The settings record to hash (keys are sorted for stability)
|
|
1256
1292
|
* @returns A hex-encoded SHA-256 digest
|
|
1257
1293
|
* @public
|
|
1258
1294
|
*/
|
|
1259
|
-
declare function hashSettings(settings: Record<string, unknown>): string;
|
|
1295
|
+
export declare function hashSettings(settings: Record<string, unknown>): string;
|
|
1260
1296
|
//#endregion
|
|
1261
1297
|
//#region src/utils/process-failure.d.ts
|
|
1262
1298
|
/**
|
|
@@ -1292,7 +1328,7 @@ interface VitestErrorLike {
|
|
|
1292
1328
|
* still be populated even when the signature is null.
|
|
1293
1329
|
* @public
|
|
1294
1330
|
*/
|
|
1295
|
-
declare const processFailure: (error: VitestErrorLike) => {
|
|
1331
|
+
export declare const processFailure: (error: VitestErrorLike) => {
|
|
1296
1332
|
frames: ReadonlyArray<StackFrameInput>;
|
|
1297
1333
|
signatureHash: string | null;
|
|
1298
1334
|
};
|
|
@@ -1309,7 +1345,7 @@ type VitestThresholdsInput = Record<string, unknown>;
|
|
|
1309
1345
|
* @returns Normalized thresholds with global, perFile, and pattern entries
|
|
1310
1346
|
* @public
|
|
1311
1347
|
*/
|
|
1312
|
-
declare function resolveThresholds(input: VitestThresholdsInput | undefined): ResolvedThresholds;
|
|
1348
|
+
export declare function resolveThresholds(input: VitestThresholdsInput | undefined): ResolvedThresholds;
|
|
1313
1349
|
//#endregion
|
|
1314
1350
|
//#region src/utils/strip-console-reporters.d.ts
|
|
1315
1351
|
/**
|
|
@@ -1324,7 +1360,7 @@ declare function resolveThresholds(input: VitestThresholdsInput | undefined): Re
|
|
|
1324
1360
|
* @see {@link https://vitest.dev/api/advanced/reporters.html | Vitest Reporter docs}
|
|
1325
1361
|
* @internal
|
|
1326
1362
|
*/
|
|
1327
|
-
declare const CONSOLE_REPORTERS: Set<string>;
|
|
1363
|
+
export declare const CONSOLE_REPORTERS: Set<string>;
|
|
1328
1364
|
/**
|
|
1329
1365
|
* Filter out built-in console reporters from a Vitest reporters array.
|
|
1330
1366
|
*
|
|
@@ -1337,19 +1373,19 @@ declare const CONSOLE_REPORTERS: Set<string>;
|
|
|
1337
1373
|
*
|
|
1338
1374
|
* @internal
|
|
1339
1375
|
*/
|
|
1340
|
-
declare function stripConsoleReporters(reporters: unknown[]): unknown[];
|
|
1376
|
+
export declare function stripConsoleReporters(reporters: unknown[]): unknown[];
|
|
1341
1377
|
//#endregion
|
|
1342
1378
|
//#region src/index.d.ts
|
|
1343
1379
|
/** Preset map for coverage levels without per-file enforcement. Mirrors `AgentPlugin.COVERAGE_LEVELS`. @public */
|
|
1344
|
-
declare const COVERAGE_LEVELS: Readonly<Record<import("@vitest-agent/sdk").CoverageLevelName, CoverageLevelPreset>>;
|
|
1380
|
+
export declare const COVERAGE_LEVELS: Readonly<Record<import("@vitest-agent/sdk").CoverageLevelName, CoverageLevelPreset>>;
|
|
1345
1381
|
/** Preset map for coverage levels with per-file enforcement. Mirrors `AgentPlugin.COVERAGE_LEVELS_PER_FILE`. @public */
|
|
1346
|
-
declare const COVERAGE_LEVELS_PER_FILE: Readonly<Record<import("@vitest-agent/sdk").CoverageLevelName, CoverageLevelPreset>>;
|
|
1382
|
+
export declare const COVERAGE_LEVELS_PER_FILE: Readonly<Record<import("@vitest-agent/sdk").CoverageLevelName, CoverageLevelPreset>>;
|
|
1347
1383
|
/** Auto-update tolerance functions for `coverage.thresholds.autoUpdate`. Mirrors `AgentPlugin.COVERAGE_AUTOUPDATE`. @public */
|
|
1348
|
-
declare const COVERAGE_AUTOUPDATE: Readonly<{
|
|
1384
|
+
export declare const COVERAGE_AUTOUPDATE: Readonly<{
|
|
1349
1385
|
standard: (n: number) => number;
|
|
1350
1386
|
strict: (n: number) => number;
|
|
1351
1387
|
lenient: (n: number) => number;
|
|
1352
1388
|
}>;
|
|
1353
1389
|
//#endregion
|
|
1354
|
-
export { type AddProjectInput,
|
|
1390
|
+
export { type AddProjectInput, type AgentPluginConstructorOptions, type AgentReporterConstructorOptions, type ClassifyContext, type ClassifyFn, type CoverageInput, CoverageLevel, type CoverageLevelName, type CoverageLevelPreset, type CoverageOptions, type DiscoverBuilder, type DiscoverInput, type PackageJson as DiscoverPackageJson, type DiscoverProjectsOptions, type DiscoverProjectsResult, type DiscoverResult, type DiscoverStrategyCreateOptions, type DiscoverStrategyExtendOptions, type InjectTagsResult, type ModuleInfo, type TagOptions, type ValidationError, type ValidationInfo, type ValidationInput, type ValidationResult, type ValidationWarning, type VitestErrorLike, type VitestStackFrameLike, type VitestThresholdsInput, type WalkerEntry, type WalkerEntryStat, type WalkerFileSystem, resolveCoverageInput, validateCoverageConfig };
|
|
1355
1391
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -112,6 +112,7 @@ function processCoverageInternal(coverageMap, options, testedFiles) {
|
|
|
112
112
|
} } : {},
|
|
113
113
|
scoped,
|
|
114
114
|
...scoped && testedFiles ? { scopedFiles: [...testedFiles] } : {},
|
|
115
|
+
...scoped && options.totalFiles !== void 0 ? { totalFiles: options.totalFiles } : {},
|
|
115
116
|
lowCoverage,
|
|
116
117
|
lowCoverageFiles: lowCoverage.map((f) => f.file),
|
|
117
118
|
...options.targets ? {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vitest-agent/plugin",
|
|
3
|
-
"version": "2.5.
|
|
3
|
+
"version": "2.5.6",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Vitest plugin for the vitest-agent ecosystem: owns persistence, classification, baselines, trends, and dispatches rendering to a configurable reporter.",
|
|
6
6
|
"keywords": [
|
|
@@ -41,11 +41,11 @@
|
|
|
41
41
|
"dependencies": {
|
|
42
42
|
"@effect/platform-node": "4.0.0-rc.109",
|
|
43
43
|
"@effect/sql-sqlite-node": "4.0.0-rc.109",
|
|
44
|
-
"@effected/workspaces": "^0.
|
|
45
|
-
"@vitest-agent/cli": "2.2.
|
|
46
|
-
"@vitest-agent/mcp": "2.4.
|
|
47
|
-
"@vitest-agent/reporter": "2.2.
|
|
48
|
-
"@vitest-agent/sdk": "2.
|
|
44
|
+
"@effected/workspaces": "^0.19.0",
|
|
45
|
+
"@vitest-agent/cli": "2.2.14",
|
|
46
|
+
"@vitest-agent/mcp": "2.4.14",
|
|
47
|
+
"@vitest-agent/reporter": "2.2.3",
|
|
48
|
+
"@vitest-agent/sdk": "2.5.0",
|
|
49
49
|
"effect": "4.0.0-rc.109",
|
|
50
50
|
"magic-string": "^1.2.3"
|
|
51
51
|
},
|
package/plugin.js
CHANGED
|
@@ -8,9 +8,13 @@ import { discoverProjects } from "./utils/discover-projects.js";
|
|
|
8
8
|
import { ensureGithubActionsReporter } from "./utils/ensure-github-reporter.js";
|
|
9
9
|
import { injectTags } from "./utils/inject-tags.js";
|
|
10
10
|
import { isBenignViteSourceMapWarning } from "./utils/is-benign-vite-source-map-warning.js";
|
|
11
|
+
import { resolveCoverageDirIsolation } from "./utils/resolve-coverage-dir-isolation.js";
|
|
11
12
|
import { DEFAULT_BUILT_RECENTLY_MS, DEFAULT_LOCK_STALE_MS, DEFAULT_LOCK_WAIT_TIMEOUT_MS, acquireRunScriptLock, markRunScriptDone, parseLockTimingOverride, releaseRunScriptLock } from "./utils/run-script-lock.js";
|
|
12
13
|
import { stripConsoleReporters } from "./utils/strip-console-reporters.js";
|
|
13
14
|
import { execSync } from "node:child_process";
|
|
15
|
+
import { mkdtempSync, rmSync } from "node:fs";
|
|
16
|
+
import { tmpdir } from "node:os";
|
|
17
|
+
import { join } from "node:path";
|
|
14
18
|
import { AgentConsoleMode, CiConsoleMode, CoverageLevel, EnvironmentDetector, EnvironmentDetectorLive, HumanConsoleMode, SRC_DIR, TEST_DIR, formatFatalError, isTestFileName, resolveLogLevel } from "@vitest-agent/sdk";
|
|
15
19
|
import { Effect, Schema } from "effect";
|
|
16
20
|
|
|
@@ -94,6 +98,15 @@ function resolveFormat(mode) {
|
|
|
94
98
|
*/
|
|
95
99
|
const aggregatedReporterByVitest = /* @__PURE__ */ new WeakSet();
|
|
96
100
|
/**
|
|
101
|
+
* Guards the coverage.reportsDirectory isolation decision (issue #194) to
|
|
102
|
+
* run at most once per Vitest run — `configureVitest` fires once per
|
|
103
|
+
* project, but `coverage.reportsDirectory` is root-level config shared by
|
|
104
|
+
* every project in that run.
|
|
105
|
+
*
|
|
106
|
+
* @internal
|
|
107
|
+
*/
|
|
108
|
+
const coverageDirDecidedByVitest = /* @__PURE__ */ new WeakSet();
|
|
109
|
+
/**
|
|
97
110
|
* The version of this package, inlined at build time from
|
|
98
111
|
* `package.json#version` via rslib-builder's `__PACKAGE_VERSION__` substitution.
|
|
99
112
|
* Re-exported from the package barrel as the public symbol; defined here so
|
|
@@ -101,7 +114,7 @@ const aggregatedReporterByVitest = /* @__PURE__ */ new WeakSet();
|
|
|
101
114
|
*
|
|
102
115
|
* @public
|
|
103
116
|
*/
|
|
104
|
-
const CURRENT_PLUGIN_VERSION = "2.5.
|
|
117
|
+
const CURRENT_PLUGIN_VERSION = "2.5.6";
|
|
105
118
|
const TEST_FILE_DIR_RE = new RegExp(`/(?:${SRC_DIR}|${TEST_DIR})/`);
|
|
106
119
|
const isTestFile = (id) => isTestFileName(id) && TEST_FILE_DIR_RE.test(id);
|
|
107
120
|
/**
|
|
@@ -203,6 +216,31 @@ function AgentPlugin(options = {}, _layer) {
|
|
|
203
216
|
const rawTargets = options.coverageTargets;
|
|
204
217
|
const coverageTargets = rawTargets ? resolveThresholds(rawTargets) : void 0;
|
|
205
218
|
const coverageMode = coverageConfig?.enabled === false ? "ui-only" : "full";
|
|
219
|
+
if (coverageConfig && !coverageDirDecidedByVitest.has(vitest)) {
|
|
220
|
+
coverageDirDecidedByVitest.add(vitest);
|
|
221
|
+
const dirDecision = resolveCoverageDirIsolation({
|
|
222
|
+
executor,
|
|
223
|
+
coverageEnabled: coverageMode === "full",
|
|
224
|
+
env: process.env,
|
|
225
|
+
configured: coverageConfig.reportsDirectory
|
|
226
|
+
});
|
|
227
|
+
if (dirDecision.kind === "isolate") {
|
|
228
|
+
const isolatedDir = mkdtempSync(join(tmpdir(), "vitest-agent-cov-"));
|
|
229
|
+
log("isolating coverage.reportsDirectory ->", isolatedDir);
|
|
230
|
+
coverageConfig.reportsDirectory = isolatedDir;
|
|
231
|
+
vitest.onClose(() => {
|
|
232
|
+
try {
|
|
233
|
+
rmSync(isolatedDir, {
|
|
234
|
+
recursive: true,
|
|
235
|
+
force: true
|
|
236
|
+
});
|
|
237
|
+
} catch {}
|
|
238
|
+
});
|
|
239
|
+
} else if (dirDecision.kind === "explicit") {
|
|
240
|
+
log("using explicit VITEST_AGENT_COVERAGE_DIR ->", dirDecision.dir);
|
|
241
|
+
coverageConfig.reportsDirectory = dirDecision.dir;
|
|
242
|
+
}
|
|
243
|
+
}
|
|
206
244
|
const transport = options.transport ?? { kind: "local" };
|
|
207
245
|
log("transport.kind:", transport.kind);
|
|
208
246
|
const passWithNoTestsRaw = vitest.config.passWithNoTests;
|
package/reporter.js
CHANGED
|
@@ -4,14 +4,15 @@ import { ReporterLive } from "./layers/ReporterLive.js";
|
|
|
4
4
|
import { buildReporterKit, normalizeReporters } from "./utils/build-reporter-kit.js";
|
|
5
5
|
import { captureEnvVars } from "./utils/capture-env.js";
|
|
6
6
|
import { captureSettings, hashSettings } from "./utils/capture-settings.js";
|
|
7
|
+
import { isPartialRun } from "./utils/is-partial-run.js";
|
|
7
8
|
import { processFailure } from "./utils/process-failure.js";
|
|
8
9
|
import { routeRenderedOutput } from "./utils/route-rendered-output.js";
|
|
9
10
|
import { stringifyFailureValue } from "./utils/stringify-failure-value.js";
|
|
11
|
+
import { mkdirSync } from "node:fs";
|
|
12
|
+
import { dirname } from "node:path";
|
|
10
13
|
import { DataReader, DataStore, DetailResolver, EnvironmentDetector, ExecutorResolver, FormatSelector, HistoryTracker, OutputPipelineLive, PathResolutionLive, buildAgentReport, coerceErrorField, computeTrend, ensureMigrated, formatFatalError, historyKey, isTimeoutError, probeHostMetadataFromEnv, resolveDataPath, resolveLogFile, resolveLogLevel } from "@vitest-agent/sdk";
|
|
11
14
|
import { Effect, Option, PubSub } from "effect";
|
|
12
15
|
import { randomUUID } from "node:crypto";
|
|
13
|
-
import { mkdirSync } from "node:fs";
|
|
14
|
-
import { dirname } from "node:path";
|
|
15
16
|
import { NodeServices } from "@effect/platform-node";
|
|
16
17
|
import { DefaultVitestAgentReporter } from "@vitest-agent/reporter";
|
|
17
18
|
|
|
@@ -199,6 +200,35 @@ var AgentReporter = class {
|
|
|
199
200
|
* @internal
|
|
200
201
|
*/
|
|
201
202
|
hookStartedAt = /* @__PURE__ */ new Map();
|
|
203
|
+
/**
|
|
204
|
+
* Count of test specifications Vitest started for the current run,
|
|
205
|
+
* captured from `onTestRunStart`'s `specifications` argument. Used
|
|
206
|
+
* alongside a fresh `globTestSpecifications()` total in `onTestRunEnd`
|
|
207
|
+
* as one of `isPartialRun`'s signals (issue #160 gap 2) — a tags-only
|
|
208
|
+
* `run_tests` filter narrows the run without setting `filenamePattern`
|
|
209
|
+
* or `projectFilter`, so the spec-count comparison is the only signal
|
|
210
|
+
* that catches it. `undefined` when `onTestRunStart` never fired
|
|
211
|
+
* (tests invoking `onTestRunEnd` directly); `onTestRunEnd` falls back
|
|
212
|
+
* to the executed module count in that case.
|
|
213
|
+
*
|
|
214
|
+
* @internal
|
|
215
|
+
*/
|
|
216
|
+
startedSpecCount;
|
|
217
|
+
/**
|
|
218
|
+
* Original values of coverage-threshold keys deleted from
|
|
219
|
+
* `vitest.coverageProvider.options.thresholds` while neutralizing a
|
|
220
|
+
* partial run (issue #160). In `run` mode Vitest re-initializes the
|
|
221
|
+
* provider on every `vitest.start`, so the snapshot is moot — but in
|
|
222
|
+
* watch mode the provider is created once and scoped reruns go through
|
|
223
|
+
* `rerunFiles` without re-initializing it, so a deleted key would stay
|
|
224
|
+
* gone for the rest of the watch session. `onTestRunStart` restores
|
|
225
|
+
* these keys (only if still absent — a legitimately re-initialized
|
|
226
|
+
* provider is left alone) and clears the map. Empty when the last run
|
|
227
|
+
* was not partial.
|
|
228
|
+
*
|
|
229
|
+
* @internal
|
|
230
|
+
*/
|
|
231
|
+
neutralizedThresholdSnapshot = /* @__PURE__ */ new Map();
|
|
202
232
|
constructor(options = {}) {
|
|
203
233
|
this.logLevel = resolveLogLevel();
|
|
204
234
|
this.logFile = resolveLogFile();
|
|
@@ -397,6 +427,16 @@ var AgentReporter = class {
|
|
|
397
427
|
* `RunStarted` event for live subscribers.
|
|
398
428
|
*/
|
|
399
429
|
onTestRunStart(_specifications) {
|
|
430
|
+
this.startedSpecCount = _specifications.length;
|
|
431
|
+
if (this.neutralizedThresholdSnapshot.size > 0) {
|
|
432
|
+
try {
|
|
433
|
+
const thresholds = (this._vitest?.coverageProvider)?.options?.thresholds;
|
|
434
|
+
if (thresholds !== void 0 && typeof thresholds === "object") {
|
|
435
|
+
for (const [key, value] of this.neutralizedThresholdSnapshot) if (!(key in thresholds)) thresholds[key] = value;
|
|
436
|
+
}
|
|
437
|
+
} catch {}
|
|
438
|
+
this.neutralizedThresholdSnapshot = /* @__PURE__ */ new Map();
|
|
439
|
+
}
|
|
400
440
|
if (!this.wantsRunEvents()) return;
|
|
401
441
|
this.currentRunId = randomUUID();
|
|
402
442
|
this.moduleStartedAt.clear();
|
|
@@ -791,6 +831,7 @@ var AgentReporter = class {
|
|
|
791
831
|
async onTestRunEnd(testModules, unhandledErrors, reason) {
|
|
792
832
|
if (this.rendered) return;
|
|
793
833
|
this.rendered = true;
|
|
834
|
+
const errors = unhandledErrors;
|
|
794
835
|
if (this.wantsRunEvents() && this.currentRunId !== null) {
|
|
795
836
|
let pass = 0;
|
|
796
837
|
let fail = 0;
|
|
@@ -820,11 +861,11 @@ var AgentReporter = class {
|
|
|
820
861
|
timeoutCount: timeout,
|
|
821
862
|
durationMs: totalDuration,
|
|
822
863
|
// @vitest-agent/ui, which both populate `collectedModules` on their
|
|
823
|
-
collectedModules: testModules.length
|
|
864
|
+
collectedModules: testModules.length,
|
|
865
|
+
...errors.length > 0 && { unhandledErrors: errors }
|
|
824
866
|
});
|
|
825
867
|
}
|
|
826
868
|
const modules = testModules;
|
|
827
|
-
const errors = unhandledErrors;
|
|
828
869
|
const opts = this.options;
|
|
829
870
|
const stashedCoverage = this.coverage;
|
|
830
871
|
const stashedVitest = this._vitest;
|
|
@@ -832,6 +873,31 @@ var AgentReporter = class {
|
|
|
832
873
|
const logFile = this.logFile;
|
|
833
874
|
const runEvents = this.runEvents;
|
|
834
875
|
const preBuiltReporters = this.reporters;
|
|
876
|
+
const vitestForPartialCheck = stashedVitest;
|
|
877
|
+
const startedSpecCount = this.startedSpecCount ?? modules.length;
|
|
878
|
+
let totalSpecCount = startedSpecCount;
|
|
879
|
+
try {
|
|
880
|
+
const specs = await vitestForPartialCheck?.globTestSpecifications?.();
|
|
881
|
+
if (specs !== void 0) totalSpecCount = specs.length;
|
|
882
|
+
} catch {}
|
|
883
|
+
const isPartial = isPartialRun({
|
|
884
|
+
filenamePattern: vitestForPartialCheck?.filenamePattern,
|
|
885
|
+
startedSpecCount,
|
|
886
|
+
totalSpecCount,
|
|
887
|
+
projectFilter: opts.projectFilter
|
|
888
|
+
});
|
|
889
|
+
const testedFiles = isPartial ? Array.from(new Set(modules.map((m) => m.relativeModuleId.replace(/\.test\.([^.]+)$/, ".$1").replace(/\.spec\.([^.]+)$/, ".$1")))) : void 0;
|
|
890
|
+
if (isPartial) {
|
|
891
|
+
this.neutralizedThresholdSnapshot = /* @__PURE__ */ new Map();
|
|
892
|
+
try {
|
|
893
|
+
const thresholds = (stashedVitest?.coverageProvider)?.options?.thresholds;
|
|
894
|
+
if (thresholds !== void 0 && typeof thresholds === "object") for (const key of Object.keys(thresholds)) {
|
|
895
|
+
if (key === "perFile" || key === "autoUpdate" || key === "100") continue;
|
|
896
|
+
this.neutralizedThresholdSnapshot.set(key, thresholds[key]);
|
|
897
|
+
delete thresholds[key];
|
|
898
|
+
}
|
|
899
|
+
} catch {}
|
|
900
|
+
}
|
|
835
901
|
const emitEvent = (event) => {
|
|
836
902
|
this.emit(event);
|
|
837
903
|
};
|
|
@@ -964,9 +1030,10 @@ var AgentReporter = class {
|
|
|
964
1030
|
thresholds: opts.coverageThresholds,
|
|
965
1031
|
includeBareZero: opts.includeBareZero,
|
|
966
1032
|
...opts.coverageTargets ? { targets: opts.coverageTargets } : {},
|
|
967
|
-
...baselines ? { baselines } : {}
|
|
1033
|
+
...baselines ? { baselines } : {},
|
|
1034
|
+
...isPartial ? { totalFiles: totalSpecCount } : {}
|
|
968
1035
|
};
|
|
969
|
-
const coverageResult = stashedCoverage && isFirstProject ? yield* analyzer.process(stashedCoverage, coverageOpts) : Option.none();
|
|
1036
|
+
const coverageResult = stashedCoverage && isFirstProject ? isPartial ? yield* analyzer.processScoped(stashedCoverage, coverageOpts, testedFiles ?? []) : yield* analyzer.process(stashedCoverage, coverageOpts) : Option.none();
|
|
970
1037
|
const coverageReport = Option.getOrUndefined(coverageResult);
|
|
971
1038
|
if (wantsRunEvents && coverageReport !== void 0) {
|
|
972
1039
|
const globalThresholds = coverageReport.thresholds.global;
|
|
@@ -978,9 +1045,12 @@ var AgentReporter = class {
|
|
|
978
1045
|
file: fc.file,
|
|
979
1046
|
missing: fc.summary,
|
|
980
1047
|
uncoveredLines: fc.uncoveredLines
|
|
981
|
-
}))
|
|
1048
|
+
})),
|
|
1049
|
+
...coverageReport.scoped ? { scoped: coverageReport.scoped } : {},
|
|
1050
|
+
...coverageReport.scopedFiles !== void 0 ? { scopedFiles: coverageReport.scopedFiles.length } : {},
|
|
1051
|
+
...coverageReport.totalFiles !== void 0 ? { totalFiles: coverageReport.totalFiles } : {}
|
|
982
1052
|
});
|
|
983
|
-
for (const metric of [
|
|
1053
|
+
if (!coverageReport.scoped) for (const metric of [
|
|
984
1054
|
"lines",
|
|
985
1055
|
"branches",
|
|
986
1056
|
"functions",
|
|
@@ -1029,7 +1099,7 @@ var AgentReporter = class {
|
|
|
1029
1099
|
passed: baseReport.summary.passed,
|
|
1030
1100
|
failed: baseReport.summary.failed,
|
|
1031
1101
|
skipped: baseReport.summary.skipped,
|
|
1032
|
-
scoped:
|
|
1102
|
+
scoped: isPartial,
|
|
1033
1103
|
actorType: attribution.actorType,
|
|
1034
1104
|
agentId: attribution.agentId,
|
|
1035
1105
|
conversationId: attribution.conversationId,
|
|
@@ -1311,6 +1381,10 @@ var AgentReporter = class {
|
|
|
1311
1381
|
const newBaselines = computeUpdatedBaselines(baselines, coverageReport.totals, opts.coverageTargets);
|
|
1312
1382
|
yield* store.writeBaselines(newBaselines);
|
|
1313
1383
|
}
|
|
1384
|
+
if (coverageReport && !coverageReport.scoped) {
|
|
1385
|
+
if (opts.coverageThresholds !== void 0) yield* store.writeThresholds(opts.coverageThresholds);
|
|
1386
|
+
if (opts.coverageTargets !== void 0) yield* store.writeTargets(opts.coverageTargets);
|
|
1387
|
+
}
|
|
1314
1388
|
let trendSummary;
|
|
1315
1389
|
if (coverageReport && !coverageReport.scoped) {
|
|
1316
1390
|
const firstProjectKey = Array.from(projectGroups.keys())[0];
|
|
@@ -2,8 +2,8 @@ import { toPosixPath } from "./to-posix-path.js";
|
|
|
2
2
|
import { nodeWalkerFs } from "./walker-fs.js";
|
|
3
3
|
import { DefaultDiscoverStrategy } from "./discover-strategy.js";
|
|
4
4
|
import { isTestShapedPackage } from "./is-test-shaped-package.js";
|
|
5
|
-
import { NON_DISCOVERABLE_DIRS, SRC_DIR, TEST_DIR } from "@vitest-agent/sdk";
|
|
6
5
|
import { isAbsolute, join, normalize, relative } from "node:path";
|
|
6
|
+
import { NON_DISCOVERABLE_DIRS, SRC_DIR, TEST_DIR } from "@vitest-agent/sdk";
|
|
7
7
|
import { findWorkspaceRootSync, getWorkspacePackagesSync } from "@effected/workspaces";
|
|
8
8
|
import { nodeSyncOps } from "@effected/workspaces/node-sync";
|
|
9
9
|
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { nodeWalkerFs } from "./walker-fs.js";
|
|
2
2
|
import { findTestFiles } from "./find-test-files.js";
|
|
3
3
|
import { Tag } from "./tag.js";
|
|
4
|
-
import { NON_DISCOVERABLE_DIRS, SRC_DIR, TEST_DIR, TEST_FILE_GLOB_SUFFIX, TEST_HELPER_DIRS } from "@vitest-agent/sdk";
|
|
5
4
|
import { join, sep } from "node:path";
|
|
5
|
+
import { NON_DISCOVERABLE_DIRS, SRC_DIR, TEST_DIR, TEST_FILE_GLOB_SUFFIX, TEST_HELPER_DIRS } from "@vitest-agent/sdk";
|
|
6
6
|
import { configDefaults } from "vitest/config";
|
|
7
7
|
|
|
8
8
|
//#region src/utils/discover-strategy.ts
|
package/utils/find-test-files.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { toPosixPath } from "./to-posix-path.js";
|
|
2
2
|
import { nodeWalkerFs } from "./walker-fs.js";
|
|
3
|
-
import { NON_DISCOVERABLE_DIRS } from "@vitest-agent/sdk";
|
|
4
3
|
import { join, relative } from "node:path";
|
|
4
|
+
import { NON_DISCOVERABLE_DIRS } from "@vitest-agent/sdk";
|
|
5
5
|
|
|
6
6
|
//#region src/utils/find-test-files.ts
|
|
7
7
|
function globToRegex(pattern) {
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
//#region src/utils/is-partial-run.ts
|
|
2
|
+
/**
|
|
3
|
+
* Pure decision function: was this Vitest run scoped to a subset of the
|
|
4
|
+
* project's test files?
|
|
5
|
+
*
|
|
6
|
+
* @remarks
|
|
7
|
+
* A run is partial when any of the following holds:
|
|
8
|
+
* - Vitest's `filenamePattern` was set (a non-empty array) for this run.
|
|
9
|
+
* - Fewer specifications started than exist in total for the same project set.
|
|
10
|
+
* - An explicit `--project` filter was supplied.
|
|
11
|
+
*
|
|
12
|
+
* Any of these makes coverage's whole-project denominator meaningless for
|
|
13
|
+
* threshold enforcement (issue #160).
|
|
14
|
+
*
|
|
15
|
+
* @public
|
|
16
|
+
*/
|
|
17
|
+
function isPartialRun(input) {
|
|
18
|
+
const { filenamePattern, startedSpecCount, totalSpecCount, projectFilter } = input;
|
|
19
|
+
if (filenamePattern !== void 0 && filenamePattern.length > 0) return true;
|
|
20
|
+
if (startedSpecCount < totalSpecCount) return true;
|
|
21
|
+
if (projectFilter !== void 0) return true;
|
|
22
|
+
return false;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
//#endregion
|
|
26
|
+
export { isPartialRun };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { nodeWalkerFs } from "./walker-fs.js";
|
|
2
2
|
import { findTestFiles } from "./find-test-files.js";
|
|
3
|
-
import { SRC_DIR, TEST_DIR, TEST_FILE_GLOB_SUFFIX } from "@vitest-agent/sdk";
|
|
4
3
|
import { join } from "node:path";
|
|
4
|
+
import { SRC_DIR, TEST_DIR, TEST_FILE_GLOB_SUFFIX } from "@vitest-agent/sdk";
|
|
5
5
|
|
|
6
6
|
//#region src/utils/is-test-shaped-package.ts
|
|
7
7
|
/**
|
package/utils/process-failure.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { computeFailureSignature, findFunctionBoundary } from "@vitest-agent/sdk";
|
|
2
1
|
import { readFileSync } from "node:fs";
|
|
2
|
+
import { computeFailureSignature, findFunctionBoundary } from "@vitest-agent/sdk";
|
|
3
3
|
|
|
4
4
|
//#region src/utils/process-failure.ts
|
|
5
5
|
const FRAME_LINE_REGEX = /^\s*at\s+(?:([\w$.<>[\] ]+?)\s+)?\(?([^\n)]+):(\d+):(\d+)\)?\s*$/;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
//#region src/utils/resolve-coverage-dir-isolation.ts
|
|
2
|
+
/**
|
|
3
|
+
* Values of `VITEST_AGENT_COVERAGE_DIR_ISOLATION` that opt out of the
|
|
4
|
+
* per-process coverage directory rewrite.
|
|
5
|
+
*/
|
|
6
|
+
const OPT_OUT_VALUES = /* @__PURE__ */ new Set([
|
|
7
|
+
"off",
|
|
8
|
+
"0",
|
|
9
|
+
"false"
|
|
10
|
+
]);
|
|
11
|
+
/**
|
|
12
|
+
* Pure decision function: should this Vitest run's `coverage.reportsDirectory`
|
|
13
|
+
* be isolated to a per-process temp directory?
|
|
14
|
+
*
|
|
15
|
+
* @remarks
|
|
16
|
+
* Two concurrent plain-CLI `vitest run` invocations in one checkout share
|
|
17
|
+
* `coverage.reportsDirectory` by default; the v8 provider's `clean: true`
|
|
18
|
+
* default `rm -rf`s that directory at run start, so one run can delete the
|
|
19
|
+
* other's `.tmp` files mid-run (issue #194). The MCP `run_tests` path
|
|
20
|
+
* already isolates via `makeCoverageDirOverride()`; this function drives
|
|
21
|
+
* the equivalent decision for the plain-CLI (`AgentPlugin.configureVitest`)
|
|
22
|
+
* path.
|
|
23
|
+
*
|
|
24
|
+
* Only the `agent` executor is ever isolated — a human's `./coverage`
|
|
25
|
+
* artifacts, and CI's configured directory, are never relocated.
|
|
26
|
+
*
|
|
27
|
+
* @public
|
|
28
|
+
*/
|
|
29
|
+
function resolveCoverageDirIsolation(input) {
|
|
30
|
+
const { executor, coverageEnabled, env } = input;
|
|
31
|
+
if (!coverageEnabled) return { kind: "keep" };
|
|
32
|
+
if (executor !== "agent") return { kind: "keep" };
|
|
33
|
+
const isolationOverride = env.VITEST_AGENT_COVERAGE_DIR_ISOLATION;
|
|
34
|
+
if (isolationOverride !== void 0 && OPT_OUT_VALUES.has(isolationOverride)) return { kind: "keep" };
|
|
35
|
+
const explicitDir = env.VITEST_AGENT_COVERAGE_DIR;
|
|
36
|
+
if (explicitDir !== void 0 && explicitDir.length > 0) return {
|
|
37
|
+
kind: "explicit",
|
|
38
|
+
dir: explicitDir
|
|
39
|
+
};
|
|
40
|
+
return { kind: "isolate" };
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
//#endregion
|
|
44
|
+
export { resolveCoverageDirIsolation };
|
package/utils/run-script-lock.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { createHash, randomBytes } from "node:crypto";
|
|
2
1
|
import { closeSync, mkdirSync, openSync, readFileSync, rmSync, statSync, writeFileSync, writeSync } from "node:fs";
|
|
3
|
-
import { join } from "node:path";
|
|
4
2
|
import { homedir } from "node:os";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import { createHash, randomBytes } from "node:crypto";
|
|
5
5
|
|
|
6
6
|
//#region src/utils/run-script-lock.ts
|
|
7
7
|
/**
|