@elench/testkit 0.1.60 → 0.1.62
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/lib/config/database.mjs +53 -0
- package/lib/config/database.test.mjs +29 -0
- package/lib/config/discovery-config.mjs +13 -0
- package/lib/config/env.mjs +55 -0
- package/lib/config/env.test.mjs +40 -0
- package/lib/config/index.mjs +21 -807
- package/lib/config/paths.mjs +28 -0
- package/lib/config/paths.test.mjs +27 -0
- package/lib/config/runtime.mjs +241 -0
- package/lib/config/runtime.test.mjs +56 -0
- package/lib/config/skip-config.mjs +189 -0
- package/lib/config/skip-config.test.mjs +63 -0
- package/lib/config/telemetry.mjs +28 -0
- package/lib/config/validation.mjs +124 -0
- package/lib/coverage/backend-discovery.mjs +183 -0
- package/lib/coverage/backend-discovery.test.mjs +52 -0
- package/lib/coverage/evidence.mjs +147 -0
- package/lib/coverage/evidence.test.mjs +77 -0
- package/lib/coverage/fs-walk.mjs +64 -0
- package/lib/coverage/graph-builder.mjs +181 -0
- package/lib/coverage/index.mjs +1 -816
- package/lib/coverage/index.test.mjs +330 -14
- package/lib/coverage/next-discovery.mjs +174 -0
- package/lib/coverage/next-static-analysis.mjs +763 -0
- package/lib/coverage/routing.mjs +86 -0
- package/lib/coverage/routing.test.mjs +52 -0
- package/lib/coverage/shared.mjs +198 -0
- package/lib/coverage/shared.test.mjs +39 -0
- package/node_modules/@elench/testkit-bridge/package.json +2 -2
- package/node_modules/@elench/testkit-bridge/src/index.mjs +156 -13
- package/node_modules/@elench/testkit-bridge/src/index.test.mjs +39 -5
- package/node_modules/@elench/testkit-protocol/package.json +1 -1
- package/node_modules/@elench/testkit-protocol/src/index.d.ts +26 -0
- package/node_modules/@elench/testkit-protocol/src/index.mjs +18 -0
- package/node_modules/@elench/testkit-protocol/src/index.test.mjs +75 -1
- package/package.json +5 -4
|
@@ -45,6 +45,19 @@ const context = {
|
|
|
45
45
|
route: "/coverage",
|
|
46
46
|
filePath: "app/coverage/page.tsx",
|
|
47
47
|
},
|
|
48
|
+
{
|
|
49
|
+
id: "ui_surface:web:/coverage:coverage-refresh-button",
|
|
50
|
+
kind: "ui_surface",
|
|
51
|
+
service: "web",
|
|
52
|
+
label: "Refresh overlay",
|
|
53
|
+
route: "/coverage",
|
|
54
|
+
filePath: "app/coverage/page.tsx",
|
|
55
|
+
target: {
|
|
56
|
+
kind: "testId",
|
|
57
|
+
value: "coverage-refresh-button",
|
|
58
|
+
confidence: "high",
|
|
59
|
+
},
|
|
60
|
+
},
|
|
48
61
|
{
|
|
49
62
|
id: "api_route:web:GET:/api/coverage",
|
|
50
63
|
kind: "api_route",
|
|
@@ -72,9 +85,16 @@ const context = {
|
|
|
72
85
|
],
|
|
73
86
|
edges: [
|
|
74
87
|
{
|
|
75
|
-
id: "
|
|
76
|
-
kind: "
|
|
88
|
+
id: "contains:page_view:web:/coverage:ui_surface:web:/coverage:coverage-refresh-button",
|
|
89
|
+
kind: "contains",
|
|
77
90
|
from: "page_view:web:/coverage",
|
|
91
|
+
to: "ui_surface:web:/coverage:coverage-refresh-button",
|
|
92
|
+
confidence: "high",
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
id: "requests:ui_surface:web:/coverage:coverage-refresh-button:api_route:web:GET:/api/coverage",
|
|
96
|
+
kind: "requests",
|
|
97
|
+
from: "ui_surface:web:/coverage:coverage-refresh-button",
|
|
78
98
|
to: "api_route:web:GET:/api/coverage",
|
|
79
99
|
confidence: "high",
|
|
80
100
|
},
|
|
@@ -89,7 +109,10 @@ const context = {
|
|
|
89
109
|
selectionType: "pw",
|
|
90
110
|
framework: "playwright",
|
|
91
111
|
testFilePath: "app/coverage/__testkit__/coverage.pw.testkit.ts",
|
|
92
|
-
coveredNodeIds: [
|
|
112
|
+
coveredNodeIds: [
|
|
113
|
+
"page_view:web:/coverage",
|
|
114
|
+
"ui_surface:web:/coverage:coverage-refresh-button",
|
|
115
|
+
],
|
|
93
116
|
details: {
|
|
94
117
|
route: "/coverage",
|
|
95
118
|
targets: [{ kind: "testId", value: "coverage-refresh-button", confidence: "high" }],
|
|
@@ -156,10 +179,18 @@ describe("testkit bridge", () => {
|
|
|
156
179
|
coverageState: "covered",
|
|
157
180
|
relatedFailureCount: 1,
|
|
158
181
|
relatedCoverageCount: 1,
|
|
182
|
+
coverageBreakdown: {
|
|
183
|
+
direct: 0,
|
|
184
|
+
indirect: 0,
|
|
185
|
+
mixed: 1,
|
|
186
|
+
},
|
|
159
187
|
},
|
|
160
188
|
failures: [
|
|
161
189
|
{
|
|
162
|
-
|
|
190
|
+
kind: "ui_surface",
|
|
191
|
+
label: "Refresh overlay",
|
|
192
|
+
importance: "high",
|
|
193
|
+
reason: "Refresh overlay is implicated by 1 failing test.",
|
|
163
194
|
targets: [{ kind: "testId", value: "coverage-refresh-button", confidence: "high" }],
|
|
164
195
|
failedTests: [
|
|
165
196
|
{
|
|
@@ -171,7 +202,10 @@ describe("testkit bridge", () => {
|
|
|
171
202
|
],
|
|
172
203
|
coverage: [
|
|
173
204
|
{
|
|
174
|
-
|
|
205
|
+
kind: "ui_surface",
|
|
206
|
+
label: "Refresh overlay",
|
|
207
|
+
importance: "high",
|
|
208
|
+
supportKind: "mixed",
|
|
175
209
|
targets: [{ kind: "testId", value: "coverage-refresh-button", confidence: "high" }],
|
|
176
210
|
supportingTests: [
|
|
177
211
|
{
|
|
@@ -5,6 +5,8 @@ export type BrowserTargetKind = "testId" | "role" | "text" | "css" | "xpath" | "
|
|
|
5
5
|
export type BrowserConfidence = "low" | "medium" | "high";
|
|
6
6
|
export type BrowserFailureState = "failing" | "healthy" | "unavailable";
|
|
7
7
|
export type BrowserCoverageState = "covered" | "missing" | "unavailable";
|
|
8
|
+
export type BridgeSurfaceImportance = "critical" | "high" | "medium" | "low";
|
|
9
|
+
export type BridgeCoverageSupportKind = "direct" | "indirect" | "mixed";
|
|
8
10
|
|
|
9
11
|
export type CoverageNodeKind =
|
|
10
12
|
| "page_view"
|
|
@@ -86,11 +88,22 @@ export interface CoverageEvidence {
|
|
|
86
88
|
};
|
|
87
89
|
}
|
|
88
90
|
|
|
91
|
+
export type CoverageGraphDiagnosticLevel = "info" | "warn";
|
|
92
|
+
|
|
93
|
+
export interface CoverageGraphDiagnostic {
|
|
94
|
+
level: CoverageGraphDiagnosticLevel;
|
|
95
|
+
code: string;
|
|
96
|
+
filePath: string;
|
|
97
|
+
service: string;
|
|
98
|
+
message: string;
|
|
99
|
+
}
|
|
100
|
+
|
|
89
101
|
export interface CoverageGraph {
|
|
90
102
|
schemaVersion: number;
|
|
91
103
|
nodes: CoverageGraphNode[];
|
|
92
104
|
edges: CoverageGraphEdge[];
|
|
93
105
|
evidence: CoverageEvidence[];
|
|
106
|
+
diagnostics: CoverageGraphDiagnostic[];
|
|
94
107
|
}
|
|
95
108
|
|
|
96
109
|
export interface BridgeProductRef {
|
|
@@ -149,6 +162,9 @@ export interface FailureOverlayEntry {
|
|
|
149
162
|
targets: BrowserTarget[];
|
|
150
163
|
failedTests: BridgeSupportingTestRef[];
|
|
151
164
|
viaNodes: BridgeCoverageViaNodeRef[];
|
|
165
|
+
importance?: BridgeSurfaceImportance;
|
|
166
|
+
surfaceKind?: string | null;
|
|
167
|
+
reason?: string | null;
|
|
152
168
|
}
|
|
153
169
|
|
|
154
170
|
export interface CoverageOverlayEntry {
|
|
@@ -161,6 +177,10 @@ export interface CoverageOverlayEntry {
|
|
|
161
177
|
supportingTests: BridgeSupportingTestRef[];
|
|
162
178
|
viaNodes: BridgeCoverageViaNodeRef[];
|
|
163
179
|
confidence: BrowserConfidence;
|
|
180
|
+
importance?: BridgeSurfaceImportance;
|
|
181
|
+
surfaceKind?: string | null;
|
|
182
|
+
supportKind?: BridgeCoverageSupportKind;
|
|
183
|
+
reason?: string | null;
|
|
164
184
|
}
|
|
165
185
|
|
|
166
186
|
export interface PageOverlayResponse {
|
|
@@ -177,6 +197,11 @@ export interface PageOverlayResponse {
|
|
|
177
197
|
coverageState: BrowserCoverageState;
|
|
178
198
|
relatedFailureCount: number;
|
|
179
199
|
relatedCoverageCount: number;
|
|
200
|
+
coverageBreakdown?: {
|
|
201
|
+
direct: number;
|
|
202
|
+
indirect: number;
|
|
203
|
+
mixed: number;
|
|
204
|
+
};
|
|
180
205
|
};
|
|
181
206
|
failures: FailureOverlayEntry[];
|
|
182
207
|
coverage: CoverageOverlayEntry[];
|
|
@@ -196,6 +221,7 @@ export declare function normalizeBrowserMetadataDocument(value: unknown): Browse
|
|
|
196
221
|
export declare function normalizeCoverageGraphNode(value: unknown): CoverageGraphNode | null;
|
|
197
222
|
export declare function normalizeCoverageGraphEdge(value: unknown): CoverageGraphEdge | null;
|
|
198
223
|
export declare function normalizeCoverageEvidence(value: unknown): CoverageEvidence | null;
|
|
224
|
+
export declare function normalizeCoverageGraphDiagnostic(value: unknown): CoverageGraphDiagnostic | null;
|
|
199
225
|
export declare function normalizeCoverageGraph(value: unknown): CoverageGraph | null;
|
|
200
226
|
export declare function normalizePageOverlayResponse(value: unknown): PageOverlayResponse | null;
|
|
201
227
|
export declare function isPageOverlayResponse(value: unknown): value is PageOverlayResponse;
|
|
@@ -158,6 +158,20 @@ export function normalizeCoverageEvidence(value) {
|
|
|
158
158
|
};
|
|
159
159
|
}
|
|
160
160
|
|
|
161
|
+
const DIAGNOSTIC_LEVELS = new Set(["info", "warn"]);
|
|
162
|
+
|
|
163
|
+
export function normalizeCoverageGraphDiagnostic(value) {
|
|
164
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return null;
|
|
165
|
+
const level = normalizeOptionalString(value.level);
|
|
166
|
+
const code = normalizeOptionalString(value.code);
|
|
167
|
+
const filePath = normalizeOptionalString(value.filePath);
|
|
168
|
+
const service = normalizeOptionalString(value.service);
|
|
169
|
+
const message = normalizeOptionalString(value.message);
|
|
170
|
+
if (!level || !code || !filePath || !service || !message) return null;
|
|
171
|
+
if (!DIAGNOSTIC_LEVELS.has(level)) return null;
|
|
172
|
+
return { level, code, filePath, service, message };
|
|
173
|
+
}
|
|
174
|
+
|
|
161
175
|
export function normalizeCoverageGraph(value) {
|
|
162
176
|
if (!value || typeof value !== "object" || Array.isArray(value)) return null;
|
|
163
177
|
const schemaVersion =
|
|
@@ -169,12 +183,16 @@ export function normalizeCoverageGraph(value) {
|
|
|
169
183
|
const evidence = Array.isArray(value.evidence)
|
|
170
184
|
? value.evidence.map(normalizeCoverageEvidence).filter(Boolean)
|
|
171
185
|
: [];
|
|
186
|
+
const diagnostics = Array.isArray(value.diagnostics)
|
|
187
|
+
? value.diagnostics.map(normalizeCoverageGraphDiagnostic).filter(Boolean)
|
|
188
|
+
: [];
|
|
172
189
|
if (nodes.length === 0) return null;
|
|
173
190
|
return {
|
|
174
191
|
schemaVersion,
|
|
175
192
|
nodes,
|
|
176
193
|
edges,
|
|
177
194
|
evidence,
|
|
195
|
+
diagnostics,
|
|
178
196
|
};
|
|
179
197
|
}
|
|
180
198
|
|
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
normalizeBrowserTarget,
|
|
7
7
|
normalizeCoverageEvidence,
|
|
8
8
|
normalizeCoverageGraph,
|
|
9
|
+
normalizeCoverageGraphDiagnostic,
|
|
9
10
|
normalizeCoverageGraphEdge,
|
|
10
11
|
normalizeCoverageGraphNode,
|
|
11
12
|
} from "./index.mjs";
|
|
@@ -107,7 +108,79 @@ describe("testkit browser protocol", () => {
|
|
|
107
108
|
});
|
|
108
109
|
});
|
|
109
110
|
|
|
110
|
-
it("normalizes graph
|
|
111
|
+
it("normalizes coverage graph diagnostics", () => {
|
|
112
|
+
expect(
|
|
113
|
+
normalizeCoverageGraphDiagnostic({
|
|
114
|
+
level: "warn",
|
|
115
|
+
code: "no-service-context",
|
|
116
|
+
filePath: "tests/example.int.testkit.ts",
|
|
117
|
+
service: "web",
|
|
118
|
+
message: 'No coverage context available for service "web".',
|
|
119
|
+
})
|
|
120
|
+
).toEqual({
|
|
121
|
+
level: "warn",
|
|
122
|
+
code: "no-service-context",
|
|
123
|
+
filePath: "tests/example.int.testkit.ts",
|
|
124
|
+
service: "web",
|
|
125
|
+
message: 'No coverage context available for service "web".',
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
expect(normalizeCoverageGraphDiagnostic({ level: "error", code: "x", filePath: "f", service: "s", message: "m" })).toBeNull();
|
|
129
|
+
expect(normalizeCoverageGraphDiagnostic({ level: "warn", code: "", filePath: "f", service: "s", message: "m" })).toBeNull();
|
|
130
|
+
expect(normalizeCoverageGraphDiagnostic(null)).toBeNull();
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
it("normalizes graph payloads with diagnostics", () => {
|
|
134
|
+
expect(
|
|
135
|
+
normalizeCoverageGraph({
|
|
136
|
+
schemaVersion: TESTKIT_COVERAGE_GRAPH_VERSION,
|
|
137
|
+
nodes: [
|
|
138
|
+
{
|
|
139
|
+
id: "page_view:web:/coverage",
|
|
140
|
+
kind: "page_view",
|
|
141
|
+
service: "web",
|
|
142
|
+
label: "Coverage",
|
|
143
|
+
route: "/coverage",
|
|
144
|
+
},
|
|
145
|
+
],
|
|
146
|
+
edges: [],
|
|
147
|
+
evidence: [],
|
|
148
|
+
diagnostics: [
|
|
149
|
+
{
|
|
150
|
+
level: "info",
|
|
151
|
+
code: "zero-coverage-inferred",
|
|
152
|
+
filePath: "tests/example.pw.testkit.ts",
|
|
153
|
+
service: "web",
|
|
154
|
+
message: "No routes matched.",
|
|
155
|
+
},
|
|
156
|
+
],
|
|
157
|
+
})
|
|
158
|
+
).toEqual({
|
|
159
|
+
schemaVersion: TESTKIT_COVERAGE_GRAPH_VERSION,
|
|
160
|
+
nodes: [
|
|
161
|
+
{
|
|
162
|
+
id: "page_view:web:/coverage",
|
|
163
|
+
kind: "page_view",
|
|
164
|
+
service: "web",
|
|
165
|
+
label: "Coverage",
|
|
166
|
+
route: "/coverage",
|
|
167
|
+
},
|
|
168
|
+
],
|
|
169
|
+
edges: [],
|
|
170
|
+
evidence: [],
|
|
171
|
+
diagnostics: [
|
|
172
|
+
{
|
|
173
|
+
level: "info",
|
|
174
|
+
code: "zero-coverage-inferred",
|
|
175
|
+
filePath: "tests/example.pw.testkit.ts",
|
|
176
|
+
service: "web",
|
|
177
|
+
message: "No routes matched.",
|
|
178
|
+
},
|
|
179
|
+
],
|
|
180
|
+
});
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
it("normalizes graph payloads without diagnostics field", () => {
|
|
111
184
|
expect(
|
|
112
185
|
normalizeCoverageGraph({
|
|
113
186
|
schemaVersion: TESTKIT_COVERAGE_GRAPH_VERSION,
|
|
@@ -136,6 +209,7 @@ describe("testkit browser protocol", () => {
|
|
|
136
209
|
],
|
|
137
210
|
edges: [],
|
|
138
211
|
evidence: [],
|
|
212
|
+
diagnostics: [],
|
|
139
213
|
});
|
|
140
214
|
});
|
|
141
215
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@elench/testkit",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.62",
|
|
4
4
|
"description": "CLI for discovering and running local HTTP, DAL, and Playwright test suites",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"workspaces": [
|
|
@@ -59,15 +59,16 @@
|
|
|
59
59
|
"vitest": "^3.2.4"
|
|
60
60
|
},
|
|
61
61
|
"dependencies": {
|
|
62
|
-
"@elench/testkit-bridge": "0.1.
|
|
63
|
-
"@elench/testkit-protocol": "0.1.
|
|
62
|
+
"@elench/testkit-bridge": "0.1.62",
|
|
63
|
+
"@elench/testkit-protocol": "0.1.62",
|
|
64
64
|
"@babel/code-frame": "^7.29.0",
|
|
65
65
|
"@oclif/core": "^4.10.6",
|
|
66
66
|
"esbuild": "^0.25.11",
|
|
67
67
|
"execa": "^9.5.0",
|
|
68
68
|
"ink": "^7.0.1",
|
|
69
69
|
"picocolors": "^1.1.1",
|
|
70
|
-
"react": "^19.2.5"
|
|
70
|
+
"react": "^19.2.5",
|
|
71
|
+
"typescript": "^5.9.3"
|
|
71
72
|
},
|
|
72
73
|
"engines": {
|
|
73
74
|
"node": ">=18"
|