@elench/testkit 0.1.118 → 0.1.119
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/app/doctor.mjs +11 -113
- package/lib/cli/assistant/command-observer.mjs +1 -1
- package/lib/cli/assistant/state.mjs +2 -0
- package/lib/cli/commands/lint.mjs +37 -0
- package/lib/cli/entrypoint.mjs +1 -0
- package/lib/cli/operations/lint/operation.mjs +12 -0
- package/lib/cli/renderers/doctor/text.mjs +5 -0
- package/lib/cli/renderers/lint/text.mjs +20 -0
- package/lib/config-api/database-steps.mjs +132 -0
- package/lib/config-api/index.d.ts +36 -3
- package/lib/config-api/index.mjs +118 -12
- package/lib/lint/index.mjs +569 -0
- package/lib/runner/template-steps.mjs +8 -0
- package/lib/runtime/index.d.ts +43 -0
- package/lib/runtime/index.mjs +24 -0
- package/lib/runtime-src/k6/http-assertions.js +82 -0
- package/lib/shared/configured-steps.mjs +16 -0
- package/lib/ui/index.d.ts +46 -0
- package/lib/ui/index.mjs +11 -0
- package/lib/ui/sandbox.mjs +115 -0
- package/node_modules/@elench/next-analysis/package.json +1 -1
- package/node_modules/@elench/testkit-bridge/package.json +2 -2
- package/node_modules/@elench/testkit-protocol/package.json +1 -1
- package/node_modules/@elench/ts-analysis/package.json +1 -1
- package/package.json +5 -5
- package/packages/testkit-bridge/node_modules/@elench/testkit-protocol/dist/index.d.ts +188 -0
- package/packages/testkit-bridge/node_modules/@elench/testkit-protocol/dist/index.d.ts.map +1 -0
- package/packages/testkit-bridge/node_modules/@elench/testkit-protocol/dist/index.js +293 -0
- package/packages/testkit-bridge/node_modules/@elench/testkit-protocol/dist/index.js.map +1 -0
- package/packages/testkit-bridge/node_modules/@elench/testkit-protocol/package.json +25 -0
package/lib/runtime/index.mjs
CHANGED
|
@@ -39,15 +39,23 @@ export {
|
|
|
39
39
|
singleIterationOptions,
|
|
40
40
|
} from "../runtime-src/k6/checks.js";
|
|
41
41
|
export {
|
|
42
|
+
captureError,
|
|
42
43
|
expectCondition,
|
|
44
|
+
expectError,
|
|
43
45
|
expectErrorMessage,
|
|
44
46
|
expectErrorShape,
|
|
47
|
+
expectField,
|
|
48
|
+
expectNoRows,
|
|
45
49
|
expectJson,
|
|
46
50
|
expectJsonPath,
|
|
47
51
|
expectNotStatus,
|
|
48
52
|
expectResponse,
|
|
53
|
+
expectRowCount,
|
|
54
|
+
expectSingleRow,
|
|
49
55
|
expectStatus,
|
|
50
56
|
expectStatusOneOf,
|
|
57
|
+
expectTruthyField,
|
|
58
|
+
expectType,
|
|
51
59
|
expectValue,
|
|
52
60
|
} from "../runtime-src/k6/http-assertions.js";
|
|
53
61
|
export {
|
|
@@ -72,15 +80,23 @@ export {
|
|
|
72
80
|
} from "../runtime-src/k6/http.js";
|
|
73
81
|
|
|
74
82
|
import {
|
|
83
|
+
captureError,
|
|
75
84
|
expectCondition,
|
|
85
|
+
expectError,
|
|
76
86
|
expectErrorMessage,
|
|
77
87
|
expectErrorShape,
|
|
88
|
+
expectField,
|
|
89
|
+
expectNoRows,
|
|
78
90
|
expectJson,
|
|
79
91
|
expectJsonPath,
|
|
80
92
|
expectNotStatus,
|
|
81
93
|
expectResponse,
|
|
94
|
+
expectRowCount,
|
|
95
|
+
expectSingleRow,
|
|
82
96
|
expectStatus,
|
|
83
97
|
expectStatusOneOf,
|
|
98
|
+
expectTruthyField,
|
|
99
|
+
expectType,
|
|
84
100
|
expectValue,
|
|
85
101
|
} from "../runtime-src/k6/http-assertions.js";
|
|
86
102
|
import {
|
|
@@ -90,17 +106,25 @@ import {
|
|
|
90
106
|
import { safeJson } from "../runtime-src/k6/http.js";
|
|
91
107
|
|
|
92
108
|
export const expect = {
|
|
109
|
+
captureError,
|
|
93
110
|
condition: expectCondition,
|
|
94
111
|
error: {
|
|
112
|
+
captured: expectError,
|
|
95
113
|
message: expectErrorMessage,
|
|
96
114
|
shape: expectErrorShape,
|
|
97
115
|
},
|
|
116
|
+
field: expectField,
|
|
98
117
|
json: expectJson,
|
|
99
118
|
jsonPath: expectJsonPath,
|
|
119
|
+
noRows: expectNoRows,
|
|
100
120
|
notStatus: expectNotStatus,
|
|
101
121
|
response: expectResponse,
|
|
122
|
+
rowCount: expectRowCount,
|
|
123
|
+
singleRow: expectSingleRow,
|
|
102
124
|
status: expectStatus,
|
|
103
125
|
statusOneOf: expectStatusOneOf,
|
|
126
|
+
truthyField: expectTruthyField,
|
|
127
|
+
type: expectType,
|
|
104
128
|
value: expectValue,
|
|
105
129
|
};
|
|
106
130
|
|
|
@@ -152,6 +152,77 @@ export function expectCondition(predicate, label) {
|
|
|
152
152
|
});
|
|
153
153
|
}
|
|
154
154
|
|
|
155
|
+
export function expectRowCount(rows, expectedCount, label = null) {
|
|
156
|
+
const expected = Number(expectedCount);
|
|
157
|
+
if (!Number.isInteger(expected) || expected < 0) {
|
|
158
|
+
throw new Error("expectRowCount requires a non-negative integer count");
|
|
159
|
+
}
|
|
160
|
+
return expectValue(
|
|
161
|
+
rows,
|
|
162
|
+
(value) => Array.isArray(value) && value.length === expected,
|
|
163
|
+
normalizeLabel(label, `row count is ${expected}`)
|
|
164
|
+
);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
export function expectSingleRow(rows, label = "query returns one row") {
|
|
168
|
+
if (!expectRowCount(rows, 1, label)) return null;
|
|
169
|
+
return rows[0];
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
export function expectNoRows(rows, label = "query returns no rows") {
|
|
173
|
+
return expectRowCount(rows, 0, label);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
export function expectField(row, field, predicateOrExpected, label = null) {
|
|
177
|
+
const fieldName = String(field || "");
|
|
178
|
+
return expectValue(
|
|
179
|
+
row?.[fieldName],
|
|
180
|
+
normalizeFieldPredicate(predicateOrExpected),
|
|
181
|
+
normalizeLabel(label, `${fieldName || "field"} matches expectation`)
|
|
182
|
+
);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
export function expectTruthyField(row, field, label = null) {
|
|
186
|
+
const fieldName = String(field || "");
|
|
187
|
+
return expectField(
|
|
188
|
+
row,
|
|
189
|
+
fieldName,
|
|
190
|
+
(value) => Boolean(value),
|
|
191
|
+
normalizeLabel(label, `${fieldName || "field"} is truthy`)
|
|
192
|
+
);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
export function expectType(value, typeName, label = null) {
|
|
196
|
+
const expected = String(typeName || "").trim();
|
|
197
|
+
if (!expected) throw new Error("expectType requires a type name");
|
|
198
|
+
return expectValue(
|
|
199
|
+
value,
|
|
200
|
+
(actual) => actualType(actual) === expected,
|
|
201
|
+
normalizeLabel(label, `type is ${expected}`)
|
|
202
|
+
);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
export function captureError(fn) {
|
|
206
|
+
try {
|
|
207
|
+
fn();
|
|
208
|
+
return null;
|
|
209
|
+
} catch (error) {
|
|
210
|
+
return error;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
export function expectError(errorOrFn, predicate = null, label = null) {
|
|
215
|
+
const error = typeof errorOrFn === "function" ? captureError(errorOrFn) : errorOrFn;
|
|
216
|
+
return expectValue(
|
|
217
|
+
error,
|
|
218
|
+
(value) => {
|
|
219
|
+
if (!value) return false;
|
|
220
|
+
return typeof predicate === "function" ? Boolean(predicate(value)) : true;
|
|
221
|
+
},
|
|
222
|
+
normalizeLabel(label, "error is captured")
|
|
223
|
+
);
|
|
224
|
+
}
|
|
225
|
+
|
|
155
226
|
function buildHttpAssertionDetail({ kind, title, trace, expected, actual, response, message }) {
|
|
156
227
|
return {
|
|
157
228
|
kind,
|
|
@@ -238,6 +309,17 @@ function toValuePreview(value) {
|
|
|
238
309
|
}
|
|
239
310
|
}
|
|
240
311
|
|
|
312
|
+
function normalizeFieldPredicate(predicateOrExpected) {
|
|
313
|
+
if (typeof predicateOrExpected === "function") return predicateOrExpected;
|
|
314
|
+
return (value) => Object.is(value, predicateOrExpected);
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
function actualType(value) {
|
|
318
|
+
if (value === null) return "null";
|
|
319
|
+
if (Array.isArray(value)) return "array";
|
|
320
|
+
return typeof value;
|
|
321
|
+
}
|
|
322
|
+
|
|
241
323
|
function normalizeLabel(value, fallback) {
|
|
242
324
|
const normalized = typeof value === "string" ? value.trim() : "";
|
|
243
325
|
return normalized.length > 0 ? normalized : fallback;
|
|
@@ -55,31 +55,37 @@ export function normalizeConfiguredStep(step, label) {
|
|
|
55
55
|
if (kind === "command") {
|
|
56
56
|
const cmd = normalizeOptionalString(step.run);
|
|
57
57
|
if (!cmd) throw new Error(`${label}.run must be a non-empty string`);
|
|
58
|
+
const args = normalizeStepArgs(step.args, label);
|
|
58
59
|
return {
|
|
59
60
|
kind,
|
|
60
61
|
cmd,
|
|
61
62
|
cwd: normalizeOptionalString(step.cwd),
|
|
62
63
|
inputs: normalizeConfiguredStepInputs(step.inputs, label),
|
|
64
|
+
...(args !== undefined ? { args } : {}),
|
|
63
65
|
};
|
|
64
66
|
}
|
|
65
67
|
if (kind === "sql-file") {
|
|
66
68
|
const filePath = normalizeOptionalString(step.path);
|
|
67
69
|
if (!filePath) throw new Error(`${label}.path must be a non-empty string`);
|
|
70
|
+
const args = normalizeStepArgs(step.args, label);
|
|
68
71
|
return {
|
|
69
72
|
kind,
|
|
70
73
|
path: filePath,
|
|
71
74
|
cwd: normalizeOptionalString(step.cwd),
|
|
72
75
|
inputs: normalizeConfiguredStepInputs(step.inputs, label),
|
|
76
|
+
...(args !== undefined ? { args } : {}),
|
|
73
77
|
};
|
|
74
78
|
}
|
|
75
79
|
if (kind === "module") {
|
|
76
80
|
const specifier = normalizeOptionalString(step.target);
|
|
77
81
|
if (!specifier) throw new Error(`${label}.target must be a non-empty string`);
|
|
82
|
+
const args = normalizeStepArgs(step.args, label);
|
|
78
83
|
return {
|
|
79
84
|
kind,
|
|
80
85
|
specifier,
|
|
81
86
|
cwd: normalizeOptionalString(step.cwd),
|
|
82
87
|
inputs: normalizeConfiguredStepInputs(step.inputs, label),
|
|
88
|
+
...(args !== undefined ? { args } : {}),
|
|
83
89
|
};
|
|
84
90
|
}
|
|
85
91
|
|
|
@@ -94,6 +100,15 @@ export function parseModuleSpecifier(specifier) {
|
|
|
94
100
|
};
|
|
95
101
|
}
|
|
96
102
|
|
|
103
|
+
export function normalizeStepArgs(value, label) {
|
|
104
|
+
if (value == null) return undefined;
|
|
105
|
+
try {
|
|
106
|
+
return JSON.parse(JSON.stringify(value));
|
|
107
|
+
} catch {
|
|
108
|
+
throw new Error(`${label}.args must be JSON-serializable`);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
97
112
|
export function isBareModuleSpecifier(modulePath) {
|
|
98
113
|
if (typeof modulePath !== "string" || modulePath.length === 0) return false;
|
|
99
114
|
if (modulePath.startsWith("./") || modulePath.startsWith("../")) return false;
|
|
@@ -155,6 +170,7 @@ export function finalizeConfiguredStep(step, transform) {
|
|
|
155
170
|
...(typeof step.path === "string" ? { path: transform(step.path) } : {}),
|
|
156
171
|
...(typeof step.specifier === "string" ? { specifier: transform(step.specifier) } : {}),
|
|
157
172
|
inputs: finalizeConfiguredInputs(step.inputs || [], transform),
|
|
173
|
+
...(step.args !== undefined ? { args: step.args } : {}),
|
|
158
174
|
};
|
|
159
175
|
}
|
|
160
176
|
|
package/lib/ui/index.d.ts
CHANGED
|
@@ -1,3 +1,49 @@
|
|
|
1
1
|
export * from "@playwright/test";
|
|
2
2
|
export { defineConfig } from "../playwright/index";
|
|
3
3
|
export type { PlaywrightConfigOptions } from "../playwright/index";
|
|
4
|
+
|
|
5
|
+
export interface UiSandboxOptions {
|
|
6
|
+
allowRemote?: boolean;
|
|
7
|
+
backendBaseUrl?: string;
|
|
8
|
+
baseUrl?: string;
|
|
9
|
+
frontendBaseUrl?: string;
|
|
10
|
+
headers?: Record<string, string>;
|
|
11
|
+
prefix?: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export interface UiSandboxFixture {
|
|
15
|
+
id: string;
|
|
16
|
+
backendBaseUrl: string;
|
|
17
|
+
frontendBaseUrl: string;
|
|
18
|
+
page: import("@playwright/test").Page;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export declare function createUiSandbox(options?: UiSandboxOptions): {
|
|
22
|
+
expect: typeof import("@playwright/test").expect;
|
|
23
|
+
test: import("@playwright/test").TestType<
|
|
24
|
+
import("@playwright/test").PlaywrightTestArgs & import("@playwright/test").PlaywrightTestOptions & {
|
|
25
|
+
testkitSandbox: UiSandboxFixture;
|
|
26
|
+
},
|
|
27
|
+
import("@playwright/test").PlaywrightWorkerArgs & import("@playwright/test").PlaywrightWorkerOptions
|
|
28
|
+
>;
|
|
29
|
+
};
|
|
30
|
+
export declare function createSandboxId(options?: Pick<UiSandboxOptions, "prefix">): string;
|
|
31
|
+
export declare function resolveFrontendBaseUrl(options?: UiSandboxOptions): string;
|
|
32
|
+
export declare function resolveBackendBaseUrl(options?: UiSandboxOptions): string;
|
|
33
|
+
export declare function assertSafeUiTarget(url: string, options?: Pick<UiSandboxOptions, "allowRemote">): string;
|
|
34
|
+
export declare function assertSafeUiTargets(
|
|
35
|
+
urls?: string[],
|
|
36
|
+
options?: Pick<UiSandboxOptions, "allowRemote">
|
|
37
|
+
): string[];
|
|
38
|
+
export declare function createAuthedApiClient(
|
|
39
|
+
playwrightRequest?: typeof import("@playwright/test").request,
|
|
40
|
+
options?: UiSandboxOptions
|
|
41
|
+
): Promise<import("@playwright/test").APIRequestContext>;
|
|
42
|
+
export declare function waitForUiSettled(
|
|
43
|
+
page: import("@playwright/test").Page,
|
|
44
|
+
options?: { frames?: number; timeout?: number }
|
|
45
|
+
): Promise<void>;
|
|
46
|
+
export declare function waitForAnimationFrames(
|
|
47
|
+
page: import("@playwright/test").Page,
|
|
48
|
+
frames?: number
|
|
49
|
+
): Promise<void>;
|
package/lib/ui/index.mjs
CHANGED
|
@@ -1,2 +1,13 @@
|
|
|
1
1
|
export * from "@playwright/test";
|
|
2
2
|
export { defineConfig } from "../playwright/index.mjs";
|
|
3
|
+
export {
|
|
4
|
+
assertSafeUiTarget,
|
|
5
|
+
assertSafeUiTargets,
|
|
6
|
+
createAuthedApiClient,
|
|
7
|
+
createSandboxId,
|
|
8
|
+
createUiSandbox,
|
|
9
|
+
resolveBackendBaseUrl,
|
|
10
|
+
resolveFrontendBaseUrl,
|
|
11
|
+
waitForAnimationFrames,
|
|
12
|
+
waitForUiSettled,
|
|
13
|
+
} from "./sandbox.mjs";
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { expect, request, test as base } from "@playwright/test";
|
|
2
|
+
|
|
3
|
+
export function createUiSandbox(options = {}) {
|
|
4
|
+
const sandboxId = createSandboxId(options);
|
|
5
|
+
return {
|
|
6
|
+
expect,
|
|
7
|
+
test: base.extend({
|
|
8
|
+
testkitSandbox: async ({ page }, use) => {
|
|
9
|
+
await use({
|
|
10
|
+
id: sandboxId,
|
|
11
|
+
backendBaseUrl: resolveBackendBaseUrl(options),
|
|
12
|
+
frontendBaseUrl: resolveFrontendBaseUrl(options),
|
|
13
|
+
page,
|
|
14
|
+
});
|
|
15
|
+
},
|
|
16
|
+
}),
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function createSandboxId(options = {}) {
|
|
21
|
+
const prefix =
|
|
22
|
+
String(options.prefix || "ui").replace(/[^A-Za-z0-9_-]+/g, "-").replace(/^-+|-+$/g, "") || "ui";
|
|
23
|
+
const worker = process.env.TEST_WORKER_INDEX || process.env.TESTKIT_WORKER_INDEX || "0";
|
|
24
|
+
const run = process.env.TESTKIT_LEASE_ID || process.env.TESTKIT_RUNTIME_ID || process.pid;
|
|
25
|
+
return `${prefix}-${run}-${worker}`;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function resolveFrontendBaseUrl(options = {}) {
|
|
29
|
+
return resolveBaseUrl(
|
|
30
|
+
options.frontendBaseUrl ||
|
|
31
|
+
options.baseUrl ||
|
|
32
|
+
process.env.TESTKIT_FRONTEND_BASE_URL ||
|
|
33
|
+
process.env.BASE_URL
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export function resolveBackendBaseUrl(options = {}) {
|
|
38
|
+
return resolveBaseUrl(options.backendBaseUrl || process.env.TESTKIT_BACKEND_BASE_URL || process.env.API_BASE_URL);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function assertSafeUiTarget(url, options = {}) {
|
|
42
|
+
const parsed = parseUrl(url);
|
|
43
|
+
if (!parsed) {
|
|
44
|
+
throw new Error(`Invalid UI target URL: ${url}`);
|
|
45
|
+
}
|
|
46
|
+
if (options.allowRemote === true) return parsed.toString().replace(/\/$/, "");
|
|
47
|
+
if (!isLocalHost(parsed.hostname)) {
|
|
48
|
+
throw new Error(`UI target must be local unless allowRemote is true: ${url}`);
|
|
49
|
+
}
|
|
50
|
+
return parsed.toString().replace(/\/$/, "");
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export function assertSafeUiTargets(urls = [], options = {}) {
|
|
54
|
+
return urls.map((url) => assertSafeUiTarget(url, options));
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export async function createAuthedApiClient(playwrightRequest = request, options = {}) {
|
|
58
|
+
const baseURL = assertSafeUiTarget(resolveBackendBaseUrl(options), options);
|
|
59
|
+
return playwrightRequest.newContext({
|
|
60
|
+
baseURL,
|
|
61
|
+
extraHTTPHeaders: options.headers || {},
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export async function waitForUiSettled(page, options = {}) {
|
|
66
|
+
const timeout = options.timeout ?? 5_000;
|
|
67
|
+
await page.waitForLoadState("domcontentloaded", { timeout });
|
|
68
|
+
await waitForAnimationFrames(page, options.frames ?? 2);
|
|
69
|
+
await page.waitForLoadState("networkidle", { timeout }).catch(() => {});
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export async function waitForAnimationFrames(page, frames = 2) {
|
|
73
|
+
const count = Math.max(1, Number(frames) || 1);
|
|
74
|
+
await page.evaluate(
|
|
75
|
+
(frameCount) =>
|
|
76
|
+
new Promise((resolve) => {
|
|
77
|
+
let remaining = frameCount;
|
|
78
|
+
const tick = () => {
|
|
79
|
+
remaining -= 1;
|
|
80
|
+
if (remaining <= 0) {
|
|
81
|
+
resolve();
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
requestAnimationFrame(tick);
|
|
85
|
+
};
|
|
86
|
+
requestAnimationFrame(tick);
|
|
87
|
+
}),
|
|
88
|
+
count
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function resolveBaseUrl(value) {
|
|
93
|
+
const normalized = String(value || "").trim();
|
|
94
|
+
if (!normalized) {
|
|
95
|
+
throw new Error("A UI base URL is required");
|
|
96
|
+
}
|
|
97
|
+
return assertSafeUiTarget(normalized);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function parseUrl(value) {
|
|
101
|
+
try {
|
|
102
|
+
return new URL(value);
|
|
103
|
+
} catch {
|
|
104
|
+
return null;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function isLocalHost(hostname) {
|
|
109
|
+
return (
|
|
110
|
+
hostname === "localhost" ||
|
|
111
|
+
hostname === "127.0.0.1" ||
|
|
112
|
+
hostname === "::1" ||
|
|
113
|
+
hostname.endsWith(".localhost")
|
|
114
|
+
);
|
|
115
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@elench/testkit-bridge",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.119",
|
|
4
4
|
"description": "Browser bridge helpers for testkit",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
"typecheck": "tsc -p tsconfig.json --noEmit"
|
|
23
23
|
},
|
|
24
24
|
"dependencies": {
|
|
25
|
-
"@elench/testkit-protocol": "0.1.
|
|
25
|
+
"@elench/testkit-protocol": "0.1.119"
|
|
26
26
|
},
|
|
27
27
|
"private": false
|
|
28
28
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@elench/testkit",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.119",
|
|
4
4
|
"description": "Assistant-first CLI for running, inspecting, and debugging local testkit suites",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"workspaces": [
|
|
@@ -95,10 +95,10 @@
|
|
|
95
95
|
},
|
|
96
96
|
"dependencies": {
|
|
97
97
|
"@babel/code-frame": "^7.29.0",
|
|
98
|
-
"@elench/next-analysis": "0.1.
|
|
99
|
-
"@elench/testkit-bridge": "0.1.
|
|
100
|
-
"@elench/testkit-protocol": "0.1.
|
|
101
|
-
"@elench/ts-analysis": "0.1.
|
|
98
|
+
"@elench/next-analysis": "0.1.119",
|
|
99
|
+
"@elench/testkit-bridge": "0.1.119",
|
|
100
|
+
"@elench/testkit-protocol": "0.1.119",
|
|
101
|
+
"@elench/ts-analysis": "0.1.119",
|
|
102
102
|
"@oclif/core": "^4.10.6",
|
|
103
103
|
"@playwright/test": "^1.52.0",
|
|
104
104
|
"esbuild": "^0.25.11",
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
export declare const TESTKIT_BROWSER_PROTOCOL_VERSION = 1;
|
|
2
|
+
export declare const TESTKIT_COVERAGE_GRAPH_VERSION = 1;
|
|
3
|
+
export type BrowserTargetKind = "testId" | "role" | "text" | "css" | "xpath" | "component";
|
|
4
|
+
export type BrowserConfidence = "low" | "medium" | "high";
|
|
5
|
+
export type BrowserFailureState = "failing" | "healthy" | "unavailable";
|
|
6
|
+
export type BrowserCoverageState = "covered" | "missing" | "unavailable";
|
|
7
|
+
export type BridgeSurfaceImportance = "critical" | "high" | "medium" | "low";
|
|
8
|
+
export type BridgeCoverageSupportKind = "direct" | "indirect" | "mixed";
|
|
9
|
+
export type CoverageNodeKind = "page_view" | "ui_surface" | "ui_action" | "client_request" | "api_route" | "server_action" | "server_capability" | "data_capability" | "test_file";
|
|
10
|
+
export type CoverageEdgeKind = "contains" | "renders" | "triggers" | "requests" | "handles" | "delegates_to" | "covers";
|
|
11
|
+
export type CoverageEvidenceSource = "convention" | "static" | "runtime";
|
|
12
|
+
export type CoverageGraphDiagnosticLevel = "info" | "warn";
|
|
13
|
+
export interface BrowserTarget {
|
|
14
|
+
kind: BrowserTargetKind;
|
|
15
|
+
value: string;
|
|
16
|
+
label?: string;
|
|
17
|
+
confidence?: BrowserConfidence;
|
|
18
|
+
}
|
|
19
|
+
export interface BrowserMetadata {
|
|
20
|
+
label?: string;
|
|
21
|
+
origins?: string[];
|
|
22
|
+
routes?: string[];
|
|
23
|
+
targets?: BrowserTarget[];
|
|
24
|
+
}
|
|
25
|
+
export interface BrowserMetadataDocument {
|
|
26
|
+
schemaVersion: number;
|
|
27
|
+
browser: BrowserMetadata;
|
|
28
|
+
}
|
|
29
|
+
export interface CoverageGraphNode {
|
|
30
|
+
id: string;
|
|
31
|
+
kind: CoverageNodeKind;
|
|
32
|
+
service: string;
|
|
33
|
+
label: string;
|
|
34
|
+
filePath?: string;
|
|
35
|
+
route?: string;
|
|
36
|
+
method?: string;
|
|
37
|
+
path?: string;
|
|
38
|
+
target?: BrowserTarget | null;
|
|
39
|
+
metadata?: Record<string, string | number | boolean | null>;
|
|
40
|
+
}
|
|
41
|
+
export interface CoverageGraphEdge {
|
|
42
|
+
id: string;
|
|
43
|
+
kind: CoverageEdgeKind;
|
|
44
|
+
from: string;
|
|
45
|
+
to: string;
|
|
46
|
+
confidence?: BrowserConfidence;
|
|
47
|
+
metadata?: Record<string, string | number | boolean | null>;
|
|
48
|
+
}
|
|
49
|
+
export interface CoverageEvidenceDetails {
|
|
50
|
+
requestPaths?: string[];
|
|
51
|
+
route?: string;
|
|
52
|
+
targets?: BrowserTarget[];
|
|
53
|
+
}
|
|
54
|
+
export interface CoverageEvidence {
|
|
55
|
+
id: string;
|
|
56
|
+
source: CoverageEvidenceSource;
|
|
57
|
+
confidence?: BrowserConfidence;
|
|
58
|
+
service: string;
|
|
59
|
+
suiteName: string;
|
|
60
|
+
type: string;
|
|
61
|
+
testFilePath: string;
|
|
62
|
+
coveredNodeIds: string[];
|
|
63
|
+
details?: CoverageEvidenceDetails;
|
|
64
|
+
}
|
|
65
|
+
export interface CoverageGraphDiagnostic {
|
|
66
|
+
level: CoverageGraphDiagnosticLevel;
|
|
67
|
+
code: string;
|
|
68
|
+
filePath: string;
|
|
69
|
+
service: string;
|
|
70
|
+
message: string;
|
|
71
|
+
}
|
|
72
|
+
export interface CoverageGraph {
|
|
73
|
+
schemaVersion: number;
|
|
74
|
+
nodes: CoverageGraphNode[];
|
|
75
|
+
edges: CoverageGraphEdge[];
|
|
76
|
+
evidence: CoverageEvidence[];
|
|
77
|
+
diagnostics: CoverageGraphDiagnostic[];
|
|
78
|
+
}
|
|
79
|
+
export interface BridgeProductRef {
|
|
80
|
+
name: string;
|
|
81
|
+
directory: string;
|
|
82
|
+
}
|
|
83
|
+
export interface BridgeServiceRef {
|
|
84
|
+
name: string;
|
|
85
|
+
baseUrl: string;
|
|
86
|
+
origin: string;
|
|
87
|
+
}
|
|
88
|
+
export interface BrowserMatchResponse {
|
|
89
|
+
protocolVersion: number;
|
|
90
|
+
url: string;
|
|
91
|
+
origin: string;
|
|
92
|
+
route: string;
|
|
93
|
+
matched: boolean;
|
|
94
|
+
product: BridgeProductRef;
|
|
95
|
+
service: BridgeServiceRef | null;
|
|
96
|
+
}
|
|
97
|
+
export interface BridgeRunSummary {
|
|
98
|
+
artifactAvailable: boolean;
|
|
99
|
+
generatedAt: string | null;
|
|
100
|
+
status: string | null;
|
|
101
|
+
}
|
|
102
|
+
export interface BridgeSupportingTestRef {
|
|
103
|
+
service: string;
|
|
104
|
+
suite: string;
|
|
105
|
+
type: string;
|
|
106
|
+
filePath: string;
|
|
107
|
+
label: string;
|
|
108
|
+
status?: "passed" | "failed" | "skipped" | "not_run";
|
|
109
|
+
error?: string | null;
|
|
110
|
+
}
|
|
111
|
+
export interface BridgeCoverageViaNodeRef {
|
|
112
|
+
id: string;
|
|
113
|
+
kind: CoverageNodeKind;
|
|
114
|
+
label: string;
|
|
115
|
+
route?: string;
|
|
116
|
+
method?: string;
|
|
117
|
+
path?: string;
|
|
118
|
+
}
|
|
119
|
+
export interface FailureOverlayEntry {
|
|
120
|
+
id: string;
|
|
121
|
+
kind: CoverageNodeKind;
|
|
122
|
+
label: string;
|
|
123
|
+
service: string;
|
|
124
|
+
route?: string | null;
|
|
125
|
+
targets: BrowserTarget[];
|
|
126
|
+
failedTests: BridgeSupportingTestRef[];
|
|
127
|
+
viaNodes: BridgeCoverageViaNodeRef[];
|
|
128
|
+
importance?: BridgeSurfaceImportance;
|
|
129
|
+
surfaceKind?: string | null;
|
|
130
|
+
reason?: string | null;
|
|
131
|
+
}
|
|
132
|
+
export interface CoverageOverlayEntry {
|
|
133
|
+
id: string;
|
|
134
|
+
kind: CoverageNodeKind;
|
|
135
|
+
label: string;
|
|
136
|
+
service: string;
|
|
137
|
+
route?: string | null;
|
|
138
|
+
targets: BrowserTarget[];
|
|
139
|
+
supportingTests: BridgeSupportingTestRef[];
|
|
140
|
+
viaNodes: BridgeCoverageViaNodeRef[];
|
|
141
|
+
confidence: BrowserConfidence;
|
|
142
|
+
importance?: BridgeSurfaceImportance;
|
|
143
|
+
surfaceKind?: string | null;
|
|
144
|
+
supportKind?: BridgeCoverageSupportKind;
|
|
145
|
+
reason?: string | null;
|
|
146
|
+
}
|
|
147
|
+
export interface PageOverlayResponse {
|
|
148
|
+
protocolVersion: number;
|
|
149
|
+
page: {
|
|
150
|
+
url: string;
|
|
151
|
+
origin: string;
|
|
152
|
+
route: string;
|
|
153
|
+
};
|
|
154
|
+
match: BrowserMatchResponse;
|
|
155
|
+
run: BridgeRunSummary;
|
|
156
|
+
summary: {
|
|
157
|
+
failureState: BrowserFailureState;
|
|
158
|
+
coverageState: BrowserCoverageState;
|
|
159
|
+
relatedFailureCount: number;
|
|
160
|
+
relatedCoverageCount: number;
|
|
161
|
+
coverageBreakdown?: {
|
|
162
|
+
direct: number;
|
|
163
|
+
indirect: number;
|
|
164
|
+
mixed: number;
|
|
165
|
+
};
|
|
166
|
+
};
|
|
167
|
+
failures: FailureOverlayEntry[];
|
|
168
|
+
coverage: CoverageOverlayEntry[];
|
|
169
|
+
}
|
|
170
|
+
export interface BridgeErrorResponse {
|
|
171
|
+
protocolVersion: number;
|
|
172
|
+
error: {
|
|
173
|
+
code: string;
|
|
174
|
+
message: string;
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
export declare function normalizeBrowserTarget(value: unknown): BrowserTarget | null;
|
|
178
|
+
export declare function normalizeBrowserMetadata(value: unknown): BrowserMetadata | null;
|
|
179
|
+
export declare function normalizeBrowserMetadataDocument(value: unknown): BrowserMetadataDocument | null;
|
|
180
|
+
export declare function normalizeCoverageGraphNode(value: unknown): CoverageGraphNode | null;
|
|
181
|
+
export declare function normalizeCoverageGraphEdge(value: unknown): CoverageGraphEdge | null;
|
|
182
|
+
export declare function normalizeCoverageEvidence(value: unknown): CoverageEvidence | null;
|
|
183
|
+
export declare function normalizeCoverageGraphDiagnostic(value: unknown): CoverageGraphDiagnostic | null;
|
|
184
|
+
export declare function normalizeCoverageGraph(value: unknown): CoverageGraph | null;
|
|
185
|
+
export declare function isPageOverlayResponse(value: unknown): value is PageOverlayResponse;
|
|
186
|
+
export declare function normalizePageOverlayResponse(value: unknown): PageOverlayResponse | null;
|
|
187
|
+
export declare function createBridgeErrorResponse(code: string, message: string): BridgeErrorResponse;
|
|
188
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|