@elench/testkit 0.1.108 → 0.1.109

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.
Files changed (54) hide show
  1. package/README.md +9 -9
  2. package/lib/app/doctor.mjs +5 -5
  3. package/lib/app/typecheck.mjs +6 -5
  4. package/lib/bundler/index.mjs +134 -7
  5. package/lib/cli/args.mjs +3 -2
  6. package/lib/cli/assistant/command-observer.mjs +2 -1
  7. package/lib/cli/assistant/command-results.mjs +2 -1
  8. package/lib/cli/assistant/context-pack.mjs +2 -2
  9. package/lib/cli/assistant/prompt-builder.mjs +2 -2
  10. package/lib/cli/command-flags.mjs +2 -1
  11. package/lib/cli/commands/cleanup.mjs +13 -2
  12. package/lib/cli/commands/discover.mjs +2 -1
  13. package/lib/cli/commands/run.mjs +3 -2
  14. package/lib/cli/entrypoint.mjs +3 -1
  15. package/lib/cli/operations/cleanup/operation.mjs +6 -1
  16. package/lib/cli/operations/status/operation.mjs +2 -2
  17. package/lib/cli/renderers/discover/report.mjs +6 -8
  18. package/lib/cli/renderers/run/failure.mjs +1 -1
  19. package/lib/cli/renderers/run/text-reporter.mjs +1 -1
  20. package/lib/cli/renderers/status/text.mjs +101 -1
  21. package/lib/config/discovery.mjs +10 -1
  22. package/lib/config-api/index.mjs +2 -2
  23. package/lib/config-api/next-runtime-tsconfig.mjs +2 -1
  24. package/lib/coverage/graph-builder.mjs +2 -4
  25. package/lib/coverage/routing.mjs +1 -1
  26. package/lib/coverage/shared.mjs +1 -2
  27. package/lib/discovery/index.d.ts +5 -8
  28. package/lib/discovery/index.mjs +15 -24
  29. package/lib/domain/test-types.mjs +44 -0
  30. package/lib/history/index.d.ts +3 -4
  31. package/lib/history/index.mjs +6 -14
  32. package/lib/runner/formatting.mjs +2 -3
  33. package/lib/runner/maintenance.mjs +136 -35
  34. package/lib/runner/planning.mjs +1 -1
  35. package/lib/runner/results.mjs +0 -6
  36. package/lib/runner/status-model.mjs +520 -0
  37. package/lib/runner/suite-selection.mjs +20 -11
  38. package/lib/runner/template-steps.mjs +2 -2
  39. package/lib/runner/template.mjs +4 -0
  40. package/lib/ui/index.d.ts +1 -0
  41. package/lib/ui/index.mjs +1 -0
  42. package/lib/vitest/index.mjs +2 -1
  43. package/node_modules/@elench/next-analysis/package.json +1 -1
  44. package/node_modules/@elench/testkit-bridge/dist/index.js +9 -11
  45. package/node_modules/@elench/testkit-bridge/dist/index.js.map +1 -1
  46. package/node_modules/@elench/testkit-bridge/package.json +2 -2
  47. package/node_modules/@elench/testkit-protocol/dist/index.d.ts +1 -3
  48. package/node_modules/@elench/testkit-protocol/dist/index.d.ts.map +1 -1
  49. package/node_modules/@elench/testkit-protocol/dist/index.js +3 -6
  50. package/node_modules/@elench/testkit-protocol/dist/index.js.map +1 -1
  51. package/node_modules/@elench/testkit-protocol/package.json +1 -1
  52. package/node_modules/@elench/ts-analysis/dist/requests.js +1 -1
  53. package/node_modules/@elench/ts-analysis/package.json +1 -1
  54. package/package.json +9 -9
