@elench/testkit 0.1.19 → 0.1.20
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 +8 -3
- package/lib/config/index.mjs +23 -2
- package/lib/config/index.test.mjs +36 -4
- package/lib/runner/index.mjs +4 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -5,11 +5,11 @@ CLI that reads `runner.manifest.json` plus `testkit.config.json` from a product
|
|
|
5
5
|
## Prerequisites
|
|
6
6
|
|
|
7
7
|
```bash
|
|
8
|
-
sudo snap install k6
|
|
9
8
|
sudo apt-get install -y jq
|
|
10
9
|
```
|
|
11
10
|
|
|
12
|
-
|
|
11
|
+
`@elench/testkit` ships its own `k6` binary and uses it for both HTTP and DAL suites by default.
|
|
12
|
+
If you need to force a different binary, set `TESTKIT_K6_BIN` to an absolute or relative path.
|
|
13
13
|
|
|
14
14
|
Database isolation uses Docker-managed local Postgres containers. `testkit` creates and reuses template databases automatically, then clones per-worker databases from those templates for fast reruns. The default image is `pgvector/pgvector:pg16`.
|
|
15
15
|
|
|
@@ -77,6 +77,12 @@ const suite = defineHttpSuite({ auth: clerkSessionAuth }, ({ req, setupData }) =
|
|
|
77
77
|
`testkit` bundles these imports before invoking k6, so tests do not need
|
|
78
78
|
generated `_testkit` files or direct package-manager path imports.
|
|
79
79
|
|
|
80
|
+
If you need to override the packaged `k6` binary for local environment reasons:
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
TESTKIT_K6_BIN=/path/to/k6 npx @elench/testkit int
|
|
84
|
+
```
|
|
85
|
+
|
|
80
86
|
Legacy compatibility:
|
|
81
87
|
|
|
82
88
|
- `testkit runtime install`
|
|
@@ -173,5 +179,4 @@ npm run test:system
|
|
|
173
179
|
`test:system` runs real end-to-end fixtures from `test/fixtures/system/`. It requires:
|
|
174
180
|
|
|
175
181
|
- Docker with a running daemon
|
|
176
|
-
- `k6` on `PATH`
|
|
177
182
|
- Playwright Chromium browser assets available to `@playwright/test`
|
package/lib/config/index.mjs
CHANGED
|
@@ -23,6 +23,7 @@ import {
|
|
|
23
23
|
|
|
24
24
|
const RUNNER_MANIFEST = "runner.manifest.json";
|
|
25
25
|
const TESTKIT_CONFIG = "testkit.config.json";
|
|
26
|
+
const TESTKIT_K6_BIN = "TESTKIT_K6_BIN";
|
|
26
27
|
export function parseDotenv(filePath) {
|
|
27
28
|
if (!fs.existsSync(filePath)) return {};
|
|
28
29
|
return parseDotenvString(fs.readFileSync(filePath, "utf8"));
|
|
@@ -94,15 +95,35 @@ export function loadConfigs(opts = {}) {
|
|
|
94
95
|
});
|
|
95
96
|
}
|
|
96
97
|
|
|
97
|
-
export function
|
|
98
|
+
export function resolveK6Binary() {
|
|
99
|
+
const override = process.env[TESTKIT_K6_BIN]?.trim();
|
|
100
|
+
if (override) {
|
|
101
|
+
const isPathLike =
|
|
102
|
+
path.isAbsolute(override) ||
|
|
103
|
+
override.includes(path.sep) ||
|
|
104
|
+
override.includes(path.posix.sep) ||
|
|
105
|
+
override.includes(path.win32.sep);
|
|
106
|
+
const overridePath = isPathLike ? path.resolve(process.cwd(), override) : override;
|
|
107
|
+
|
|
108
|
+
if (isPathLike && !fs.existsSync(overridePath)) {
|
|
109
|
+
throw new Error(`${TESTKIT_K6_BIN} points to a missing file: ${overridePath}`);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
return overridePath;
|
|
113
|
+
}
|
|
114
|
+
|
|
98
115
|
const thisFile = fileURLToPath(import.meta.url);
|
|
99
116
|
const abs = path.resolve(path.dirname(thisFile), "..", "..", "vendor", "k6");
|
|
100
117
|
if (!fs.existsSync(abs)) {
|
|
101
|
-
throw new Error(`Bundled
|
|
118
|
+
throw new Error(`Bundled k6 binary not found: ${abs}`);
|
|
102
119
|
}
|
|
103
120
|
return abs;
|
|
104
121
|
}
|
|
105
122
|
|
|
123
|
+
export function resolveDalBinary() {
|
|
124
|
+
return resolveK6Binary();
|
|
125
|
+
}
|
|
126
|
+
|
|
106
127
|
export function resolveServiceCwd(productDir, maybeRelative) {
|
|
107
128
|
return path.resolve(productDir, maybeRelative || ".");
|
|
108
129
|
}
|
|
@@ -1,12 +1,44 @@
|
|
|
1
1
|
import fs from "fs";
|
|
2
2
|
import path from "path";
|
|
3
|
-
import
|
|
4
|
-
import {
|
|
3
|
+
import os from "os";
|
|
4
|
+
import { afterEach, describe, expect, it } from "vitest";
|
|
5
|
+
import { resolveDalBinary, resolveK6Binary } from "./index.mjs";
|
|
6
|
+
|
|
7
|
+
const originalK6Bin = process.env.TESTKIT_K6_BIN;
|
|
8
|
+
|
|
9
|
+
afterEach(() => {
|
|
10
|
+
if (originalK6Bin === undefined) {
|
|
11
|
+
delete process.env.TESTKIT_K6_BIN;
|
|
12
|
+
} else {
|
|
13
|
+
process.env.TESTKIT_K6_BIN = originalK6Bin;
|
|
14
|
+
}
|
|
15
|
+
});
|
|
5
16
|
|
|
6
17
|
describe("config-index", () => {
|
|
7
|
-
it("resolves the bundled
|
|
8
|
-
const binaryPath =
|
|
18
|
+
it("resolves the bundled k6 binary from the package root", () => {
|
|
19
|
+
const binaryPath = resolveK6Binary();
|
|
9
20
|
expect(path.basename(binaryPath)).toBe("k6");
|
|
10
21
|
expect(fs.existsSync(binaryPath)).toBe(true);
|
|
11
22
|
});
|
|
23
|
+
|
|
24
|
+
it("keeps resolveDalBinary aligned with the shared k6 resolver", () => {
|
|
25
|
+
expect(resolveDalBinary()).toBe(resolveK6Binary());
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it("uses TESTKIT_K6_BIN when provided with a relative path", () => {
|
|
29
|
+
const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "testkit-k6-"));
|
|
30
|
+
const binPath = path.join(tempDir, "k6-custom");
|
|
31
|
+
fs.writeFileSync(binPath, "#!/usr/bin/env bash\nexit 0\n");
|
|
32
|
+
process.env.TESTKIT_K6_BIN = path.relative(process.cwd(), binPath);
|
|
33
|
+
|
|
34
|
+
expect(resolveK6Binary()).toBe(binPath);
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it("throws a clear error when TESTKIT_K6_BIN points at a missing path", () => {
|
|
38
|
+
process.env.TESTKIT_K6_BIN = "./definitely-missing-k6-bin";
|
|
39
|
+
|
|
40
|
+
expect(() => resolveK6Binary()).toThrow(
|
|
41
|
+
/TESTKIT_K6_BIN points to a missing file/
|
|
42
|
+
);
|
|
43
|
+
});
|
|
12
44
|
});
|
package/lib/runner/index.mjs
CHANGED
|
@@ -4,7 +4,7 @@ import { spawn } from "child_process";
|
|
|
4
4
|
import net from "net";
|
|
5
5
|
import { execa, execaCommand } from "execa";
|
|
6
6
|
import { bundleK6File } from "../bundler/index.mjs";
|
|
7
|
-
import {
|
|
7
|
+
import { resolveK6Binary, resolveServiceCwd } from "../config/index.mjs";
|
|
8
8
|
import {
|
|
9
9
|
cleanupOrphanedLocalInfrastructure,
|
|
10
10
|
destroyRuntimeDatabase,
|
|
@@ -521,6 +521,7 @@ async function runHttpK6Batch(targetConfig, batch) {
|
|
|
521
521
|
|
|
522
522
|
async function runHttpK6Task(targetConfig, task, baseUrl) {
|
|
523
523
|
const absFile = path.join(targetConfig.productDir, task.file);
|
|
524
|
+
const k6Binary = resolveK6Binary();
|
|
524
525
|
const bundledFile = await bundleK6File({
|
|
525
526
|
productDir: targetConfig.productDir,
|
|
526
527
|
serviceName: targetConfig.name,
|
|
@@ -529,7 +530,7 @@ async function runHttpK6Task(targetConfig, task, baseUrl) {
|
|
|
529
530
|
console.log(`·· ${targetConfig.workerLabel}:${task.suiteName} → ${task.file}`);
|
|
530
531
|
const startedAt = Date.now();
|
|
531
532
|
try {
|
|
532
|
-
await execa(
|
|
533
|
+
await execa(k6Binary, ["run", "--address", "127.0.0.1:0", "-e", `BASE_URL=${baseUrl}`, bundledFile], {
|
|
533
534
|
cwd: targetConfig.productDir,
|
|
534
535
|
env: buildExecutionEnv(targetConfig),
|
|
535
536
|
stdio: "inherit",
|
|
@@ -567,7 +568,7 @@ async function runDalBatch(targetConfig, batch) {
|
|
|
567
568
|
|
|
568
569
|
async function runDalTask(targetConfig, task, databaseUrl) {
|
|
569
570
|
const absFile = path.join(targetConfig.productDir, task.file);
|
|
570
|
-
const k6Binary =
|
|
571
|
+
const k6Binary = resolveK6Binary();
|
|
571
572
|
const bundledFile = await bundleK6File({
|
|
572
573
|
productDir: targetConfig.productDir,
|
|
573
574
|
serviceName: targetConfig.name,
|