@cjournois/e2e-kind (0.1.3)
Installation
@cjournois:registry=npm install @cjournois/e2e-kind@0.1.3"@cjournois/e2e-kind": "0.1.3"About this package
@cjournois/e2e-kind
Stand a Helm chart up on an ephemeral kind cluster from a declarative config, run a suite against it, and tear it down — including the diagnostics dump that makes a CI failure conclusive.
Replaces the ~55 lines of hand-written bash that each deployable project used to carry in its
just e2e recipe.
Usage
Install it in the project's e2e harness, then point it at a stack config:
bun add -d @cjournois/e2e-kind
./e2e/node_modules/.bin/e2e-kind e2e/stack.json
In a justfile, as the e2e-full recipe:
# Full stack on an ephemeral kind cluster, driven by e2e/stack.json.
e2e-full:
./e2e/node_modules/.bin/e2e-kind e2e/stack.json
Paths inside the config are repo-root relative, so run it from the repo root.
Flags:
| Flag | Default | Role |
|---|---|---|
--tag <tag> |
e2e-<epoch> |
Image tag to build and deploy. |
--npmrc <path> |
~/.npmrc |
npmrc to mount as the npmrc build secret. |
What it does
- Delete any leftover cluster, then
kind create cluster --wait 120s. docker buildeach image withDOCKER_BUILDKIT=1.- One
kind load docker-imagefor the built images, then perpreload:docker pull,docker save --platform <host>,kind load image-archive. - Create the namespace idempotently (
create --dry-run=client -o yamlpiped toapply -f -). helm upgrade --installwith the values file and one--set <key>.image.tag=per image.kubectl rollout statusfor each rollout.- Background
kubectl port-forwardper forward, then poll the health URL. - Run the suite. Its exit code is the driver's.
- On failure, dump
describe podsand the primary deployment's logs, then kill the forwards and delete the cluster. Order matters: a workflow-levelif: failure()step runs after teardown and would find nothing left to inspect.
Teardown runs whether the suite passed, failed, or threw.
Config
Point your editor at the shipped schema for completion:
{
"$schema": "./node_modules/@cjournois/e2e-kind/schema.json",
"cluster": "recall-e2e",
"namespace": "recall",
"release": "recall",
"chart": "packages/recall-helm/recall",
"values": "values-local.yaml",
"npmrcSecret": true,
"images": [
{ "helmKey": "api", "name": "recall-api", "containerfile": "services/recall-api/Containerfile" },
{ "helmKey": "app", "name": "recall-app", "containerfile": "services/recall-app/Containerfile" }
],
"preload": ["pgvector/pgvector:pg18"],
"rollouts": [{ "deploy": "recall-api", "timeout": "180s" }, { "deploy": "recall-app" }],
"forward": [{ "svc": "recall-app", "local": 3400 }],
"health": { "path": "/healthz", "port": 3400 },
"diagnostics": { "deploy": "recall-api" }
}
| Field | Default | Role |
|---|---|---|
cluster |
— | kind cluster name. The kubeconfig context is kind-<cluster>. |
namespace / release |
— | Target namespace and Helm release name. |
chart |
— | Chart directory, repo-root relative. |
values |
none | Values file, resolved inside chart. Omit for a chart that needs no overrides. |
npmrcSecret |
false |
Mount ~/.npmrc as --secret id=npmrc — only when the file exists, so it works with and without private-registry access. |
images[] |
— | name, containerfile, optional context (default .), optional helmKey. |
images[].helmKey |
'' |
Chart value holding the image block: api writes api.image.tag; omitted writes the top-level image.tag. |
setRepository |
false |
Also set <key>.image.repository and pullPolicy=IfNotPresent, for charts that default to a remote registry. |
preload[] |
[] |
Images pulled on the host and loaded into the node. Use for anything large enough that an in-cluster pull would outrun a service's migrate-on-boot. |
set |
{} |
Extra --set key=value pairs, appended last. |
rollouts[] |
— | deploy plus optional timeout (default 120s), waited in order. |
forward[] |
[] |
svc and local; remote defaults to local. |
health |
none | path and port (must match a forward.local), plus attempts (30) and intervalSeconds (2). |
diagnostics |
none | deploy to tail on failure, plus tail (120). Without it only describe pods is dumped. |
spec |
Playwright in e2e/ |
cwd, command, env for the suite. |
Validation is strict: an unknown key is an error, not a silent no-op. Two images sharing a
helmKey, or a health.port that no forward exposes, are rejected up front rather than at minute
eight of a cluster run.
Commands
just install # bun install
just lint # biome + eslint
just test # bun test
just build # tsdown -> lib/, then regenerate schema.json
The tests assert the exact argv the driver emits for all four real project stacks, so a change in command construction shows up as a diff rather than a broken pipeline.
Dependencies
Dependencies
| ID | Version |
|---|---|
| commander | ^15.0.0 |
| zod | ^4.3.6 |
Development dependencies
| ID | Version |
|---|---|
| @biomejs/biome | 2.5.1 |
| @cjournois/biome-config-ts | ^0.1.0 |
| @cjournois/eslint-config-ts | ^0.1.0 |
| @eslint/js | ^9.39.4 |
| @stryker-mutator/core | ^9.6.1 |
| @types/bun | 1.3.14 |
| eslint | ^9.39.4 |
| eslint-plugin-import | ^2.32.0 |
| globals | ^17.4.0 |
| tsdown | ^0.22.0 |
| typescript | ^6.0.0 |
| typescript-eslint | ^8.58.0 |