@@ -1,7 +1,107 @@
1
1
  export function renderStatusResult(result) {
2
- return normalizeLines(result?.lines);
2
+ if (Array.isArray(result?.lines)) return normalizeLines(result.lines);
3
+ if (!result) return [];
4
+
5
+ const lines = [
6
+ `Testkit Status: ${result.name || result.product?.selectedService || "service"}`,
7
+ "",
8
+ "Product",
9
+ ` dir: ${result.product?.dir || "unknown"}`,
10
+ ` config: ${result.product?.configFile || "none"}`,
11
+ ` services: ${formatList(result.product?.services)}`,
12
+ ` dependencies: ${formatList(result.product?.dependencies)}`,
13
+ "",
14
+ "Runs",
15
+ ` active: ${result.runs?.active || 0}`,
16
+ ` stale: ${result.runs?.stale || 0}`,
17
+ ];
18
+
19
+ for (const run of (result.runs?.runs || []).slice(0, 5)) {
20
+ const ports = run.ports?.length ? ` ports=${run.ports.join(",")}` : "";
21
+ lines.push(` ${run.runId}: ${run.status} pid=${run.pid}${ports}`);
22
+ }
23
+ if ((result.runs?.runs || []).length > 5) {
24
+ lines.push(` ... ${(result.runs.runs.length - 5)} more run${result.runs.runs.length - 5 === 1 ? "" : "s"}`);
25
+ }
26
+
27
+ lines.push("", "Runtime Graphs");
28
+ if ((result.runtimeGraphs || []).length === 0) {
29
+ lines.push(" none");
30
+ } else {
31
+ for (const graph of result.runtimeGraphs || []) {
32
+ const marker = graph.orphan ? " orphan" : "";
33
+ lines.push(` ${graph.name}${marker}`);
34
+ lines.push(` desired instances: ${graph.desired?.instanceCount ?? "none"}`);
35
+ lines.push(` runtime dirs: ${graph.runtimeDirCount || 0}`);
36
+ lines.push(` current: ${formatRuntimeRange(graph.currentRuntimeDirs?.map((runtime) => runtime.id))}`);
37
+ lines.push(` stale: ${formatRuntimeRange(graph.staleRuntimeDirs?.map((runtime) => runtime.id))}`);
38
+ lines.push(` runtime services: ${formatList(graph.desired?.runtimeServices || graph.actual?.runtimeServices)}`);
39
+ lines.push(` target services: ${formatList(graph.desired?.targetServices || graph.actual?.targetServices)}`);
40
+ }
41
+ }
42
+
43
+ lines.push(
44
+ "",
45
+ "Caches",
46
+ " bundles",
47
+ ` size: ${formatBytes(result.caches?.bundles?.sizeBytes || 0)}`,
48
+ ` files: ${result.caches?.bundles?.fileCount || 0}`,
49
+ ` source files: ${result.caches?.bundles?.sourceFileCount || 0}`,
50
+ ` duplicated sources: ${result.caches?.bundles?.duplicatedSourceCount || 0}`,
51
+ ` inline sourcemaps: ${formatSourcemaps(result.caches?.bundles)}`,
52
+ ` manifest entries: ${result.caches?.bundles?.manifest?.entryCount || 0}`,
53
+ ` unmanaged files: ${result.caches?.bundles?.unmanagedFileCount || 0}`,
54
+ " assistant command results",
55
+ ` size: ${formatBytes(result.caches?.assistant?.sizeBytes || 0)}`,
56
+ ` files: ${result.caches?.assistant?.fileCount || 0}`,
57
+ ` large files: ${result.caches?.assistant?.largeFileCount || 0}`
58
+ );
59
+
60
+ if (result.warnings?.length) {
61
+ lines.push("", "Warnings");
62
+ for (const warning of result.warnings) lines.push(` - ${warning}`);
63
+ }
64
+
65
+ if (!result.hasState) {
66
+ lines.push("", "No state — run tests first.");
67
+ }
68
+
69
+ return lines;
3
70
  }
4
71
 
5
72
  function normalizeLines(lines) {
6
73
  return Array.isArray(lines) ? lines : [];
7
74
  }
