@elench/testkit 0.1.82 → 0.1.84

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 (100) hide show
  1. package/README.md +37 -7
  2. package/lib/cli/agents/index.mjs +64 -0
  3. package/lib/cli/agents/investigate.mjs +75 -0
  4. package/lib/cli/agents/investigation-context.mjs +102 -0
  5. package/lib/cli/agents/prompt-builder.mjs +25 -0
  6. package/lib/cli/agents/providers/claude.mjs +74 -0
  7. package/lib/cli/agents/providers/codex.mjs +83 -0
  8. package/lib/cli/agents/providers/shared.mjs +134 -0
  9. package/lib/cli/command-helpers.mjs +53 -25
  10. package/lib/cli/commands/investigate.mjs +87 -0
  11. package/lib/cli/entrypoint.mjs +3 -0
  12. package/lib/cli/presentation/colors.mjs +12 -0
  13. package/lib/cli/presentation/events-reporter.mjs +135 -0
  14. package/lib/cli/presentation/summary-box.mjs +11 -11
  15. package/lib/cli/presentation/tree-reporter.mjs +159 -0
  16. package/lib/cli/tui/run-app.mjs +1 -0
  17. package/lib/cli/tui/run-session-app.mjs +370 -0
  18. package/lib/cli/tui/run-session-state.mjs +481 -0
  19. package/lib/cli/tui/run-tree-state.mjs +1 -0
  20. package/lib/config-api/auth-fixtures.mjs +15 -10
  21. package/lib/discovery/index.mjs +1 -1
  22. package/lib/index.d.ts +5 -1
  23. package/lib/runner/orchestrator.mjs +1 -0
  24. package/lib/runtime/index.d.ts +138 -5
  25. package/lib/runtime/index.mjs +68 -2
  26. package/lib/runtime-src/k6/http-assertions.js +31 -1
  27. package/lib/runtime-src/k6/http-checks.js +120 -0
  28. package/lib/runtime-src/k6/http-suite-runtime.js +5 -1
  29. package/lib/runtime-src/k6/http.js +213 -23
  30. package/lib/runtime-src/shared/error-body.mjs +42 -0
  31. package/lib/runtime-src/shared/http-parsing.mjs +68 -0
  32. package/node_modules/@elench/next-analysis/package.json +1 -1
  33. package/node_modules/@elench/testkit-bridge/package.json +2 -2
  34. package/node_modules/@elench/testkit-protocol/package.json +1 -1
  35. package/node_modules/@elench/ts-analysis/package.json +1 -1
  36. package/package.json +7 -6
  37. package/lib/app/configs.test.mjs +0 -34
  38. package/lib/app/typecheck.test.mjs +0 -24
  39. package/lib/bundler/index.test.mjs +0 -164
  40. package/lib/cli/args.test.mjs +0 -110
  41. package/lib/cli/presentation/code-frames.test.mjs +0 -71
  42. package/lib/cli/presentation/run-reporter.test.mjs +0 -192
  43. package/lib/cli/presentation/summary-box.test.mjs +0 -43
  44. package/lib/cli/presentation/terminal-layout.test.mjs +0 -23
  45. package/lib/config/database.test.mjs +0 -29
  46. package/lib/config/discovery.test.mjs +0 -276
  47. package/lib/config/env.test.mjs +0 -40
  48. package/lib/config/index.test.mjs +0 -44
  49. package/lib/config/paths.test.mjs +0 -27
  50. package/lib/config/runtime.test.mjs +0 -82
  51. package/lib/config/skip-config.test.mjs +0 -63
  52. package/lib/config-api/index.test.mjs +0 -344
  53. package/lib/config-api/next-runtime-tsconfig.test.mjs +0 -58
  54. package/lib/coverage/backend-discovery.test.mjs +0 -61
  55. package/lib/coverage/evidence.test.mjs +0 -87
  56. package/lib/coverage/index.test.mjs +0 -715
  57. package/lib/coverage/routing.test.mjs +0 -36
  58. package/lib/coverage/shared.test.mjs +0 -72
  59. package/lib/database/fingerprint.test.mjs +0 -99
  60. package/lib/database/index.test.mjs +0 -95
  61. package/lib/database/naming.test.mjs +0 -39
  62. package/lib/database/state.test.mjs +0 -66
  63. package/lib/database/template-steps.test.mjs +0 -43
  64. package/lib/discovery/file-metadata.test.mjs +0 -51
  65. package/lib/discovery/index.test.mjs +0 -182
  66. package/lib/discovery/path-policy.test.mjs +0 -65
  67. package/lib/drizzle/index.test.mjs +0 -33
  68. package/lib/env/index.test.mjs +0 -82
  69. package/lib/history/index.test.mjs +0 -115
  70. package/lib/package.test.mjs +0 -59
  71. package/lib/playwright/index.test.mjs +0 -43
  72. package/lib/regressions/github.test.mjs +0 -324
  73. package/lib/regressions/index.test.mjs +0 -187
  74. package/lib/reporters/playwright.test.mjs +0 -167
  75. package/lib/runner/default-runtime-errors.test.mjs +0 -49
  76. package/lib/runner/execution-config.test.mjs +0 -67
  77. package/lib/runner/failure-details.test.mjs +0 -114
  78. package/lib/runner/formatting.test.mjs +0 -205
  79. package/lib/runner/metadata.test.mjs +0 -52
  80. package/lib/runner/planning.test.mjs +0 -371
  81. package/lib/runner/playwright-config.test.mjs +0 -78
  82. package/lib/runner/processes.test.mjs +0 -21
  83. package/lib/runner/regressions.test.mjs +0 -168
  84. package/lib/runner/reporting.test.mjs +0 -310
  85. package/lib/runner/results.test.mjs +0 -376
  86. package/lib/runner/runtime-manager.test.mjs +0 -252
  87. package/lib/runner/runtime-preparation.test.mjs +0 -141
  88. package/lib/runner/selection.test.mjs +0 -24
  89. package/lib/runner/setup-operations.test.mjs +0 -94
  90. package/lib/runner/state.test.mjs +0 -62
  91. package/lib/runner/suite-selection.test.mjs +0 -49
  92. package/lib/runner/template.test.mjs +0 -272
  93. package/lib/shared/build-config.test.mjs +0 -132
  94. package/lib/shared/configured-steps.test.mjs +0 -102
  95. package/lib/shared/execution-schema.test.mjs +0 -26
  96. package/lib/shared/file-timeout.test.mjs +0 -64
  97. package/lib/shared/test-context.test.mjs +0 -43
  98. package/lib/timing/index.test.mjs +0 -64
  99. package/lib/toolchains/index.test.mjs +0 -168
  100. package/lib/vitest/index.test.mjs +0 -20
