@elench/testkit 0.1.54 → 0.1.56

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 (43) hide show
  1. package/README.md +22 -0
  2. package/lib/bundler/index.mjs +1 -1
  3. package/lib/bundler/index.test.mjs +29 -0
  4. package/lib/cli/args.mjs +2 -2
  5. package/lib/cli/args.test.mjs +8 -2
  6. package/lib/cli/command-helpers.mjs +5 -1
  7. package/lib/cli/commands/artifacts.mjs +2 -2
  8. package/lib/cli/commands/logs.mjs +2 -2
  9. package/lib/cli/commands/run.mjs +2 -2
  10. package/lib/cli/commands/show.mjs +2 -2
  11. package/lib/cli/db.mjs +17 -2
  12. package/lib/cli/entrypoint.mjs +2 -1
  13. package/lib/cli/presentation/run-reporter.mjs +25 -0
  14. package/lib/cli/presentation/run-reporter.test.mjs +80 -0
  15. package/lib/cli/tui/watch-app.mjs +134 -18
  16. package/lib/cli/viewer.mjs +67 -0
  17. package/lib/config/discovery.mjs +1 -0
  18. package/lib/config/discovery.test.mjs +8 -0
  19. package/lib/database/index.mjs +85 -11
  20. package/lib/database/template-steps.mjs +45 -6
  21. package/lib/database/template-steps.test.mjs +43 -0
  22. package/lib/index.d.ts +58 -0
  23. package/lib/index.mjs +3 -0
  24. package/lib/runner/artifacts.mjs +16 -0
  25. package/lib/runner/default-runtime-runner.mjs +4 -1
  26. package/lib/runner/logs.mjs +54 -6
  27. package/lib/runner/orchestrator.mjs +67 -14
  28. package/lib/runner/planning.mjs +1 -1
  29. package/lib/runner/reporting.mjs +58 -2
  30. package/lib/runner/reporting.test.mjs +85 -2
  31. package/lib/runner/runtime-contexts.mjs +3 -3
  32. package/lib/runner/runtime-preparation.mjs +31 -0
  33. package/lib/runner/setup-operations.mjs +115 -0
  34. package/lib/runner/setup-operations.test.mjs +94 -0
  35. package/lib/runner/suite-selection.mjs +4 -4
  36. package/lib/runner/suite-selection.test.mjs +9 -2
  37. package/lib/runner/template-steps.mjs +129 -11
  38. package/lib/runner/worker-loop.mjs +1 -1
  39. package/lib/runtime-src/k6/checks.js +9 -0
  40. package/lib/runtime-src/k6/scenario-runtime.js +234 -0
  41. package/lib/runtime-src/k6/scenario-suite.js +179 -0
  42. package/lib/toolchains/index.mjs +0 -4
  43. package/package.json +1 -1