75
+
76
+ function formatList(values) {
77
+ const list = Array.isArray(values) ? values.filter(Boolean) : [];
78
+ return list.length > 0 ? list.join(", ") : "none";
79
+ }
80
+
81
+ function formatRuntimeRange(ids) {
82
+ const values = Array.isArray(ids) ? ids : [];
83
+ if (values.length === 0) return "none";
84
+ if (values.length === 1) return values[0];
85
+ return `${values[0]}..${values.at(-1)}`;
86
+ }
87
+
88
+ function formatBytes(value) {
89
+ const bytes = Number(value || 0);
90
+ if (bytes < 1024) return `${bytes}B`;
91
+ const units = ["KB", "MB", "GB", "TB"];
92
+ let amount = bytes / 1024;
93
+ let unitIndex = 0;
94
+ while (amount >= 1024 && unitIndex < units.length - 1) {
95
+ amount /= 1024;
96
+ unitIndex += 1;
97
+ }
98
+ return `${amount >= 10 ? amount.toFixed(0) : amount.toFixed(1)}${units[unitIndex]}`;
99
+ }
100
+
101
+ function formatSourcemaps(bundles = {}) {
102
+ if (bundles.sourcemapFileCount == null) return bundles.sourcemapStatus || "unknown";
103
+ if (bundles.sourcemapStatus && bundles.sourcemapStatus !== "present" && bundles.sourcemapStatus !== "none") {
104
+ return `${bundles.sourcemapFileCount} (${bundles.sourcemapStatus})`;
105
+ }
106
+ return String(bundles.sourcemapFileCount || 0);
107
+ }
@@ -15,7 +15,8 @@ const DISCOVERY_RULES = [
15
15
  { suffix: ".scenario.testkit.ts", type: "scenario", framework: "k6" },
16
16
  { suffix: ".dal.testkit.ts", type: "dal", framework: "k6" },
17
17
  { suffix: ".load.testkit.ts", type: "load", framework: "k6" },
18
- { suffix: ".pw.testkit.ts", type: "e2e", framework: "playwright" },
18
+ { suffix: ".ui.testkit.ts", type: "ui", framework: "playwright" },
19
+ { suffix: ".pw.testkit.ts", type: "ui", framework: "playwright", legacySuffix: true },
19
20
  ];
20
21
 
