@elench/testkit 0.1.69 → 0.1.71

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 (53) hide show
  1. package/README.md +70 -10
  2. package/lib/app/doctor.mjs +1 -1
  3. package/lib/app/typecheck.mjs +8 -4
  4. package/lib/bundler/index.mjs +17 -17
  5. package/lib/cli/command-helpers.mjs +1 -1
  6. package/lib/cli/commands/doctor.mjs +1 -1
  7. package/lib/cli/commands/typecheck.mjs +1 -1
  8. package/lib/cli/known-failures.mjs +4 -4
  9. package/lib/cli/presentation/discovery-reporter.mjs +2 -2
  10. package/lib/config/{setup-loader.mjs → config-loader.mjs} +32 -32
  11. package/lib/config/index.mjs +16 -16
  12. package/lib/config/runtime.mjs +1 -1
  13. package/lib/config/telemetry.mjs +4 -4
  14. package/lib/config/validation.mjs +1 -1
  15. package/lib/{setup → config-api}/index.d.ts +7 -7
  16. package/lib/{setup → config-api}/index.mjs +10 -10
  17. package/lib/{setup → config-api}/index.test.mjs +16 -3
  18. package/lib/{setup → config-api}/runtime.mjs +10 -10
  19. package/lib/coverage/index.test.mjs +3 -3
  20. package/lib/discovery/file-metadata.mjs +1 -1
  21. package/lib/discovery/file-metadata.test.mjs +2 -2
  22. package/lib/discovery/index.d.ts +1 -1
  23. package/lib/discovery/index.mjs +28 -28
  24. package/lib/discovery/index.test.mjs +10 -10
  25. package/lib/drizzle/index.d.ts +14 -0
  26. package/lib/drizzle/index.mjs +15 -0
  27. package/lib/drizzle/index.test.mjs +33 -0
  28. package/lib/env/index.d.ts +17 -0
  29. package/lib/env/index.mjs +65 -0
  30. package/lib/env/index.test.mjs +82 -0
  31. package/lib/known-failures/github.mjs +4 -4
  32. package/lib/package.test.mjs +24 -4
  33. package/lib/playwright/index.d.ts +21 -0
  34. package/lib/playwright/index.mjs +53 -0
  35. package/lib/playwright/index.test.mjs +43 -0
  36. package/lib/runner/template-steps.mjs +5 -5
  37. package/lib/runner/template.mjs +2 -2
  38. package/lib/runtime-src/k6/scenario-suite.js +1 -1
  39. package/lib/runtime-src/k6/suite.js +1 -1
  40. package/lib/shared/build-config.mjs +1 -1
  41. package/lib/shared/build-config.test.mjs +1 -1
  42. package/lib/shared/configured-steps.test.mjs +2 -2
  43. package/lib/toolchains/index.mjs +2 -2
  44. package/lib/vitest/index.d.ts +12 -0
  45. package/lib/vitest/index.mjs +31 -0
  46. package/lib/vitest/index.test.mjs +20 -0
  47. package/node_modules/@elench/next-analysis/package.json +1 -1
  48. package/node_modules/@elench/testkit-bridge/package.json +2 -2
  49. package/node_modules/@elench/testkit-protocol/package.json +1 -1
  50. package/node_modules/@elench/ts-analysis/package.json +1 -1
  51. package/package.json +24 -8
  52. /package/lib/{setup → config-api}/next-runtime-tsconfig.mjs +0 -0
  53. /package/lib/{setup → config-api}/next-runtime-tsconfig.test.mjs +0 -0
package/README.md CHANGED
@@ -4,7 +4,7 @@
4
4
  filesystem, starts local services, provisions Docker-managed local Postgres
5
5
  databases, and runs HTTP, DAL, and Playwright suites.
6
6
 
7
- The package is now driven by `testkit.setup.ts`, not `testkit.config.json`.
7
+ The package is now driven by `testkit.config.ts`, not `testkit.config.json`.
8
8
 
9
9
  ## Usage
10
10
 
@@ -81,23 +81,83 @@ persisted under `.testkit/results/` and inspected on demand with `show`,
81
81
  run counts, pass/fail/skip counts, average duration, and last observed status,
82
82
  and those summaries are exposed in compact, verbose, and JSON discovery output.
83
83
 