@@ -0,0 +1,179 @@
1
+ import { fail } from "k6";
2
+ import {
3
+ defaultOptions,
4
+ emitFailureCollectionArtifact,
5
+ recordFailureDetail,
6
+ recordRuntimeFailure,
7
+ startFailureCollection,
8
+ } from "./checks.js";
9
+ import {
10
+ createHttpClient,
11
+ emitHttpTraceCollectionArtifact,
12
+ getEnv,
13
+ startHttpTraceCollection,
14
+ } from "./http.js";
15
+ import {
16
+ clearRuntimeContext,
17
+ registerRuntimeContext,
18
+ resolveHttpProfile,
19
+ } from "../../setup/runtime.mjs";
20
+ import { createScenarioRuntime } from "./scenario-runtime.js";
21
+
22
+ export function defineScenarioSuite(configOrRun, maybeRun) {
23
+ const { config, run } = normalizeSuiteArgs(configOrRun, maybeRun);
24
+
25
+ return {
26
+ get options() {
27
+ return mergeProfileConfig(config).options || defaultOptions;
28
+ },
29
+ setup() {
30
+ const resolved = resolveRuntimeConfig(config);
31
+ startFailureCollection("setup");
32
+ startHttpTraceCollection("setup");
33
+ try {
34
+ registerRuntimeContext({ env: resolved.env, http: resolved.client.rawHttp || null });
35
+ if (typeof resolved.auth?.setup !== "function") return null;
36
+ return resolved.auth.setup({ env: resolved.env });
37
+ } catch (error) {
38
+ recordFailureDetail(buildRuntimeExceptionDetail("setup", error));
39
+ recordRuntimeFailure();
40
+ fail(formatFatalSuiteError("setup", error));
41
+ } finally {
42
+ emitFailureCollectionArtifact();
43
+ emitHttpTraceCollectionArtifact();
44
+ clearRuntimeContext();
45
+ }
46
+ },
47
+ exec(setupData) {
48
+ const resolved = resolveRuntimeConfig(config);
49
+ const scenario = createScenarioRuntime({
50
+ seed: resolved.env.rawEnv.TESTKIT_SCENARIO_SEED,
51
+ });
52
+ startFailureCollection("exec");
53
+ startHttpTraceCollection("exec");
54
+ try {
55
+ registerRuntimeContext({ env: resolved.env, http: resolved.client.rawHttp || null });
56
+ return run({
57
+ env: resolved.env,
58
+ req: resolved.client.request,
59
+ rawReq: resolved.client.raw,
60
+ getWithHeaders: resolved.client.getWithHeaders,
61
+ setupData,
62
+ session: setupData,
63
+ scenario,
64
+ });
65
+ } catch (error) {
66
+ recordFailureDetail(buildRuntimeExceptionDetail("exec", error));
67
+ recordRuntimeFailure();
68
+ fail(formatFatalSuiteError("exec", error));
69
+ } finally {
70
+ scenario.emitArtifact();
71
+ emitFailureCollectionArtifact();
72
+ emitHttpTraceCollectionArtifact();
73
+ clearRuntimeContext();
74
+ }
75
+ },
76
+ };
77
+ }
78
+
79
+ function normalizeSuiteArgs(configOrRun, maybeRun) {
80
+ if (typeof configOrRun === "function") {
81
+ return { config: {}, run: configOrRun };
82
+ }
83
+ if (typeof maybeRun !== "function") {
84
+ throw new Error("suite factory requires a run callback");
85
+ }
86
+ return { config: configOrRun || {}, run: maybeRun };
87
+ }
88
+
89
+ function callHeaders(builder, setupData, env) {
90
+ if (typeof builder !== "function") return {};
91
+ return builder(setupData, { env }) || {};
92
+ }
93
+
94
+ function mergeProfileConfig(config) {
95
+ if (!config?.profile) return config || {};
96
+
97
+ const profile = resolveHttpProfile(config.profile) || {};
98
+ return {
99
+ ...profile,
100
+ ...config,
101
+ auth: config.auth ?? profile.auth ?? null,
102
+ headers: config.headers ?? profile.headers,
103
+ rawHeaders: config.rawHeaders ?? profile.rawHeaders,
104
+ options: config.options ?? profile.options,
105
+ env: config.env ?? profile.env,
106
+ };
107
+ }
108
+
109
+ function resolveRuntimeConfig(config) {
110
+ const resolvedConfig = mergeProfileConfig(config);
111
+ const env = {
112
+ ...(resolvedConfig.env || getEnv()),
113
+ rawEnv: __ENV,
114
+ };
115
+ const auth = resolvedConfig.auth || null;
116
+ const client = createHttpClient({
117
+ baseUrl: env.BASE,
118
+ routeHeaders: env.routeParams,
119
+ getHeaders(setupData) {
120
+ return {
121
+ ...callHeaders(auth?.headers, setupData, env),
122
+ ...callHeaders(resolvedConfig.headers, setupData, env),
123
+ };
124
+ },
125
+ getRawHeaders(setupData) {
126
+ return callHeaders(resolvedConfig.rawHeaders, setupData, env);
127
+ },
128
+ });
129
+
130
+ return {
131
+ resolvedConfig,
132
+ env,
133
+ auth,
134
+ client,
135
+ };
136
+ }
137
+
138
+ function formatFatalSuiteError(phase, error) {
139
+ if (error instanceof Error) {
140
+ return `Uncaught testkit suite error during ${phase}: ${error.message}`;
141
+ }
142
+ return `Uncaught testkit suite error during ${phase}: ${String(error)}`;
143
+ }
144
+
145
+ function buildRuntimeExceptionDetail(phase, error) {
146
+ const message = error instanceof Error ? error.message : String(error);
147
+ const stack = error instanceof Error && typeof error.stack === "string" ? error.stack : "";
148
+ const location = extractLocationFromStack(stack);
149
+ return {
150
+ kind: "runtime-exception",
151
+ key: location
152
+ ? `${location.path}:${location.line}:${location.column}`
153
+ : `runtime-exception:${phase}:${message}`,
154
+ title: "Uncaught runtime exception",
155
+ message: `Uncaught testkit suite error during ${phase}: ${message}`,
156
+ location,
157
+ stack,
158
+ };
159
+ }
160
+
161
+ function extractLocationFromStack(stack) {
162
+ if (!stack) return null;
163
+ const matches = [...String(stack).matchAll(/(file:\/\/[^\s)]+|\/[^\s):]+):(\d+):(\d+)/g)].map(
164
+ (match) => ({
165
+ path: normalizeStackPath(match[1]),
166
+ line: Number(match[2]),
167
+ column: Number(match[3]),
168
+ })
169
+ );
170
+ return matches[0] || null;
171
+ }
172
+
173
+ function normalizeStackPath(rawPath) {
174
+ if (typeof rawPath !== "string") return rawPath;
175
+ if (rawPath.startsWith("file://")) {
176
+ return rawPath.slice("file://".length);
177
+ }
178
+ return rawPath;
179
+ }
@@ -89,11 +89,7 @@ export async function announceResolvedToolchain(config, resolvedToolchain, repor
89
89
  announcedToolchains.add(config);
90
90
  if (reporter?.toolchainResolved) {
91
91
  reporter.toolchainResolved(config, resolvedToolchain);
92
- return;
93
92
  }
94
- console.log(
95
- `[testkit] ${config.runtimeLabel || config.name}:${config.name} toolchain ${resolvedToolchain.summary}`
96
- );
97
93
  }
98
94
 
99
95
  export function applyToolchainEnv(baseEnv, resolvedToolchain, processEnv = process.env) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@elench/testkit",
3
- "version": "0.1.54",
3
+ "version": "0.1.56",
4
4
  "description": "CLI for discovering and running local HTTP, DAL, and Playwright test suites",
5
5
  "type": "module",
6
6
  "types": "./lib/index.d.ts",