@elench/testkit 0.1.27 → 0.1.28

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/README.md CHANGED
@@ -109,11 +109,12 @@ const suite = defineHttpSuite(({ rawReq }) => {
109
109
  rawReq("GET", "/health");
110
110
  });
111
111
 
112
- export const options = suite.options;
113
- export const setup = suite.setup;
114
- export default suite.exec;
112
+ export default suite;
115
113
  ```
116
114
 
115
+ `testkit` suite files should default-export the suite object returned by
116
+ `defineHttpSuite(...)` or `defineDalSuite(...)`.
117
+
117
118
  Named HTTP profiles live in `testkit.setup.ts` and can be referenced by name:
118
119
 
119
120
  ```ts
@@ -132,6 +133,8 @@ import { defineDalSuite } from "@elench/testkit";
132
133
  const suite = defineDalSuite(({ db }) => {
133
134
  db.query("select 1");
134
135
  });
136
+
137
+ export default suite;
135
138
  ```
136
139
 
137
140
  Low-level runtime primitives remain available:
@@ -119,8 +119,37 @@ registerRepoSetup(null);
119
119
  import { registerRepoSetup } from "@elench/testkit/setup";
120
120
  import * as suiteModule from ${sourceImport};
121
121
  ${setupRegistration}
122
- export const options = suiteModule.options;
123
- export const setup = suiteModule.setup;
124
- export default suiteModule.default;
122
+ const suite = normalizeTestkitSuite(suiteModule);
123
+ export const options = suite.options;
124
+ export function setup(...args) {
125
+ return suite.setup(...args);
126
+ }
127
+ export default function exec(...args) {
128
+ return suite.exec(...args);
129
+ }
130
+
131
+ function normalizeTestkitSuite(module) {
132
+ const candidate = module?.default;
133
+ if (!candidate || typeof candidate !== "object") {
134
+ throw new Error(
135
+ "testkit suite files must default-export the suite object returned by defineHttpSuite(...) or defineDalSuite(...). Example: export default defineHttpSuite(...) or const suite = defineHttpSuite(...); export default suite;"
136
+ );
137
+ }
138
+ if (typeof candidate.exec !== "function") {
139
+ throw new Error(
140
+ "testkit suite default export must expose an exec(setupData) function"
141
+ );
142
+ }
143
+
144
+ const setupFn = typeof candidate["setup"] === "function"
145
+ ? (...args) => candidate.setup(...args)
146
+ : () => null;
147
+
148
+ return {
149
+ options: candidate["options"],
150
+ setup: setupFn,
151
+ exec: (...args) => candidate.exec(...args),
152
+ };
153
+ }
125
154
  `;
126
155
  }
@@ -1,6 +1,7 @@
1
1
  import fs from "fs";
2
2
  import os from "os";
3
3
  import path from "path";
4
+ import { pathToFileURL } from "url";
4
5
  import { afterEach, describe, expect, it } from "vitest";
5
6
  import { bundleK6File } from "./index.mjs";
6
7
 
@@ -29,9 +30,7 @@ describe("runtime bundler", () => {
29
30
  ' "has status": (body) => typeof body.status === "string",',
30
31
  " });",
31
32
  "});",
32
- "export const options = suite.options;",
33
- "export const setup = suite.setup;",
34
- "export default suite.exec;",
33
+ "export default suite;",
35
34
  "",
36
35
  ].join("\n")
37
36
  );
@@ -60,9 +59,7 @@ describe("runtime bundler", () => {
60
59
  "const suite = defineDalSuite(({ db }) => {",
61
60
  ' db.query("SELECT 1");',
62
61
  "});",
63
- "export const options = suite.options;",
64
- "export const setup = suite.setup;",
65
- "export default suite.exec;",
62
+ "export default suite;",
66
63
  "",
67
64
  ].join("\n")
68
65
  );
@@ -77,4 +74,62 @@ describe("runtime bundler", () => {
77
74
  expect(bundled).toContain("defineDalSuite");
78
75
  expect(bundled).toContain('import sql from "k6/x/sql"');
79
76
  });
77
+
78
+ it("normalizes a default-exported suite object with no setup override", async () => {
79
+ const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "testkit-bundle-"));
80
+ cleanups.push(() => fs.rmSync(tmpDir, { force: true, recursive: true }));
81
+
82
+ const sourceFile = path.join(tmpDir, "no-setup.js");
83
+ fs.writeFileSync(
84
+ sourceFile,
85
+ [
86
+ "const suite = {",
87
+ " options: { vus: 1, iterations: 1 },",
88
+ " exec() {",
89
+ " return 'ok';",
90
+ " },",
91
+ "};",
92
+ "export default suite;",
93
+ "",
94
+ ].join("\n")
95
+ );
96
+
97
+ const bundledFile = await bundleK6File({
98
+ productDir: tmpDir,
99
+ serviceName: "api",
100
+ sourceFile,
101
+ });
102
+
103
+ const bundled = await import(`${pathToFileURL(bundledFile).href}?v=${Date.now()}`);
104
+ expect(typeof bundled.setup).toBe("function");
105
+ expect(bundled.setup()).toBeNull();
106
+ expect(typeof bundled.default).toBe("function");
107
+ expect(bundled.default()).toBe("ok");
108
+ });
109
+
110
+ it("throws a clear error when the default export is not a suite object", async () => {
111
+ const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "testkit-bundle-"));
112
+ cleanups.push(() => fs.rmSync(tmpDir, { force: true, recursive: true }));
113
+
114
+ const sourceFile = path.join(tmpDir, "legacy-shape.js");
115
+ fs.writeFileSync(
116
+ sourceFile,
117
+ [
118
+ "export default function exec() {",
119
+ " return 'legacy';",
120
+ "}",
121
+ "",
122
+ ].join("\n")
123
+ );
124
+
125
+ const bundledFile = await bundleK6File({
126
+ productDir: tmpDir,
127
+ serviceName: "api",
128
+ sourceFile,
129
+ });
130
+
131
+ await expect(
132
+ import(`${pathToFileURL(bundledFile).href}?v=${Date.now()}`)
133
+ ).rejects.toThrow(/default-export the suite object/);
134
+ });
80
135
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@elench/testkit",
3
- "version": "0.1.27",
3
+ "version": "0.1.28",
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",