84
+ ## Tooling Adapters
85
+
86
+ `testkit` also ships tool-specific config helpers so consumer repos do not need
87
+ repo-local runtime policy files just to cooperate with managed runs.
88
+
89
+ ```ts
90
+ // drizzle.config.ts
91
+ import { defineConfig } from "@elench/testkit/drizzle";
92
+
93
+ export default defineConfig({
94
+ schema: "./src/db/schema/index.ts",
95
+ out: "./src/db/migrations",
96
+ dialect: "postgresql",
97
+ dbCredentials: {
98
+ url: process.env.DATABASE_URL!,
99
+ },
100
+ });
101
+ ```
102
+
103
+ ```ts
104
+ // vitest.config.ts
105
+ import { defineConfig } from "@elench/testkit/vitest";
106
+
107
+ export default defineConfig({
108
+ test: {
109
+ include: ["src/**/*.test.ts"],
110
+ },
111
+ });
112
+ ```
113
+
114
+ ```ts
115
+ // playwright.config.ts
116
+ import { defineConfig } from "@elench/testkit/playwright";
117
+ import { devices } from "@playwright/test";
118
+
119
+ export default defineConfig({
120
+ testDir: "./__testkit__",
121
+ projects: [{ name: "chromium", use: { ...devices["Desktop Chrome"] } }],
122
+ }, {
123
+ dotenvFiles: [".env.local"],
124
+ });
125
+ ```
126
+
127
+ For scripts and app-runtime code, `@elench/testkit/env` provides shared helpers
128
+ for managed runtime detection, dotenv loading, and local-database safety:
129
+
130
+ ```ts
131
+ import {
132
+ assertLocalDatabaseUrl,
133
+ loadDotenvFiles,
134
+ shouldLoadDotenv,
135
+ } from "@elench/testkit/env";
136
+
137
+ if (shouldLoadDotenv()) {
138
+ loadDotenvFiles({ files: [".env", ".env.local"] });
139
+ }
140
+
141
+ assertLocalDatabaseUrl(process.env, "seed.ts");
142
+ ```
143
+
84
144
  ## Setup
85
145
 
86
- Create `testkit.setup.ts` at repo root:
146
+ Create `testkit.config.ts` at repo root:
87
147
 
88
148
  ```ts
89
149
  import {
90
- defineTestkitSetup,
91
- defineTestkitFile,
150
+ defineConfig,
151
+ defineFile,
92
152
  nextApp,
93
153
  nodeToolchain,
94
154
  nodeApp,
95
155
  seedCommand,
96
156
  templateDatabase,
97
157
  verifyModule,
98
- } from "@elench/testkit/setup";
158
+ } from "@elench/testkit/config";
99
159
 
100
- export default defineTestkitSetup({
160
+ export default defineConfig({
101
161
  execution: {
102
162
  workers: 8,
103
163
  fileTimeoutSeconds: 60,
@@ -157,15 +217,15 @@ export default defineTestkitSetup({
157
217
  File-local execution metadata now lives next to the test when possible:
158
218
 
159
219
  ```ts
160
- import { defineTestkitFile } from "@elench/testkit/setup";
220
+ import { defineFile } from "@elench/testkit/config";
161
221
 
