@elench/testkit 0.1.3 → 0.1.4
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 +28 -19
- package/lib/config.mjs +7 -7
- package/lib/runner.mjs +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @elench/testkit
|
|
2
2
|
|
|
3
|
-
CLI that reads `
|
|
3
|
+
CLI that reads `testkit.manifest.json` from a product repo, spins up ephemeral infrastructure (Neon DB branch + Fly machine) per service, runs k6 tests, and tears down.
|
|
4
4
|
|
|
5
5
|
## Prerequisites
|
|
6
6
|
|
|
@@ -13,41 +13,50 @@ fly auth login
|
|
|
13
13
|
|
|
14
14
|
## Setup
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
Add platform secrets to each product's `.env`:
|
|
17
17
|
|
|
18
18
|
```bash
|
|
19
|
-
|
|
20
|
-
|
|
19
|
+
NEON_API_KEY='...'
|
|
20
|
+
FLY_API_TOKEN='...'
|
|
21
21
|
```
|
|
22
22
|
|
|
23
|
-
Product secrets (`
|
|
23
|
+
Product secrets (`CLERK_SECRET_KEY`, etc.) are also loaded from the same `.env`.
|
|
24
24
|
|
|
25
25
|
## Usage
|
|
26
26
|
|
|
27
|
-
From the `elench/` workspace root:
|
|
28
|
-
|
|
29
27
|
```bash
|
|
30
|
-
|
|
31
|
-
node testkit/bin/testkit.mjs bourne --build
|
|
28
|
+
cd bourne
|
|
32
29
|
|
|
33
|
-
#
|
|
34
|
-
|
|
30
|
+
# Run all suites
|
|
31
|
+
npx @elench/testkit
|
|
35
32
|
|
|
36
33
|
# Specific type / suite
|
|
37
|
-
|
|
38
|
-
|
|
34
|
+
npx @elench/testkit int -s health
|
|
35
|
+
npx @elench/testkit e2e
|
|
36
|
+
|
|
37
|
+
# Specific service (multi-service products)
|
|
38
|
+
npx @elench/testkit avocado_api int -s health
|
|
39
|
+
|
|
40
|
+
# Build from source first
|
|
41
|
+
npx @elench/testkit int --build
|
|
39
42
|
|
|
40
43
|
# Lifecycle
|
|
41
|
-
|
|
42
|
-
|
|
44
|
+
npx @elench/testkit status
|
|
45
|
+
npx @elench/testkit destroy
|
|
43
46
|
```
|
|
44
47
|
|
|
45
48
|
## How it works
|
|
46
49
|
|
|
47
|
-
1. **Config** — reads
|
|
48
|
-
2. **Neon** — creates
|
|
49
|
-
3. **Fly** —
|
|
50
|
+
1. **Config** — reads `testkit.manifest.json` for per-service infra config + test suites
|
|
51
|
+
2. **Neon** — discovers or creates a `<service>-test` branch, truncates tables between runs
|
|
52
|
+
3. **Fly** — discovers or creates a machine on the service's test app, updates env vars
|
|
50
53
|
4. **k6** — runs matched test files with `BASE_URL` and `MACHINE_ID` injected
|
|
51
54
|
5. **Cleanup** — stops the Fly machine (preserved for next run)
|
|
52
55
|
|
|
53
|
-
|
|
56
|
+
Multi-service products run all services in parallel. Each service gets its own Neon branch and Fly machine.
|
|
57
|
+
|
|
58
|
+
State is persisted in `.testkit/` (or `.testkit/<service>/` for multi-service) so subsequent runs reuse existing infrastructure.
|
|
59
|
+
|
|
60
|
+
## Manifest schema
|
|
61
|
+
|
|
62
|
+
See [testkit-manifest-schema.md](testkit-manifest-schema.md).
|
package/lib/config.mjs
CHANGED
|
@@ -30,7 +30,7 @@ export function parseDotenv(filePath) {
|
|
|
30
30
|
*/
|
|
31
31
|
export function getServiceNames(cwd) {
|
|
32
32
|
const dir = cwd || process.cwd();
|
|
33
|
-
const manifestPath = path.join(dir, "
|
|
33
|
+
const manifestPath = path.join(dir, "testkit.manifest.json");
|
|
34
34
|
if (!fs.existsSync(manifestPath)) return [];
|
|
35
35
|
const m = JSON.parse(fs.readFileSync(manifestPath, "utf8"));
|
|
36
36
|
if (!isObject(m.services)) return [];
|
|
@@ -47,7 +47,7 @@ export function getServiceNames(cwd) {
|
|
|
47
47
|
export function loadConfigs(opts = {}) {
|
|
48
48
|
const cwd = process.cwd();
|
|
49
49
|
const productDir = resolveProductDir(cwd, opts.dir);
|
|
50
|
-
const manifestPath = path.join(productDir, "
|
|
50
|
+
const manifestPath = path.join(productDir, "testkit.manifest.json");
|
|
51
51
|
const raw = JSON.parse(fs.readFileSync(manifestPath, "utf8"));
|
|
52
52
|
|
|
53
53
|
if (!isObject(raw.services)) {
|
|
@@ -133,15 +133,15 @@ export function resolveDalBinary(config) {
|
|
|
133
133
|
function resolveProductDir(cwd, explicitDir) {
|
|
134
134
|
if (explicitDir) {
|
|
135
135
|
const p = path.resolve(cwd, explicitDir);
|
|
136
|
-
if (fs.existsSync(path.join(p, "
|
|
137
|
-
throw new Error(`No
|
|
136
|
+
if (fs.existsSync(path.join(p, "testkit.manifest.json"))) return p;
|
|
137
|
+
throw new Error(`No testkit.manifest.json in ${p}`);
|
|
138
138
|
}
|
|
139
139
|
|
|
140
140
|
// Check cwd
|
|
141
|
-
if (fs.existsSync(path.join(cwd, "
|
|
141
|
+
if (fs.existsSync(path.join(cwd, "testkit.manifest.json"))) return cwd;
|
|
142
142
|
|
|
143
143
|
throw new Error(
|
|
144
|
-
`No
|
|
144
|
+
`No testkit.manifest.json in current directory. ` +
|
|
145
145
|
`Either cd into a product directory or use --dir.`
|
|
146
146
|
);
|
|
147
147
|
}
|
|
@@ -152,7 +152,7 @@ function resolveProductDir(cwd, explicitDir) {
|
|
|
152
152
|
*/
|
|
153
153
|
export function isSiblingProduct(name) {
|
|
154
154
|
const candidate = path.join(process.cwd(), name);
|
|
155
|
-
return fs.existsSync(path.join(candidate, "
|
|
155
|
+
return fs.existsSync(path.join(candidate, "testkit.manifest.json"));
|
|
156
156
|
}
|
|
157
157
|
|
|
158
158
|
// ── Per-service validation ──────────────────────────────────────────────
|
package/lib/runner.mjs
CHANGED