21
22
  export function discoverProject(productDir, explicitServices = {}, options = {}) {
@@ -30,6 +31,14 @@ export function discoverProject(productDir, explicitServices = {}, options = {})
30
31
  for (const filePath of suiteFiles) {
31
32
  const rule = inferRule(filePath);
32
33
  if (!rule) continue;
34
+ if (rule.legacySuffix) {
35
+ diagnostics.push({
36
+ code: "legacy_ui_suffix",
37
+ severity: "warning",
38
+ message: `Legacy UI test suffix ".pw.testkit.ts" is deprecated. Rename to ".ui.testkit.ts": ${filePath}`,
39
+ path: filePath,
40
+ });
41
+ }
33
42
 
34
43
  const owners = inferOwners(filePath, explicitServices, repoDiscovery);
35
44
  if (owners === null) continue;
@@ -225,9 +225,9 @@ function nextApp(options = {}) {
225
225
  readyTimeoutMs,
226
226
  env: mode === "start"
227
227
  ? {
228
- NEXT_DIST_DIR: normalizedEnv.NEXT_DIST_DIR || ".next-testkit/{runtimeId}/dist",
228
+ NEXT_DIST_DIR: normalizedEnv.NEXT_DIST_DIR || "{productDir}/.next-testkit/{runtimeId}/dist",
229
229
  NEXT_TSCONFIG_PATH:
230
- normalizedEnv.NEXT_TSCONFIG_PATH || ".next-testkit/{runtimeId}/tsconfig.json",
230
+ normalizedEnv.NEXT_TSCONFIG_PATH || "{productDir}/.next-testkit/{runtimeId}/tsconfig.json",
231
231
  ...normalizedEnv,
232
232
  }
233
233
  : normalizedEnv,
@@ -3,12 +3,13 @@ import path from "path";
3
3
 
4
4
  export async function writeNextRuntimeTsconfig(context = {}) {
5
5
  const serviceDir = context.cwd || context.productDir;
6
+ const productDir = context.productDir || serviceDir;
6
7
  const runtimeId = context.runtimeId;
7
8
  if (!serviceDir || !runtimeId) {
8
9
  throw new Error("writeNextRuntimeTsconfig requires cwd and runtimeId");
9
10
  }
10
11
 
11
- const runtimeRoot = path.join(serviceDir, ".next-testkit", String(runtimeId));
12
+ const runtimeRoot = path.join(productDir, ".next-testkit", String(runtimeId));
12
13
  const outputPath = path.join(runtimeRoot, "tsconfig.json");
13
14
  const outputDir = path.dirname(outputPath);
14
15
  const relative = (target) => path.relative(outputDir, target).replaceAll(path.sep, "/");
@@ -70,8 +70,7 @@ export function buildCoverageGraph({ productDir, repoDiscovery = {}, services =
70
70
  confidence: "high",
71
71
  service: entry.serviceName,
72
72
  suiteName: entry.suiteName,
73
- selectionType: toSelectionType(entry.type, entry.framework),
74
- framework: entry.framework,
73
+ type: toSelectionType(entry.type, entry.framework),
75
74
  testFilePath: entry.filePath,
76
75
  coveredNodeIds,
77
76
  details: buildEvidenceDetails(coveredNodeIds, graph, entry, context),
@@ -173,8 +172,7 @@ function createFallbackEvidence(entry, testNodeId) {
173
172
  confidence: "medium",
174
173
  service: entry.serviceName,
175
174
  suiteName: entry.suiteName,
176
- selectionType: toSelectionType(entry.type, entry.framework),
177
- framework: entry.framework,
175
+ type: toSelectionType(entry.type, entry.framework),
178
176
  testFilePath: entry.filePath,
179
177
  coveredNodeIds: [testNodeId],
180
178
  };
@@ -53,7 +53,7 @@ export function apiRouteLookupKey(method, route) {
53
53
  }
54
54
 
55
55
  export function toSelectionType(type, framework) {
56
- if (framework === "playwright") return "pw";
56
+ if (framework === "playwright" || type === "ui") return "ui";
57
57
  if (type === "integration") return "int";
58
58
  return type;
59
59
  }
@@ -67,7 +67,6 @@ export function createTestFileNode(graph, entry) {
67
67
  filePath: entry.filePath,
68
68
  metadata: {
69
69
  suiteName: entry.suiteName,
70
- framework: entry.framework,
71
70
  type: toSelectionType(entry.type, entry.framework),
72
71
  },
73
72
  });
@@ -80,7 +79,7 @@ export function apiRouteLookupKey(method, route) {
80
79
  }
81
80
 
82
81
  export function toSelectionType(type, framework) {
83
- if (framework === "playwright") return "pw";
82
+ if (framework === "playwright" || type === "ui") return "ui";
84
83
  if (type === "integration") return "int";
85
84
  return type;
86
85
  }
@@ -1,8 +1,7 @@
1
1
  import type { CoverageGraph } from "@elench/testkit-protocol";
2
2
 
3
- export type DiscoverySelectionType = "int" | "e2e" | "scenario" | "dal" | "load" | "pw";
4
- export type DiscoveryInternalType = "integration" | "e2e" | "scenario" | "dal" | "load";
5
- export type DiscoveryFramework = "k6" | "playwright";
3
+ export type DiscoveryTestType = "ui" | "e2e" | "scenario" | "int" | "dal" | "load";
4
+ export type DiscoveryInternalType = "ui" | "integration" | "e2e" | "scenario" | "dal" | "load";
6
5
 
7
6
  export interface DiscoveryDiagnostic {
8
7
  code: string;
@@ -28,9 +27,8 @@ export interface DiscoverySuite {
28
27
  service: string;
29
28
  name: string;
30
29
  displayName: string;
31
- selectionType: DiscoverySelectionType;
30
+ type: DiscoveryTestType;
32
31
  internalType: DiscoveryInternalType;
33
- framework: DiscoveryFramework;
34
32
  groupLabel: string;
35
33
  fileCount: number;
36
34
  activeFileCount: number;
@@ -59,9 +57,8 @@ export interface DiscoveryFile {
59
57
  service: string;
60
58
  suiteName: string;
61
59
  groupLabel: string;
62
- selectionType: DiscoverySelectionType;
60
+ type: DiscoveryTestType;
63
61
  internalType: DiscoveryInternalType;
64
- framework: DiscoveryFramework;
65
62
  skipped: boolean;
66
63
  skipReason: string | null;
67
64
  locks: string[];
@@ -79,7 +76,7 @@ export interface DiscoveryResult {
79
76
  configFile: string | null;
80
77
  filters: {
81
78
  service: string | null;
82
- types: DiscoverySelectionType[] | ["all"];
79
+ types: DiscoveryTestType[] | ["all"];
83
80
  suiteSelectors: string[];
84
81
  fileNames: string[];
85
82
  runnableOnly: boolean;
@@ -3,6 +3,7 @@ import { loadConfigContext, resolveProductDir } from "../config/index.mjs";
3
3
  import { discoverProject } from "../config/discovery.mjs";
4
4
  import { loadTestkitConfig } from "../config/config-loader.mjs";
5
5
  import { buildCoverageGraph } from "../coverage/index.mjs";
6
+ import { formatPublicTestType } from "../domain/test-types.mjs";
6
7
  import { historyFilePath, loadHistory, summarizeHistoryForFiles } from "../history/index.mjs";
7
8
  import {
8
9
  matchesSelectedTypes,
@@ -124,12 +125,7 @@ export async function discoverTests(options = {}) {
124
125
 
125
126
  export function formatSelectionTypeLabel(type) {
126
127
  if (type === "int") return "Integration";
127
- if (type === "e2e") return "E2E";
128
- if (type === "scenario") return "Scenario";
129
- if (type === "dal") return "DAL";
130
- if (type === "load") return "Load";
131
- if (type === "pw") return "Playwright";
132
- return type;
128
+ return formatPublicTestType(type);
133
129
  }
134
130
 
135
131
  export function formatDisplayName(value) {
@@ -226,9 +222,8 @@ function buildResolvedSuiteEntries(config, suite, internalType, filters) {
226
222
  service: config.name,
227
223
  suiteName: suite.name,
228
224
  groupLabel: formatDisplayName(suite.name),
229
- selectionType,
225
+ type: selectionType,
230
226
  internalType,
231
- framework,
232
227
  skipped,
233
228
  skipReason,
234
229
  locks: [...new Set([...suiteLocks, ...fileLocks])].sort(),
@@ -239,13 +234,12 @@ function buildResolvedSuiteEntries(config, suite, internalType, filters) {
239
234
  if (visibleFiles.length === 0) return null;
240
235
  const skippedFileCount = visibleFiles.filter((entry) => entry.skipped).length;
241
236
  const suiteEntry = {
242
- id: buildSuiteId(config.name, selectionType, suite.name, framework),
237
+ id: buildSuiteId(config.name, selectionType, suite.name),
243
238
  service: config.name,
244
239
  name: suite.name,
245
240
  displayName: formatDisplayName(suite.name),
246
- selectionType,
241
+ type: selectionType,
247
242
  internalType,
248
- framework,
249
243
  groupLabel: formatDisplayName(suite.name),
250
244
  fileCount: visibleFiles.length,
251
245
  activeFileCount: visibleFiles.length - skippedFileCount,
@@ -308,9 +302,8 @@ function buildRawDiscovery({ rawDiscovery, explicitServices, filters }) {
308
302
  service: entry.serviceName,
309
303
  suiteName: entry.suiteName,
310
304
  groupLabel: formatDisplayName(entry.suiteName),
311
- selectionType,
305
+ type: selectionType,
312
306
  internalType: entry.type,
313
- framework: entry.framework,
314
307
  skipped: false,
315
308
  skipReason: null,
316
309
  locks: [],
@@ -318,7 +311,7 @@ function buildRawDiscovery({ rawDiscovery, explicitServices, filters }) {
318
311
  };
319
312
  files.push(fileEntry);
320
313
 
321
- const suiteId = buildSuiteId(entry.serviceName, selectionType, entry.suiteName, entry.framework);
314
+ const suiteId = buildSuiteId(entry.serviceName, selectionType, entry.suiteName);
322
315
  const existingSuite = suitesById.get(suiteId);
323
316
  if (existingSuite) {
324
317
  existingSuite.filePaths.push(entry.filePath);
@@ -330,9 +323,8 @@ function buildRawDiscovery({ rawDiscovery, explicitServices, filters }) {
330
323
  service: entry.serviceName,
331
324
  name: entry.suiteName,
332
325
  displayName: formatDisplayName(entry.suiteName),
333
- selectionType,
326
+ type: selectionType,
334
327
  internalType: entry.type,
335
- framework: entry.framework,
336
328
  groupLabel: formatDisplayName(entry.suiteName),
337
329
  fileCount: 1,
338
330
  activeFileCount: 1,
@@ -412,7 +404,7 @@ function buildSummary(services, suites, files, diagnostics) {
412
404
 
413
405
  for (const file of files) {
414
406
  byService[file.service] = (byService[file.service] || 0) + 1;
415
- byType[file.selectionType] = (byType[file.selectionType] || 0) + 1;
407
+ byType[file.type] = (byType[file.type] || 0) + 1;
416
408
  }
417
409
 
418
410
  return {
@@ -497,12 +489,12 @@ function normalizePath(filePath) {
497
489
  export function fileDisplayName(filePath) {
498
490
  const base = path.posix
499
491
  .basename(filePath)
500
- .replace(/(\.int|\.e2e|\.scenario|\.dal|\.load|\.pw)\.testkit\.ts$/, "");
492
+ .replace(/(\.int|\.e2e|\.scenario|\.dal|\.load|\.ui|\.pw)\.testkit\.ts$/, "");
501
493
  return formatDisplayName(base);
502
494
  }
503
495
 
504
- function buildSuiteId(serviceName, selectionType, suiteName, framework) {
505
- return [serviceName, selectionType, framework, suiteName].join("|");
496
+ function buildSuiteId(serviceName, selectionType, suiteName) {
497
+ return [serviceName, selectionType, suiteName].join("|");
506
498
  }
507
499
 
508
500
  function buildFileId(serviceName, selectionType, filePath) {
@@ -512,16 +504,15 @@ function buildFileId(serviceName, selectionType, filePath) {
512
504
  function compareSuiteEntries(left, right) {
513
505
  return (
514
506
  left.service.localeCompare(right.service) ||
515
- left.selectionType.localeCompare(right.selectionType) ||
516
- left.name.localeCompare(right.name) ||
517
- left.framework.localeCompare(right.framework)
507
+ left.type.localeCompare(right.type) ||
508
+ left.name.localeCompare(right.name)
518
509
  );
519
510
  }
520
511
 
521
512
  function compareFileEntries(left, right) {
522
513
  return (
523
514
  left.service.localeCompare(right.service) ||
524
- left.selectionType.localeCompare(right.selectionType) ||
515
+ left.type.localeCompare(right.type) ||
525
516
  left.suiteName.localeCompare(right.suiteName) ||
526
517
  left.path.localeCompare(right.path)
527
518
  );
@@ -0,0 +1,44 @@
1
+ export const TEST_TYPE_ORDER = ["ui", "e2e", "scenario", "int", "dal", "load"];
2
+ export const TEST_TYPES = new Set(TEST_TYPE_ORDER);
3
+ export const RUN_TYPE_ORDER = [...TEST_TYPE_ORDER, "all"];
4
+ export const RUN_TYPES = new Set(RUN_TYPE_ORDER);
5
+ export const LEGACY_TEST_TYPE_ALIASES = new Map([
6
+ ["pw", "ui"],
7
+ ]);
8
+
9
+ const TEST_TYPE_LABELS = {
10
+ ui: "UI",
11
+ e2e: "E2E",
12
+ scenario: "Scenario",
13
+ int: "INT",
14
+ dal: "DAL",
15
+ load: "Load",
16
+ };
17
+
18
+ export function normalizePublicTestType(value) {
19
+ const normalized = String(value || "").trim();
20
+ return LEGACY_TEST_TYPE_ALIASES.get(normalized) || normalized;
21
+ }
22
+
23
+ export function isPublicTestType(value) {
24
+ return TEST_TYPES.has(normalizePublicTestType(value));
25
+ }
26
+
27
+ export function isRunType(value) {
28
+ const normalized = normalizePublicTestType(value);
29
+ return normalized === "all" || TEST_TYPES.has(normalized);
30
+ }
31
+
32
+ export function formatPublicTestType(value) {
33
+ const normalized = normalizePublicTestType(value);
34
+ return TEST_TYPE_LABELS[normalized] || String(value || "");
35
+ }
36
+
37
+ export function publicTestTypeList({ includeAll = false, includeLegacy = false } = {}) {
38
+ const values = includeAll ? RUN_TYPE_ORDER : TEST_TYPE_ORDER;
39
+ return includeLegacy ? [...values, "pw"] : [...values];
40
+ }
41
+
42
+ export function publicTestTypeListText(options = {}) {
43
+ return publicTestTypeList(options).join(", ");
44
+ }
@@ -15,8 +15,7 @@ export interface TestHistoryEntry extends TestHistorySummary {
15
15
  path: string;
16
16
  service: string;
17
17
  suiteName: string;
18
- selectionType: string;
19
- framework: string;
18
+ type: string;
20
19
  notRunCount: number;
21
20
  durationCount: number;
22
21
  }
@@ -37,10 +36,10 @@ export declare function updateHistoryFromRunArtifact(
37
36
  ): TestHistoryDocument;
38
37
  export declare function summarizeHistoryForFiles(
39
38
  history: TestHistoryDocument,
40
- files?: Array<{ id: string; service: string; selectionType: string; path: string }>
39
+ files?: Array<{ id: string; service: string; type: string; path: string }>
41
40
  ): Map<string, TestHistorySummary>;
42
41
  export declare function buildHistoryTestId(
43
42
  serviceName: string,
44
- selectionType: string,
43
+ type: string,
45
44
  filePath: string
46
45
  ): string;
@@ -52,8 +52,7 @@ export function updateHistoryFromRunArtifact(history, runArtifact, recordedAt =
52
52
  path: file.path,
53
53
  service: service.name,
54
54
  suiteName: suite.name,
55
- selectionType: suite.type,
56
- framework: normalizeArtifactFramework(suite.framework),
55
+ type: suite.type,
57
56
  firstSeenAt: seenAt,
58
57
  lastSeenAt: seenAt,
59
58
  lastRunAt: seenAt,
@@ -70,8 +69,7 @@ export function updateHistoryFromRunArtifact(history, runArtifact, recordedAt =
70
69
  next.path = file.path;
71
70
  next.service = service.name;
72
71
  next.suiteName = suite.name;
73
- next.selectionType = suite.type;
74
- next.framework = normalizeArtifactFramework(suite.framework);
72
+ next.type = suite.type;
75
73
  next.lastSeenAt = seenAt;
76
74
  next.lastRunAt = seenAt;
77
75
  next.runCount += 1;
@@ -106,7 +104,7 @@ export function summarizeHistoryForFiles(history, files = []) {
106
104
  const normalized = normalizeHistory(history);
107
105
  const byId = new Map();
108
106
  for (const file of files) {
109
- const entry = normalized.tests[file.id] || normalized.tests[buildHistoryTestId(file.service, file.selectionType, file.path)];
107
+ const entry = normalized.tests[file.id] || normalized.tests[buildHistoryTestId(file.service, file.type, file.path)];
110
108
  if (!entry) continue;
111
109
  byId.set(file.id, {
112
110
  firstSeenAt: entry.firstSeenAt || null,
@@ -123,8 +121,8 @@ export function summarizeHistoryForFiles(history, files = []) {
123
121
  return byId;
124
122
  }
125
123
 
126
- export function buildHistoryTestId(serviceName, selectionType, filePath) {
127
- return [serviceName, selectionType, normalizePath(filePath)].join("|");
124
+ export function buildHistoryTestId(serviceName, type, filePath) {
125
+ return [serviceName, type, normalizePath(filePath)].join("|");
128
126
  }
129
127
 
130
128
  function normalizeHistory(parsed) {
@@ -135,8 +133,7 @@ function normalizeHistory(parsed) {
135
133
  path: normalizePath(entry.path || ""),
136
134
  service: String(entry.service || ""),
137
135
  suiteName: String(entry.suiteName || ""),
138
- selectionType: String(entry.selectionType || ""),
139
- framework: normalizeArtifactFramework(entry.framework || "k6"),
136
+ type: String(entry.type || entry.selectionType || ""),
140
137
  firstSeenAt: entry.firstSeenAt || null,
141
138
  lastSeenAt: entry.lastSeenAt || null,
142
139
  lastRunAt: entry.lastRunAt || null,
@@ -156,11 +153,6 @@ function normalizeHistory(parsed) {
156
153
  };
157
154
  }
158
155
 
159
- function normalizeArtifactFramework(value) {
160
- if (value === "default") return "k6";
161
- return value || "k6";
162
- }
163
-
164
156
  function normalizePath(filePath) {
165
157
  return String(filePath).split(path.sep).join("/").replace(/^\.\/+/, "");
166
158
  }
@@ -40,8 +40,7 @@ export function longestServiceName(results) {
40
40
  }
41
41
 
42
42
  export function formatFrameworkLabel(framework) {
43
- if (!framework || framework === "k6") return "";
44
- return framework;
43
+ return "";
45
44
  }
46
45
 
47
46
  export function formatSuiteFramework(framework) {
@@ -175,7 +174,7 @@ export function buildDebugRunSummaryLines(results, durationMs, regressionReport
175
174
  const fileDetail =
176
175
  suite.failedFiles.length > 0 ? ` (${suite.failedFiles.join(", ")})` : "";
177
176
  lines.push(
178
- ` - ${suite.type}:${suite.name}${formatSuiteFramework(suite.framework)}${fileDetail} · ${formatDuration(suite.durationMs)}`
177
+ ` - ${suite.type}:${suite.name}${fileDetail} · ${formatDuration(suite.durationMs)}`
179
178
  );
180
179
  if (suite.error) {
181
180
  lines.push(` ${suite.error}`);