@@ -1,272 +0,0 @@
1
- import fs from "fs";
2
- import os from "os";
3
- import path from "path";
4
- import { describe, expect, it } from "vitest";
5
- import {
6
- buildExecutionEnv,
7
- buildPlaywrightEnv,
8
- buildPortMap,
9
- buildTaskExecutionEnv,
10
- finalizeString,
11
- normalizeSocketHost,
12
- numericPortFromUrl,
13
- resolveRuntimeInstanceConfigs,
14
- resolveServiceStateDir,
15
- resolveTemplateString,
16
- rewriteUrlPort,
17
- socketFromUrl,
18
- } from "./template.mjs";
19
-
20
- function makeRuntimeConfig(name, local, extras = {}) {
21
- return {
22
- name,
23
- stateDir: extras.stateDir,
24
- runtimeId: extras.runtimeId,
25
- productDir: extras.productDir || process.cwd(),
26
- testkit: {
27
- local,
28
- runtime: extras.runtime || {
29
- instances: 1,
30
- maxConcurrentTasks: Infinity,
31
- prepare: {
32
- inputs: [],
33
- steps: [],
34
- },
35
- },
36
- envFiles: extras.envFiles || [],
37
- serviceEnv: extras.serviceEnv || {},
38
- databaseFrom: extras.databaseFrom,
39
- database: extras.database,
40
- templateContext: extras.templateContext,
41
- },
42
- };
43
- }
44
-
45
- describe("runner-template", () => {
46
- it("builds port maps and detects collisions", () => {
47
- const configs = [
48
- makeRuntimeConfig("api", { port: 3000, baseUrl: "http://127.0.0.1:{port}" }),
49
- makeRuntimeConfig("frontend", { port: 3001, baseUrl: "http://127.0.0.1:{port}" }),
50
- ];
51
-
52
- expect([...buildPortMap(configs, "runtime-2").entries()]).toEqual([
53
- ["api", 3100],
54
- ["frontend", 3101],
55
- ]);
56
- expect([...buildPortMap(configs, "runtime-1", { index: 1, stride: 2 }).entries()]).toEqual([
57
- ["api", 3200],
58
- ["frontend", 3201],
59
- ]);
60
-
61
- expect(() =>
62
- buildPortMap(
63
- [
64
- makeRuntimeConfig("api", { port: 3000, baseUrl: "http://127.0.0.1:{port}" }),
65
- makeRuntimeConfig("other", { port: 3000, baseUrl: "http://127.0.0.1:{port}" }),
66
- ],
67
- "runtime-1",
68
- { index: 0, stride: 2 }
69
- )
70
- ).toThrow("Runtime port collision");
71
- });
72
-
73
- it("resolves template strings and URL rewrites", () => {
74
- const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "testkit-template-"));
75
- const apiStateDir = path.join(tmpDir, "api");
76
- fs.mkdirSync(apiStateDir, { recursive: true });
77
- fs.writeFileSync(
78
- path.join(apiStateDir, "database_url"),
79
- "postgres://testkit:testkit@127.0.0.1:55432/runtime_db"
80
- );
81
-
82
- const context = {
83
- runtimeId: "runtime-2",
84
- serviceName: "frontend",
85
- serviceStateDir: "/tmp/state",
86
- portMap: new Map([
87
- ["frontend", 3200],
88
- ["api", 3100],
89
- ]),
90
- baseUrlByService: new Map([["api", "http://127.0.0.1:3100"]]),
91
- readyUrlByService: new Map([["api", "http://127.0.0.1:3100/health"]]),
92
- stateDirByService: new Map([["api", apiStateDir]]),
93
- urlMappings: [["http://api:3000", "http://127.0.0.1:3100"]],
94
- leaseId: "lease-1",
95
- leaseDir: "/tmp/lease-1",
96
- };
97
-
98
- expect(resolveTemplateString("{runtime}:{service}:{lease}", context)).toBe(
99
- "runtime-2:frontend:lease-1"
100
- );
101
- expect(resolveTemplateString("{prepareDir}", { ...context, prepareDir: "/tmp/prepare-1" })).toBe(
102
- "/tmp/prepare-1"
103
- );
104
- expect(resolveTemplateString("{baseUrl:api}", context)).toBe("http://127.0.0.1:3100");
105
- expect(resolveTemplateString("{dbHost:api}:{dbPort:api}/{dbName:api}", context)).toBe(
106
- "127.0.0.1:55432/runtime_db"
107
- );
108
- expect(finalizeString("API={baseUrl:api} OLD=http://api:3000", context)).toBe(
109
- "API=http://127.0.0.1:3100 OLD=http://127.0.0.1:3100"
110
- );
111
- expect(rewriteUrlPort("http://127.0.0.1:3000/health", 3200)).toBe(
112
- "http://127.0.0.1:3200/health"
113
- );
114
- });
115
-
116
- it("builds runtime configs and execution env", () => {
117
- const runtimeDir = fs.mkdtempSync(path.join(os.tmpdir(), "testkit-runtime-"));
118
- const api = makeRuntimeConfig(
119
- "api",
120
- {
121
- cwd: ".",
122
- start: "npm run api",
123
- port: 3000,
124
- baseUrl: "http://127.0.0.1:{port}",
125
- readyUrl: "http://127.0.0.1:{port}/health",
126
- env: {
127
- PORT: "{port}",
128
- },
129
- },
130
- {
131
- serviceEnv: {
132
- API_KEY: "secret",
133
- },
134
- }
135
- );
136
- const frontend = makeRuntimeConfig("frontend", {
137
- cwd: "frontend",
138
- start: "npm run web",
139
- port: 3001,
140
- baseUrl: "http://127.0.0.1:{port}",
141
- readyUrl: "http://127.0.0.1:{port}",
142
- env: {
143
- NEXT_PUBLIC_API_URL: "{baseUrl:api}",
144
- API_DB_HOST: "{dbHost:api}",
145
- },
146
- });
147
-
148
- const resolved = resolveRuntimeInstanceConfigs([api, frontend], "runtime-2", runtimeDir, {
149
- graphDirName: "api__frontend",
150
- portNamespaceIndex: 0,
151
- portNamespaceStride: 2,
152
- });
153
- expect(resolved[0].testkit.local.port).toBe(3100);
154
- expect(resolved[0].runtimeLabel).toBe("api__frontend/runtime-2");
155
- expect(resolveServiceStateDir(runtimeDir, api)).toBe(`${runtimeDir}/services/api`);
156
- expect(resolved[0].testkit.prepareDir).toBe(`${runtimeDir}/services/api/prepared`);
157
-
158
- fs.mkdirSync(path.join(runtimeDir, "services", "api"), { recursive: true });
159
- fs.writeFileSync(
160
- path.join(runtimeDir, "services", "api", "database_url"),
161
- "postgres://testkit:testkit@127.0.0.1:55432/runtime_db"
162
- );
163
-
164
- expect(
165
- buildExecutionEnv(
166
- resolved[1],
167
- { DATABASE_URL: "gone" },
168
- {
169
- PATH: "/usr/bin",
170
- }
171
- )
172
- ).toEqual({
173
- PATH: "/usr/bin",
174
- NEXT_PUBLIC_API_URL: "http://127.0.0.1:3100",
175
- API_DB_HOST: "127.0.0.1",
176
- TESTKIT_ACTIVE: "1",
177
- TESTKIT_RUNTIME_ID: "runtime-2",
178
- });
179
-
180
- expect(
181
- buildTaskExecutionEnv(
182
- resolved[1],
183
- {
184
- leaseId: "lease-1",
185
- leaseDir: "/tmp/lease-1",
186
- },
187
- {},
188
- {}
189
- )
190
- ).toMatchObject({
191
- TESTKIT_RUNTIME_ID: "runtime-2",
192
- TESTKIT_LEASE_ID: "lease-1",
193
- TESTKIT_LEASE_DIR: "/tmp/lease-1",
194
- });
195
- expect(finalizeString(".next-testkit/{runtimeId}/dist", resolved[1].testkit.templateContext)).toBe(
196
- ".next-testkit/runtime-2/dist"
197
- );
198
-
199
- expect(
200
- buildPlaywrightEnv(
201
- { runtimeId: "runtime-1", testkit: { serviceEnv: {}, templateContext: {} } },
202
- "http://localhost:3000",
203
- { leaseId: "lease-2", leaseDir: "/tmp/lease-2" },
204
- {}
205
- )
206
- ).toMatchObject({
207
- BASE_URL: "http://localhost:3000",
208
- TESTKIT_RUNTIME_ID: "runtime-1",
209
- TESTKIT_LEASE_ID: "lease-2",
210
- PLAYWRIGHT_HTML_OPEN: "never",
211
- });
212
- });
213
-
214
- it("finalizes runtime.prepare templates with prepareDir", () => {
215
- const runtimeDir = fs.mkdtempSync(path.join(os.tmpdir(), "testkit-runtime-prepare-"));
216
- const api = makeRuntimeConfig(
217
- "api",
218
- {
219
- cwd: ".",
220
- start: "npm run api",
221
- port: 3000,
222
- baseUrl: "http://127.0.0.1:{port}",
223
- readyUrl: "http://127.0.0.1:{port}/health",
224
- env: {},
225
- },
226
- {
227
- runtime: {
228
- instances: 1,
229
- maxConcurrentTasks: 2,
230
- prepare: {
231
- inputs: ["src/{service}.ts"],
232
- steps: [
233
- {
234
- kind: "command",
235
- cmd: "node scripts/prepare.mjs {prepareDir}",
236
- cwd: ".",
237
- inputs: ["src/{service}.ts"],
238
- },
239
- ],
240
- },
241
- },
242
- }
243
- );
244
-
245
- const [resolved] = resolveRuntimeInstanceConfigs([api], "runtime-1", runtimeDir, {
246
- graphDirName: "api",
247
- portNamespaceIndex: 0,
248
- portNamespaceStride: 1,
249
- });
250
-
251
- expect(resolved.testkit.runtime.prepare).toEqual({
252
- inputs: ["src/api.ts"],
253
- steps: [
254
- {
255
- kind: "command",
256
- cmd: `node scripts/prepare.mjs ${runtimeDir}/services/api/prepared`,
257
- cwd: ".",
258
- inputs: ["src/api.ts"],
259
- },
260
- ],
261
- });
262
- });
263
-
264
- it("parses runtime sockets", () => {
265
- expect(numericPortFromUrl("http://localhost:3000")).toBe(3000);
266
- expect(socketFromUrl("http://localhost:3000")).toEqual({
267
- host: "127.0.0.1",
268
- port: 3000,
269
- });
270
- expect(normalizeSocketHost("[::1]")).toBe("::1");
271
- });
272
- });
@@ -1,132 +0,0 @@
1
- import { describe, expect, it } from "vitest";
2
- import {
3
- buildConfigToPrepare,
4
- compiledEntryFromBuild,
5
- normalizeBuildConfig,
6
- } from "./build-config.mjs";
7
-
8
- describe("shared build config helpers", () => {
9
- it("normalizes tsc build config and derives prepare steps", () => {
10
- const build = normalizeBuildConfig(
11
- {
12
- kind: "tsc",
13
- entry: "src/server.ts",
14
- outDir: "dist",
15
- },
16
- "runtime.build"
17
- );
18
-
19
- expect(build).toEqual({
20
- kind: "tsc",
21
- cwd: null,
22
- entry: "src/server.ts",
23
- tsconfig: "tsconfig.json",
24
- outDir: "dist",
25
- inputs: [],
26
- });
27
- expect(compiledEntryFromBuild(build)).toBe("dist/server.js");
28
- expect(buildConfigToPrepare(build)).toEqual({
29
- inputs: ["tsconfig.json", "package.json", "src"],
30
- steps: [
31
- {
32
- kind: "command",
33
- cmd: './node_modules/.bin/tsc -p tsconfig.json --outDir "{prepareDir}/dist"',
34
- cwd: undefined,
35
- inputs: [],
36
- },
37
- ],
38
- });
39
- });
40
-
41
- it("normalizes script and steps builds", () => {
42
- expect(
43
- normalizeBuildConfig(
44
- {
45
- kind: "script",
46
- script: "npm run build",
47
- cwd: "frontend",
48
- inputs: ["frontend/package.json"],
49
- },
50
- "runtime.build"
51
- )
52
- ).toEqual({
53
- kind: "script",
54
- script: "npm run build",
55
- cwd: "frontend",
56
- inputs: ["frontend/package.json"],
57
- });
58
-
59
- expect(
60
- normalizeBuildConfig(
61
- {
62
- kind: "next",
63
- cwd: "frontend",
64
- },
65
- "runtime.build"
66
- )
67
- ).toEqual({
68
- kind: "next",
69
- cwd: "frontend",
70
- distDir: "dist",
71
- tsconfig: "tsconfig.json",
72
- inputs: [],
73
- });
74
-
75
- expect(
76
- normalizeBuildConfig(
77
- {
78
- kind: "steps",
79
- inputs: ["scripts/prepare.mjs"],
80
- steps: [{ kind: "command", run: "node scripts/prepare.mjs" }],
81
- },
82
- "runtime.build"
83
- )
84
- ).toEqual({
85
- kind: "steps",
86
- inputs: ["scripts/prepare.mjs"],
87
- steps: [
88
- {
89
- kind: "command",
90
- cmd: "node scripts/prepare.mjs",
91
- cwd: null,
92
- inputs: [],
93
- },
94
- ],
95
- });
96
-
97
- expect(
98
- buildConfigToPrepare({
99
- kind: "next",
100
- cwd: "frontend",
101
- distDir: "dist",
102
- tsconfig: "tsconfig.json",
103
- inputs: [],
104
- })
105
- ).toEqual({
106
- inputs: [
107
- "frontend/tsconfig.json",
108
- "frontend/package.json",
109
- "frontend/src",
110
- "frontend/app",
111
- "frontend/public",
112
- "frontend/next.config.js",
113
- "frontend/next.config.mjs",
114
- "frontend/next.config.ts",
115
- ],
116
- steps: [
117
- {
118
- kind: "module",
119
- specifier: "@elench/testkit/config/next-runtime-tsconfig#writeNextRuntimeTsconfig",
120
- cwd: "frontend",
121
- inputs: [],
122
- },
123
- {
124
- kind: "command",
125
- cmd: "./node_modules/.bin/next build",
126
- cwd: "frontend",
127
- inputs: [],
128
- },
129
- ],
130
- });
131
- });
132
- });
@@ -1,102 +0,0 @@
1
- import fs from "fs";
2
- import os from "os";
3
- import path from "path";
4
- import { afterEach, describe, expect, it } from "vitest";
5
- import {
6
- collectConfiguredInputs,
7
- finalizeConfiguredStep,
8
- isBareModuleSpecifier,
9
- normalizeConfiguredStep,
10
- parseModuleSpecifier,
11
- validateConfiguredCollection,
12
- } from "./configured-steps.mjs";
13
-
14
- const tempDirs = [];
15
-
16
- afterEach(() => {
17
- for (const dir of tempDirs.splice(0)) {
18
- fs.rmSync(dir, { recursive: true, force: true });
19
- }
20
- });
21
-
22
- describe("shared configured steps", () => {
23
- it("normalizes and finalizes configured steps", () => {
24
- const normalized = normalizeConfiguredStep(
25
- { kind: "module", target: "./seed.mjs#run", cwd: "db", inputs: ["schema.sql"] },
26
- 'Service "api" database.template.seed[0]'
27
- );
28
-
29
- expect(normalized).toEqual({
30
- kind: "module",
31
- specifier: "./seed.mjs#run",
32
- cwd: "db",
33
- inputs: ["schema.sql"],
34
- });
35
- expect(parseModuleSpecifier(normalized.specifier)).toEqual({
36
- modulePath: "./seed.mjs",
37
- exportName: "run",
38
- });
39
- expect(finalizeConfiguredStep(normalized, (value) => value.toUpperCase())).toEqual({
40
- kind: "module",
41
- specifier: "./SEED.MJS#RUN",
42
- cwd: "DB",
43
- inputs: ["SCHEMA.SQL"],
44
- });
45
- });
46
-
47
- it("collects and validates configured input paths", () => {
48
- const productDir = fs.mkdtempSync(path.join(os.tmpdir(), "testkit-configured-steps-"));
49
- tempDirs.push(productDir);
50
- fs.mkdirSync(path.join(productDir, "db"), { recursive: true });
51
- fs.writeFileSync(path.join(productDir, "db", "schema.sql"), "-- schema\n");
52
- fs.writeFileSync(path.join(productDir, "db", "seed.mjs"), "export default async function run() {}\n");
53
-
54
- const collection = {
55
- inputs: ["db/schema.sql"],
56
- steps: [
57
- { kind: "sql-file", path: "schema.sql", cwd: "db", inputs: [] },
58
- { kind: "module", target: "./seed.mjs#run", cwd: "db", inputs: [] },
59
- ],
60
- };
61
-
62
- expect(collectConfiguredInputs(productDir, collection)).toEqual([
63
- path.join(productDir, "db", "schema.sql"),
64
- path.join(productDir, "db", "seed.mjs"),
65
- ]);
66
- expect(() =>
67
- validateConfiguredCollection({
68
- productDir,
69
- label: 'Service "api" runtime.prepare',
70
- ...collection,
71
- })
72
- ).not.toThrow();
73
- });
74
-
75
- it("treats bare module specifiers as modules, not product-relative file paths", () => {
76
- const productDir = fs.mkdtempSync(path.join(os.tmpdir(), "testkit-configured-steps-"));
77
- tempDirs.push(productDir);
78
- fs.mkdirSync(path.join(productDir, "frontend"), { recursive: true });
79
-
80
- const collection = {
81
- inputs: [],
82
- steps: [
83
- {
84
- kind: "module",
85
- target: "@elench/testkit/config/next-runtime-tsconfig#writeNextRuntimeTsconfig",
86
- cwd: "frontend",
87
- inputs: [],
88
- },
89
- ],
90
- };
91
-
92
- expect(isBareModuleSpecifier("@elench/testkit/config/next-runtime-tsconfig")).toBe(true);
93
- expect(collectConfiguredInputs(productDir, collection)).toEqual([]);
94
- expect(() =>
95
- validateConfiguredCollection({
96
- productDir,
97
- label: 'Service "frontend" runtime.prepare',
98
- ...collection,
99
- })
100
- ).not.toThrow();
101
- });
102
- });
@@ -1,26 +0,0 @@
1
- import { describe, expect, it } from "vitest";
2
- import {
3
- normalizeDatabaseBinding,
4
- normalizeExecutionConfig,
5
- normalizeRuntimeMaxConcurrentTasks,
6
- resolveExecutionConfig,
7
- } from "./execution-schema.mjs";
8
-
9
- describe("shared execution schema", () => {
10
- it("normalizes execution config and repo/cli overrides", () => {
11
- expect(normalizeExecutionConfig({ workers: 2, fileTimeoutSeconds: 30 })).toEqual({
12
- workers: 2,
13
- fileTimeoutSeconds: 30,
14
- });
15
- expect(resolveExecutionConfig({ cli: { workers: 3 }, repo: { workers: 2, fileTimeoutSeconds: 45 } })).toEqual({
16
- workers: 3,
17
- fileTimeoutSeconds: 45,
18
- });
19
- });
20
-
21
- it("validates runtime concurrency and database binding", () => {
22
- expect(normalizeRuntimeMaxConcurrentTasks(undefined)).toBe(Number.POSITIVE_INFINITY);
23
- expect(normalizeDatabaseBinding("shared")).toBe("shared");
24
- expect(() => normalizeDatabaseBinding("legacy")).toThrow('Invalid database.binding value "legacy"');
25
- });
26
- });
@@ -1,64 +0,0 @@
1
- import { describe, expect, it } from "vitest";
2
- import {
3
- buildFileTimeoutEnv,
4
- DEFAULT_FILE_TIMEOUT_SECONDS,
5
- formatFileTimeoutBudgetError,
6
- formatWaitForTimeoutError,
7
- normalizeFileTimeoutSeconds,
8
- normalizeWaitIntervalSeconds,
9
- parseFileTimeoutOption,
10
- readFileTimeoutBudget,
11
- remainingFileTimeoutMs,
12
- remainingFileTimeoutSeconds,
13
- } from "./file-timeout.mjs";
14
-
15
- describe("file-timeout", () => {
16
- it("normalizes positive file timeout values", () => {
17
- expect(parseFileTimeoutOption("45")).toBe(45);
18
- expect(normalizeFileTimeoutSeconds(DEFAULT_FILE_TIMEOUT_SECONDS)).toBe(60);
19
- expect(() => parseFileTimeoutOption("0")).toThrow(
20
- 'Invalid --file-timeout-seconds value "0"'
21
- );
22
- expect(() => normalizeFileTimeoutSeconds(0)).toThrow(
23
- "execution.fileTimeoutSeconds must be a positive integer."
24
- );
25
- });
26
-
27
- it("builds and reads runtime timeout budget env", () => {
28
- const env = buildFileTimeoutEnv(45, 1_000);
29
- expect(env).toEqual({
30
- TESTKIT_INTERNAL_FILE_TIMEOUT_SECONDS: "45",
31
- TESTKIT_INTERNAL_FILE_DEADLINE_MS: "46000",
32
- });
33
-
34
- expect(readFileTimeoutBudget(env)).toEqual({
35
- fileTimeoutSeconds: 45,
36
- deadlineMs: 46_000,
37
- });
38
- });
39
-
40
- it("computes remaining file timeout budget", () => {
41
- const budget = {
42
- fileTimeoutSeconds: 45,
43
- deadlineMs: 46_000,
44
- };
45
-
46
- expect(remainingFileTimeoutMs(budget, 40_000)).toBe(6_000);
47
- expect(remainingFileTimeoutMs(budget, 47_000)).toBe(0);
48
- expect(remainingFileTimeoutSeconds(budget, 44_500)).toBe(1.5);
49
- });
50
-
51
- it("normalizes wait intervals and timeout errors", () => {
52
- expect(normalizeWaitIntervalSeconds()).toBe(0.25);
53
- expect(normalizeWaitIntervalSeconds(0.5)).toBe(0.5);
54
- expect(() => normalizeWaitIntervalSeconds(0)).toThrow(
55
- "waitFor intervalSeconds must be a positive number."
56
- );
57
- expect(formatWaitForTimeoutError("cron worker pickup", 60)).toBe(
58
- "Timed out waiting for cron worker pickup before the 60s test file timeout"
59
- );
60
- expect(formatFileTimeoutBudgetError(60)).toBe(
61
- "Default runtime exceeded the 60s test file timeout"
62
- );
63
- });
64
- });
@@ -1,43 +0,0 @@
1
- import { describe, expect, it } from "vitest";
2
-
3
- import { buildTestNamespace, readTestkitContext } from "./test-context.mjs";
4
-
5
- describe("buildTestNamespace", () => {
6
- it("prefers the lease id when present", () => {
7
- expect(buildTestNamespace({ runtimeId: "runtime-2", leaseId: "lease-4" })).toBe("lease-4");
8
- });
9
-
10
- it("falls back to the runtime id", () => {
11
- expect(buildTestNamespace({ runtimeId: "runtime-2" })).toBe("runtime-2");
12
- });
13
-
14
- it("normalizes unsafe characters", () => {
15
- expect(buildTestNamespace({ leaseId: " Lease 4 / Weird " })).toBe("lease-4-weird");
16
- });
17
-
18
- it("falls back to standalone when no runtime identifiers exist", () => {
19
- expect(buildTestNamespace({})).toBe("standalone");
20
- });
21
- });
22
-
23
- describe("readTestkitContext", () => {
24
- it("reads active state and normalized identifiers", () => {
25
- expect(
26
- readTestkitContext({
27
- TESTKIT_ACTIVE: "1",
28
- TESTKIT_RUNTIME_ID: "Runtime 2",
29
- TESTKIT_LEASE_ID: "Lease 3",
30
- })
31
- ).toEqual({
32
- active: true,
33
- runtimeId: "runtime-2",
34
- leaseId: "lease-3",
35
- namespace: "lease-3",
36
- rawEnv: {
37
- TESTKIT_ACTIVE: "1",
38
- TESTKIT_RUNTIME_ID: "Runtime 2",
39
- TESTKIT_LEASE_ID: "Lease 3",
40
- },
41
- });
42
- });
43
- });
@@ -1,64 +0,0 @@
1
- import { describe, expect, it } from "vitest";
2
- import {
3
- applyTimingUpdates,
4
- buildTimingKey,
5
- createEmptyTimings,
6
- estimateTaskDuration,
7
- normalizeTimings,
8
- } from "./index.mjs";
9
-
10
- describe("timings", () => {
11
- it("creates and normalizes empty timing structures", () => {
12
- expect(createEmptyTimings()).toEqual({ version: 1, files: {} });
13
- expect(normalizeTimings({})).toEqual({ version: 1, files: {} });
14
- });
15
-
16
- it("applies rolling timing updates", () => {
17
- const next = applyTimingUpdates(
18
- {
19
- version: 1,
20
- files: {
21
- "api|k6|integration|a.js": {
22
- durationMs: 1000,
23
- runs: 1,
24
- updatedAt: "2020-01-01T00:00:00.000Z",
25
- },
26
- },
27
- },
28
- [{ key: "api|k6|integration|a.js", durationMs: 3000 }],
29
- "2020-01-02T00:00:00.000Z"
30
- );
31
-
32
- expect(next.files["api|k6|integration|a.js"]).toEqual({
33
- durationMs: 2000,
34
- runs: 2,
35
- updatedAt: "2020-01-02T00:00:00.000Z",
36
- });
37
- });
38
-
39
- it("estimates task durations and builds timing keys", () => {
40
- expect(
41
- estimateTaskDuration(
42
- { files: { key: { durationMs: 3210 } } },
43
- "key",
44
- { framework: "k6", type: "integration", weight: 1, files: ["a.js"] }
45
- )
46
- ).toBe(3210);
47
-
48
- expect(
49
- estimateTaskDuration(
50
- { files: {} },
51
- "key",
52
- { framework: "playwright", type: "e2e", weight: 2, files: ["a.js", "b.js"] }
53
- )
54
- ).toBe(20000);
55
-
56
- expect(
57
- buildTimingKey(
58
- "api",
59
- { framework: "k6", type: "integration" },
60
- "tests/health.js"
61
- )
62
- ).toBe("api|k6|integration|tests/health.js");
63
- });
64
- });