162
- export const testkit = defineTestkitFile({
222
+ export const testkit = defineFile({
163
223
  skip: "Billing is still stubbed locally",
164
224
  locks: ["global-worker-loop"],
165
225
  });
166
226
  ```
167
227
 
168
- `testkit.setup.ts` is optional for simple repos, but it is the primary escape hatch
228
+ `testkit.config.ts` is optional for simple repos, but it is the primary escape hatch
169
229
  for:
170
230
 
171
231
  - worker count and per-file runtime budget
@@ -305,7 +365,7 @@ export default suite;
305
365
  `testkit` suite files should default-export the suite object returned by
306
366
  `defineHttpSuite(...)` or `defineDalSuite(...)`.
307
367
 
308
- Named HTTP profiles live in `testkit.setup.ts` and can be referenced by name:
368
+ Named HTTP profiles live in `testkit.config.ts` and can be referenced by name:
309
369
 
310
370
  ```ts
311
371
  import { defineHttpSuite } from "@elench/testkit";
@@ -13,7 +13,7 @@ export async function runDoctor(options = {}) {
13
13
  checks.push({
14
14
  code: "config-load",
15
15
  level: "pass",
16
- message: "Loaded testkit setup and service config",
16
+ message: "Loaded testkit config and service config",
17
17
  });
18
18
 
19
19
  const discovery = await discoverTests({ dir: productDir, diagnostics: "report" });
@@ -16,7 +16,7 @@ export async function runTestkitTypecheck(options = {}) {
16
16
  const checks = [];
17
17
  const rootTsconfig = writeRootTypecheckConfig({
18
18
  productDir,
19
- setupFile: context.setupFile,
19
+ configFile: context.configFile,
20
20
  outputDir: tempDir,
21
21
  });
22
22
  checks.push({
@@ -63,7 +63,7 @@ export async function runTestkitTypecheck(options = {}) {
63
63
  };
64
64
  }
65
65
 
66
- function writeRootTypecheckConfig({ productDir, setupFile, outputDir }) {
66
+ function writeRootTypecheckConfig({ productDir, configFile, outputDir }) {
67
67
  const tsconfigPath = path.join(outputDir, "repo.tsconfig.json");
68
68
  const extendsPath = findExistingTsconfig(productDir) || null;
69
69
  const config = {
@@ -78,7 +78,7 @@ function writeRootTypecheckConfig({ productDir, setupFile, outputDir }) {
78
78
  target: "ES2022",
79
79
  },
80
80
  include: [
81
- setupFile ? relativeJsonPath(tsconfigPath, setupFile) : "testkit.setup.ts",
81
+ configFile ? relativeJsonPath(tsconfigPath, configFile) : "testkit.config.ts",
82
82
  "**/*.int.testkit.ts",
83
83
  "**/*.e2e.testkit.ts",
84
84
  "**/*.scenario.testkit.ts",
@@ -197,7 +197,11 @@ function serviceExists(rootDir, relativePath) {
197
197
  function packageTypePaths(tsconfigPath) {
198
198
  return {
199
199
  "@elench/testkit": [relativeJsonPath(tsconfigPath, path.join(PACKAGE_ROOT, "lib", "index.d.ts"))],
200
- "@elench/testkit/setup": [relativeJsonPath(tsconfigPath, path.join(PACKAGE_ROOT, "lib", "setup", "index.d.ts"))],
200
+ "@elench/testkit/config": [relativeJsonPath(tsconfigPath, path.join(PACKAGE_ROOT, "lib", "config-api", "index.d.ts"))],
201
+ "@elench/testkit/drizzle": [relativeJsonPath(tsconfigPath, path.join(PACKAGE_ROOT, "lib", "drizzle", "index.d.ts"))],
202
+ "@elench/testkit/env": [relativeJsonPath(tsconfigPath, path.join(PACKAGE_ROOT, "lib", "env", "index.d.ts"))],
203
+ "@elench/testkit/playwright": [relativeJsonPath(tsconfigPath, path.join(PACKAGE_ROOT, "lib", "playwright", "index.d.ts"))],
201
204
  "@elench/testkit/runtime": [relativeJsonPath(tsconfigPath, path.join(PACKAGE_ROOT, "lib", "runtime", "index.d.ts"))],
205
+ "@elench/testkit/vitest": [relativeJsonPath(tsconfigPath, path.join(PACKAGE_ROOT, "lib", "vitest", "index.d.ts"))],
202
206
  };
203
207
  }
@@ -4,11 +4,11 @@ import path from "path";
4
4
  import crypto from "crypto";
5
5
  import { build } from "esbuild";
6
6
  import { fileURLToPath } from "url";
7
- import { findSetupFile } from "../config/setup-loader.mjs";
7
+ import { findConfigFile } from "../config/config-loader.mjs";
8
8
 
9
9
  const PACKAGE_ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..", "..");
10
10
  const ROOT_ENTRY = path.join(PACKAGE_ROOT, "lib", "index.mjs");
11
- const SETUP_ENTRY = path.join(PACKAGE_ROOT, "lib", "setup", "index.mjs");
11
+ const CONFIG_ENTRY = path.join(PACKAGE_ROOT, "lib", "config-api", "index.mjs");
12
12
  const RUNTIME_ENTRY = path.join(PACKAGE_ROOT, "lib", "runtime", "index.mjs");
13
13
  const bundleCache = new Map();
14
14
 
@@ -21,8 +21,8 @@ export async function bundleK6File({
21
21
  const bundleDir = path.join(productDir, ".testkit", "_bundles", serviceName || "shared");
22
22
  fs.mkdirSync(bundleDir, { recursive: true });
23
23
 
24
- const setupFile = findSetupFile(productDir);
25
- const cacheKey = await buildCacheKey(absoluteSource, setupFile);
24
+ const configFile = findConfigFile(productDir);
25
+ const cacheKey = await buildCacheKey(absoluteSource, configFile);
26
26
  const cached = bundleCache.get(cacheKey);
27
27
  if (cached && fs.existsSync(cached)) {
28
28
  return cached;
@@ -38,7 +38,7 @@ export async function bundleK6File({
38
38
  );
39
39
  fs.writeFileSync(entryFile, buildBundleEntryModule({
40
40
  sourceFile: absoluteSource,
41
- setupFile,
41
+ configFile,
42
42
  }));
43
43
 
44
44
  await build({
@@ -62,7 +62,7 @@ export async function bundleK6File({
62
62
  return outputFile;
63
63
  }
64
64
 
65
- async function buildCacheKey(sourceFile, setupFile = null) {
65
+ async function buildCacheKey(sourceFile, configFile = null) {
66
66
  const source = await fs.promises.readFile(sourceFile, "utf8");
67
67
  const packageJson = await fs.promises.readFile(path.join(PACKAGE_ROOT, "package.json"), "utf8");
68
68
  const hash = crypto
@@ -73,9 +73,9 @@ async function buildCacheKey(sourceFile, setupFile = null) {
73
73
  .update("\0")
74
74
  .update(packageJson);
75
75
 
76
- if (setupFile && fs.existsSync(setupFile)) {
77
- hash.update("\0").update(setupFile).update("\0");
78
- hash.update(await fs.promises.readFile(setupFile, "utf8"));
76
+ if (configFile && fs.existsSync(configFile)) {
77
+ hash.update("\0").update(configFile).update("\0");
78
+ hash.update(await fs.promises.readFile(configFile, "utf8"));
79
79
  }
80
80
 
81
81
  return hash.digest("hex");
@@ -98,27 +98,27 @@ function testkitPackageAliasPlugin() {
98
98
  function resolvePackageSubpath(specifier) {
99
99
  const subpath = specifier.slice("@elench/testkit".length);
100
100
  if (!subpath) return ROOT_ENTRY;
101
- if (subpath === "/setup") return SETUP_ENTRY;
101
+ if (subpath === "/config") return CONFIG_ENTRY;
102
102
  if (subpath === "/runtime") return RUNTIME_ENTRY;
103
103
 
104
104
  throw new Error(`Unsupported @elench/testkit import "${specifier}" in ${os.platform()}`);
105
105
  }
106
106
 
107
- function buildBundleEntryModule({ sourceFile, setupFile }) {
107
+ function buildBundleEntryModule({ sourceFile, configFile }) {
108
108
  const sourceImport = JSON.stringify(sourceFile);
109
- const setupRegistration = setupFile
109
+ const configRegistration = configFile
110
110
  ? `
111
- import * as repoSetupModule from ${JSON.stringify(setupFile)};
112
- registerRepoSetup(repoSetupModule.default || repoSetupModule || null);
111
+ import * as repoConfigModule from ${JSON.stringify(configFile)};
112
+ registerRepoConfig(repoConfigModule.default || repoConfigModule || null);
113
113
  `
114
114
  : `
115
- registerRepoSetup(null);
115
+ registerRepoConfig(null);
116
116
  `;
117
117
 
118
118
  return `
119
- import { registerRepoSetup } from "@elench/testkit/setup";
119
+ import { registerRepoConfig } from "@elench/testkit/config";
120
120
  import * as suiteModule from ${sourceImport};
121
- ${setupRegistration}
121
+ ${configRegistration}
122
122
  const suite = normalizeTestkitSuite(suiteModule);
123
123
  export const options = suite.options;
124
124
  export function setup(...args) {
@@ -59,7 +59,7 @@ export const runFlags = {
59
59
  default: false,
60
60
  }),
61
61
  "ignore-skip-rules": Flags.boolean({
62
- description: "Run files even if testkit.setup.ts marks them skipped",
62
+ description: "Run files even if testkit.config.ts marks them skipped",
63
63
  default: false,
64
64
  }),
65
65
  "output-mode": Flags.string({
@@ -2,7 +2,7 @@ import { Command, Flags } from "@oclif/core";
2
2
  import { runDoctor } from "../../app/doctor.mjs";
3
3
 
4
4
  export default class DoctorCommand extends Command {
5
- static summary = "Run built-in setup, discovery, and hygiene checks";
5
+ static summary = "Run built-in config, discovery, and hygiene checks";
6
6
 
7
7
  static enableJsonFlag = true;
8
8
 
@@ -2,7 +2,7 @@ import { Command, Flags } from "@oclif/core";
2
2
  import { runTestkitTypecheck } from "../../app/typecheck.mjs";
3
3
 
4
4
  export default class TypecheckCommand extends Command {
5
- static summary = "Typecheck testkit setup, helpers, and suites";
5
+ static summary = "Typecheck testkit config, helpers, and suites";
6
6
 
7
7
  static enableJsonFlag = true;
8
8
 
@@ -1,7 +1,7 @@
1
1
  import fs from "fs";
2
2
  import path from "path";
3
3
  import { resolveProductDir } from "../config/index.mjs";
4
- import { loadTestkitSetup } from "../config/setup-loader.mjs";
4
+ import { loadTestkitConfig } from "../config/config-loader.mjs";
5
5
  import {
6
6
  buildKnownFailureIssueValidationSummaryLines,
7
7
  normalizeKnownFailureIssueValidationConfig,
@@ -106,14 +106,14 @@ export async function runKnownFailuresValidateCommand(options = {}) {
106
106
 
107
107
  async function resolveKnownFailuresContext(options) {
108
108
  const productDir = resolveProductDir(process.cwd(), options.dir);
109
- const { setup } = await loadTestkitSetup(productDir);
110
- const reporting = setup?.reporting || {};
109
+ const { config } = await loadTestkitConfig(productDir);
110
+ const reporting = config?.reporting || {};
111
111
 
112
112
  const knownFailuresRelativePath = normalizeOptionalString(options.input)
113
113
  || normalizeOptionalString(reporting.knownFailuresFile);
114
114
  if (!knownFailuresRelativePath) {
115
115
  throw new Error(
116
- "Known failures file not configured. Set reporting.knownFailuresFile in testkit.setup.ts or pass --input."
116
+ "Known failures file not configured. Set reporting.knownFailuresFile in testkit.config.ts or pass --input."
117
117
  );
118
118
  }
119
119
 
@@ -57,8 +57,8 @@ function buildCompactLines(result) {
57
57
  function buildVerboseLines(result) {
58
58
  const lines = [];
59
59
  lines.push(`${colorHeading("Summary")} ${JSON.stringify(result.summary)}`);
60
- if (result.setupFile) {
61
- lines.push(`setup ${result.setupFile}`);
60
+ if (result.configFile) {
61
+ lines.push(`config ${result.configFile}`);
62
62
  }
63
63
  if (result.history?.available) {
64
64
  lines.push(`history ${result.history.path}`);
@@ -6,17 +6,17 @@ import { fileURLToPath, pathToFileURL } from "url";
6
6
 
7
7
  const PACKAGE_ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..", "..");
8
8
  const ROOT_ENTRY = path.join(PACKAGE_ROOT, "lib", "index.mjs");
9
- const SETUP_ENTRY = path.join(PACKAGE_ROOT, "lib", "setup", "index.mjs");
9
+ const CONFIG_ENTRY = path.join(PACKAGE_ROOT, "lib", "config-api", "index.mjs");
10
10
  const RUNTIME_ENTRY = path.join(PACKAGE_ROOT, "lib", "runtime", "index.mjs");
11
- const SETUP_FILES = [
12
- "testkit.setup.ts",
13
- "testkit.setup.mts",
14
- "testkit.setup.mjs",
15
- "testkit.setup.js",
11
+ const CONFIG_FILES = [
12
+ "testkit.config.ts",
13
+ "testkit.config.mts",
14
+ "testkit.config.mjs",
15
+ "testkit.config.js",
16
16
  ];
17
17
 
18
- export function findSetupFile(productDir) {
19
- for (const candidate of SETUP_FILES) {
18
+ export function findConfigFile(productDir) {
19
+ for (const candidate of CONFIG_FILES) {
20
20
  const absolute = path.join(productDir, candidate);
21
21
  if (fs.existsSync(absolute)) {
22
22
  return absolute;
@@ -25,54 +25,54 @@ export function findSetupFile(productDir) {
25
25
  return null;
26
26
  }
27
27
 
28
- export async function loadTestkitSetup(productDir) {
29
- const setupFile = findSetupFile(productDir);
30
- if (!setupFile) {
28
+ export async function loadTestkitConfig(productDir) {
29
+ const configFile = findConfigFile(productDir);
30
+ if (!configFile) {
31
31
  return {
32
- setup: {},
33
- setupFile: null,
32
+ config: {},
33
+ configFile: null,
34
34
  };
35
35
  }
36
36
 
37
- const bundleDir = path.join(productDir, ".testkit", "_setup");
37
+ const bundleDir = path.join(productDir, ".testkit", "_config");
38
38
  fs.mkdirSync(bundleDir, { recursive: true });
39
39
 
40
- const cacheKey = buildSetupCacheKey(setupFile);
41
- const outputFile = path.join(bundleDir, `setup-${cacheKey.slice(0, 12)}.mjs`);
40
+ const cacheKey = buildConfigCacheKey(configFile);
41
+ const outputFile = path.join(bundleDir, `config-${cacheKey.slice(0, 12)}.mjs`);
42
42
 
43
43
  await build({
44
44
  absWorkingDir: productDir,
45
45
  bundle: true,
46
- entryPoints: [setupFile],
46
+ entryPoints: [configFile],
47
47
  format: "esm",
48
48
  legalComments: "none",
49
49
  outfile: outputFile,
50
50
  platform: "node",
51
51
  sourcemap: "inline",
52
52
  target: "es2020",
53
- plugins: [testkitSetupAliasPlugin()],
53
+ plugins: [testkitConfigAliasPlugin()],
54
54
  });
55
55
 
56
56
  const imported = await import(`${pathToFileURL(outputFile).href}?v=${cacheKey}`);
57
- const setup = imported.default || imported.setup || {};
58
- if (!setup || typeof setup !== "object") {
59
- throw new Error(`testkit setup file must export an object: ${path.basename(setupFile)}`);
57
+ const config = imported.default || imported.config || {};
58
+ if (!config || typeof config !== "object") {
59
+ throw new Error(`testkit config file must export an object: ${path.basename(configFile)}`);
60
60
  }
61
61
 
62
62
  return {
63
- setup,
64
- setupFile,
63
+ config,
64
+ configFile,
65
65
  };
66
66
  }
67
67
 
68
- function buildSetupCacheKey(setupFile) {
69
- const content = fs.readFileSync(setupFile, "utf8");
70
- return crypto.createHash("sha256").update(setupFile).update("\0").update(content).digest("hex");
68
+ function buildConfigCacheKey(configFile) {
69
+ const content = fs.readFileSync(configFile, "utf8");
70
+ return crypto.createHash("sha256").update(configFile).update("\0").update(content).digest("hex");
71
71
  }
72
72
 
73
- function testkitSetupAliasPlugin() {
73
+ function testkitConfigAliasPlugin() {
74
74
  return {
75
- name: "testkit-setup-alias",
75
+ name: "testkit-config-alias",
76
76
  setup(buildApi) {
77
77
  buildApi.onResolve({ filter: /^@elench\/testkit(?:\/.*)?$/ }, (args) => ({
78
78
  namespace: "file",
@@ -85,14 +85,14 @@ function testkitSetupAliasPlugin() {
85
85
  function resolvePackageSubpath(specifier) {
86
86
  const subpath = specifier.slice("@elench/testkit".length);
87
87
  if (!subpath) return ROOT_ENTRY;
88
- if (subpath === "/setup") return SETUP_ENTRY;
88
+ if (subpath === "/config") return CONFIG_ENTRY;
89
89
  if (subpath === "/runtime") {
90
90
  throw new Error(
91
- "testkit.setup.ts may not import @elench/testkit/runtime. " +
92
- "Use @elench/testkit/setup runtime helpers instead."
91
+ "testkit.config.ts may not import @elench/testkit/runtime. " +
92
+ "Use @elench/testkit/config helpers instead."
93
93
  );
94
94
  }
95
95
  if (subpath === "/runtime/index.mjs") return RUNTIME_ENTRY;
96
96
 
97
- throw new Error(`Unsupported @elench/testkit import "${specifier}" while loading testkit setup`);
97
+ throw new Error(`Unsupported @elench/testkit import "${specifier}" while loading testkit config`);
98
98
  }
@@ -1,7 +1,7 @@
1
1
  import fs from "fs";
2
2
  import path from "path";
3
3
  import { discoverProject } from "./discovery.mjs";
4
- import { loadTestkitSetup } from "./setup-loader.mjs";
4
+ import { loadTestkitConfig } from "./config-loader.mjs";
5
5
  import { normalizeToolchainRegistry } from "../toolchains/index.mjs";
6
6
  import { loadTestFileMetadataMap } from "../discovery/file-metadata.mjs";
7
7
  import { mergeDiscoveryConfigs } from "../discovery/path-policy.mjs";
@@ -27,13 +27,13 @@ export { parseDotenv, resolveProductDir, resolveServiceCwd };
27
27
 
28
28
  export async function loadConfigContext(opts = {}) {
29
29
  const productDir = resolveProductDir(process.cwd(), opts.dir);
30
- const setupContext = opts.setupContext || (await loadTestkitSetup(productDir));
31
- const { setup, setupFile } = setupContext;
32
- const execution = normalizeRepoExecution(setup.execution);
33
- const reporting = normalizeReportingConfig(setup.reporting);
34
- const toolchains = normalizeToolchainRegistry(setup.toolchains);
35
- const discoveryConfig = normalizeRepoDiscoveryConfig(setup.discovery);
36
- const explicitServices = setup.services || {};
30
+ const configContext = opts.configContext || (await loadTestkitConfig(productDir));
31
+ const { config, configFile } = configContext;
32
+ const execution = normalizeRepoExecution(config.execution);
33
+ const reporting = normalizeReportingConfig(config.reporting);
34
+ const toolchains = normalizeToolchainRegistry(config.toolchains);
35
+ const discoveryConfig = normalizeRepoDiscoveryConfig(config.discovery);
36
+ const explicitServices = config.services || {};
37
37
  const discovery = discoverProject(productDir, explicitServices, {
38
38
  ...(opts.discoveryOptions || {}),
39
39
  discovery: discoveryConfig,
@@ -50,8 +50,8 @@ export async function loadConfigContext(opts = {}) {
50
50
  normalizeServiceConfig({
51
51
  name,
52
52
  productDir,
53
- setup,
54
- setupFile,
53
+ config,
54
+ configFile,
55
55
  execution,
56
56
  discovery: discoveryConfig,
57
57
  reporting,
@@ -67,8 +67,8 @@ export async function loadConfigContext(opts = {}) {
67
67
 
68
68
  return {
69
69
  productDir,
70
- setup,
71
- setupFile,
70
+ config,
71
+ configFile,
72
72
  execution,
73
73
  discovery: discoveryConfig,
74
74
  reporting,
@@ -98,8 +98,8 @@ export { resolveDalBinary, resolveK6Binary } from "./binaries.mjs";
98
98
  function normalizeServiceConfig({
99
99
  name,
100
100
  productDir,
101
- setup,
102
- setupFile,
101
+ config,
102
+ configFile,
103
103
  execution,
104
104
  discovery,
105
105
  reporting,
@@ -150,9 +150,9 @@ function normalizeServiceConfig({
150
150
  return {
151
151
  name,
152
152
  productDir,
153
- setupFile,
153
+ configFile,
154
154
  stateDir: path.join(productDir, ".testkit", name),
155
- telemetry: normalizeTelemetryConfig(setup.telemetry),
155
+ telemetry: normalizeTelemetryConfig(config.telemetry),
156
156
  suites,
157
157
  testkit: {
158
158
  execution,
@@ -24,7 +24,7 @@ export function normalizeReportingConfig(value) {
24
24
 
25
25
  const knownFailuresFile = normalizeOptionalString(value.knownFailuresFile);
26
26
  if (!knownFailuresFile) {
27
- throw new Error('testkit.setup.ts reporting.knownFailuresFile must be a non-empty string');
27
+ throw new Error('testkit.config.ts reporting.knownFailuresFile must be a non-empty string');
28
28
  }
29
29
 
30
30
  const issueValidation = normalizeKnownFailureIssueValidationConfig(value.issueValidation);
@@ -5,18 +5,18 @@ export function normalizeTelemetryConfig(telemetry) {
5
5
  try {
6
6
  parsed = new URL(telemetry.endpoint);
7
7
  } catch {
8
- throw new Error("testkit.setup telemetry.endpoint must be a valid URL");
8
+ throw new Error("testkit.config telemetry.endpoint must be a valid URL");
9
9
  }
10
10
  if (!["http:", "https:"].includes(parsed.protocol)) {
11
- throw new Error("testkit.setup telemetry.endpoint must use http or https");
11
+ throw new Error("testkit.config telemetry.endpoint must use http or https");
12
12
  }
13
13
  }
14
14
  if (telemetry.enabled === true) {
15
15
  if (!telemetry.endpoint) {
16
- throw new Error("testkit.setup telemetry.endpoint is required when telemetry.enabled is true");
16
+ throw new Error("testkit.config telemetry.endpoint is required when telemetry.enabled is true");
17
17
  }
18
18
  if (!telemetry.tokenEnv) {
19
- throw new Error("testkit.setup telemetry.tokenEnv is required when telemetry.enabled is true");
19
+ throw new Error("testkit.config telemetry.tokenEnv is required when telemetry.enabled is true");
20
20
  }
21
21
  }
22
22
  return {
@@ -32,7 +32,7 @@ export function validateServiceConfig({
32
32
 
33
33
  if (usesLocalExecution && !local) {
34
34
  throw new Error(
35
- `Service "${name}" defines non-DAL suites but no local runtime could be resolved. Add it in testkit.setup.ts.`
35
+ `Service "${name}" defines non-DAL suites but no local runtime could be resolved. Add it in testkit.config.ts.`
36
36
  );
37
37
  }
38
38
 
@@ -215,11 +215,11 @@ export interface NextAppOptions extends Omit<ServiceConfig, "local" | "runtime">
215
215
  toolchain?: string | NodeToolchainConfig;
216
216
  }
217
217
 
218
- export interface TestkitSetup {
218
+ export interface TestkitConfig {
219
219
  discovery?: DiscoveryConfig;
220
220
  execution?: TestkitExecutionConfig;
221
221
  profiles?: {
222
- http?: Record<string, HttpSuiteConfig>;
222
+ http?: Record<string, HttpSuiteConfig<any>>;
223
223
  };
224
224
  reporting?: {
225
225
  knownFailuresFile?: string;
@@ -235,9 +235,9 @@ export interface TestkitSetup {
235
235
  };
236
236
  }
237
237
 
238
- export declare function defineTestkitSetup<T extends TestkitSetup>(setup: T): T;
238
+ export declare function defineConfig<T extends TestkitConfig>(config: T): T;
239
239
  export declare function defineHttpProfile<T extends HttpSuiteConfig>(profile: T): T;
240
- export declare function defineTestkitFile<T extends TestkitFileMetadata>(metadata: T): T;
240
+ export declare function defineFile<T extends TestkitFileMetadata>(metadata: T): T;
241
241
  export declare function postgresDatabase(options?: Omit<LocalDatabaseConfig, "provider">): LocalDatabaseConfig;
242
242
  export declare function commandStep(
243
243
  cmd: string,
@@ -309,9 +309,9 @@ export declare function jsonSessionProfile(options?: {
309
309
  usernameEnv?: string;
310
310
  }): HttpSuiteConfig;
311
311
 
312
- export declare function registerRepoSetup(setup: unknown): void;
313
- export declare function getRepoSetup(): unknown;
314
- export declare function clearRepoSetup(): void;
312
+ export declare function registerRepoConfig(config: unknown): void;
313
+ export declare function getRepoConfig(): unknown;
314
+ export declare function clearRepoConfig(): void;
315
315
  export declare function registerRuntimeContext(context: unknown): void;
316
316
  export declare function getRuntimeContext(): unknown;
317
317
  export declare function clearRuntimeContext(): void;