@luckystack/test-runner 0.10.2 → 0.11.0
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/AGENTS.md +7 -0
- package/CHANGELOG.md +7 -0
- package/README.md +13 -68
- package/dist/authEnforcementCheck.d.ts +12 -0
- package/dist/contractCheck.d.ts +24 -0
- package/dist/csrfEnforcementCheck.d.ts +25 -0
- package/dist/customTests.d.ts +145 -0
- package/dist/extensionRegistry.d.ts +83 -0
- package/dist/fuzzCheck.d.ts +12 -0
- package/dist/index.d.ts +49 -745
- package/dist/index.js.map +1 -1
- package/dist/probeRequest.d.ts +48 -0
- package/dist/rateLimitCheck.d.ts +14 -0
- package/dist/reporter.d.ts +3 -0
- package/dist/resetServerState.d.ts +13 -0
- package/dist/resolveTestBaseUrl.d.ts +7 -0
- package/dist/resolveTestEnvironment.d.ts +21 -0
- package/dist/runAllTests.d.ts +88 -0
- package/dist/runAuthEnforcementTests.d.ts +17 -0
- package/dist/runContractTests.d.ts +22 -0
- package/dist/runCsrfEnforcementTests.d.ts +29 -0
- package/dist/runFuzzTests.d.ts +16 -0
- package/dist/runRateLimitTests.d.ts +38 -0
- package/dist/runRegisteredLayers.d.ts +24 -0
- package/dist/sampleInputFor.d.ts +13 -0
- package/dist/schemaSampleInput.d.ts +12 -0
- package/dist/socketProbeTransport.d.ts +9 -0
- package/dist/streamWatcher.d.ts +37 -0
- package/dist/testDataMarker.d.ts +2 -0
- package/dist/testLayerHelpers.d.ts +55 -0
- package/dist/testSocket.d.ts +58 -0
- package/dist/types.d.ts +46 -0
- package/dist/walkEndpoints.d.ts +6 -0
- package/docs/auth-tests.md +4 -223
- package/docs/contract-tests.md +11 -307
- package/docs/extension-hooks.md +4 -467
- package/docs/fuzz-tests.md +4 -245
- package/docs/rate-limit-tests.md +9 -261
- package/package.json +5 -5
- package/CLAUDE.md +0 -117
package/CLAUDE.md
DELETED
|
@@ -1,117 +0,0 @@
|
|
|
1
|
-
# @luckystack/test-runner
|
|
2
|
-
|
|
3
|
-
> AI summary + function INDEX. For deep specs see `docs/` next to this file.
|
|
4
|
-
|
|
5
|
-
## What this package does
|
|
6
|
-
|
|
7
|
-
Generated-type-driven test layers voor LuckyStack APIs en sync routes. Walkt elke endpoint uit de generated `apiMethodMap` (plus elke sync route uit `syncMetaMap` wanneer die wordt meegegeven) en draait vijf progressive layers: contract smoke (Zod-valid input), auth enforcement, rate-limit, crash-resistance fuzz, en per-route custom tests (`<name>_v<N>.tests.ts` naast `_api/`/`_sync/` sources). Elke layer is independent runnable; `runAllTests` orchestreert alles in volgorde en levert een geaggregeerde summary op. Reporter/fixture/layer-extension registries laten consumers eigen checks plug-in zonder de framework te forken.
|
|
8
|
-
|
|
9
|
-
## When to USE this package
|
|
10
|
-
|
|
11
|
-
- Je wil elke `_api/*` route automatisch valideren tegen de generated contract zonder per endpoint een testfile te schrijven.
|
|
12
|
-
- Je wil in CI verifiëren dat endpoints met `auth.login: true` daadwerkelijk 401 returneren voor unauthenticated requests.
|
|
13
|
-
- Je wil rate-limit gedrag (`rateLimit: N`) confirmeren zonder handmatig de `N+1`th request te bouwen.
|
|
14
|
-
- Je wil nightly crash-resistance fuzz draaien op alle endpoints om 500-stacks te vangen.
|
|
15
|
-
- Je wil custom test-layers, fixtures of een webhook reporter toevoegen aan de standard sweep.
|
|
16
|
-
|
|
17
|
-
## When to NOT suggest this (yet)
|
|
18
|
-
|
|
19
|
-
- Voor unit tests van pure functions binnen `_api/*` — gebruik vitest/jest direct, niet deze runner.
|
|
20
|
-
- Voor frontend-UI tests — gebruik Playwright/`webapp-testing` skill, deze runner is server-only.
|
|
21
|
-
- Wanneer er geen generated `apiMethodMap` beschikbaar is (project gebruikt geen `@luckystack/devkit`).
|
|
22
|
-
- Wanneer de target server productie is — fuzz/rate-limit layers maken honderden requests en `/_test/reset` bestaat alleen bij exact `NODE_ENV=development|test` plus een verplicht `TEST_RESET_TOKEN`.
|
|
23
|
-
|
|
24
|
-
Sync routes: de auto-sweep layers dekken ze alleen wanneer `runAllTests` de generated `syncMetaMap` (+ optioneel `syncInputSchemas`) krijgt; zonder `syncMetaMap` logt `runAllTests` een waarschuwing dat sync routes niet geswept worden. Sync probes gaan over Socket.io (de pipeline van echte clients) tenzij het project `routed-http` is of `syncTransport: 'http'` gezet is; de CSRF-layer probet sync altijd over HTTP. Per run één wegwerp-room; met een `authToken` joint de sweep-sessie die room zodat room-membership-enforcement een member ziet.
|
|
25
|
-
|
|
26
|
-
## Function Index
|
|
27
|
-
|
|
28
|
-
| Function / Export | 1-regel | Deep doc |
|
|
29
|
-
|---|---|---|
|
|
30
|
-
| `runAllTests({ apiMethodMap, apiMetaMap, apiInputSchemas, syncMetaMap?, syncInputSchemas?, baseUrl, ... })` | Orchestrator: draait contract + auth + rate-limit + csrf + fuzz + custom (Layer 5) in volgorde, levert een `RunAllTestsSummary` en schrijft die als JSON naar `outputFile`. `filter` wordt vóór de requests toegepast. | → docs/contract-tests.md |
|
|
31
|
-
| `runCustomTests(input)` | Layer 5: draait per-route tests. Direct callers moeten lazy `loadProjectConfig` meegeven; env/secrets resolven vóór test-module imports. `runAllTests` gebruikt een interne already-prepared entrypoint om pointer-reload te voorkomen. | → docs/contract-tests.md |
|
|
32
|
-
| `discoverCustomTestFiles(srcDir?)` | Walker die elke `<name>_v<N>.tests.ts` onder de configured src dir yields. | → docs/contract-tests.md |
|
|
33
|
-
| `logRunAllSummary(summary)` | Pretty-print één `RunAllTestsSummary`. | → docs/extension-hooks.md |
|
|
34
|
-
| `walkEndpoints(apiMethodMap)` | Genereert `EndpointDescriptor[]` uit de generated map | → docs/contract-tests.md |
|
|
35
|
-
| `walkSyncEndpoints(syncMap)` | Zelfde voor sync routes (`syncMetaMap` of `syncMethodMap`); descriptors krijgen `kind: 'sync'` | → docs/contract-tests.md |
|
|
36
|
-
| `sendProbe(input)` / `createHttpProbeTransport(opts?)` / `defaultProbeTransport` | Eén HTTP-probe (GET-payload in de `__luckystack_data` query) / transport die API- en `/sync/*`-routes over HTTP bereikt | → docs/contract-tests.md |
|
|
37
|
-
| `createSocketProbeTransport(opts)` | Transport die sync probes als Socket.io `sync` emit verstuurt | → docs/contract-tests.md |
|
|
38
|
-
| `createSampleInputFor({ apiInputSchemas?, syncInputSchemas?, stringPrefix? })` | `inputFor`-factory: Zod-valid sample per API- of sync-route | → docs/contract-tests.md |
|
|
39
|
-
| `runContractCheck({ endpoint, baseUrl, inputFor?, headers? })` | Single-endpoint contract smoke | → docs/contract-tests.md |
|
|
40
|
-
| `runContractTests({ apiMethodMap, baseUrl, skip?, inputFor?, headers?, onResult? })` | Full sweep contract layer | → docs/contract-tests.md |
|
|
41
|
-
| `runAuthEnforcementCheck({ endpoint, baseUrl, inputFor? })` | Single-endpoint auth check (verwacht 401 zonder token) | → docs/auth-tests.md |
|
|
42
|
-
| `runAuthEnforcementTests({ apiMethodMap, apiMetaMap, baseUrl, skip?, inputFor?, onResult? })` | Sweep alle `auth.login: true` endpoints | → docs/auth-tests.md |
|
|
43
|
-
| `runRateLimitCheck({ endpoint, baseUrl, rateLimit, inputFor?, headers? })` | Single-endpoint rate-limit assertie | → docs/rate-limit-tests.md |
|
|
44
|
-
| `runRateLimitTests({ apiMethodMap, apiMetaMap, baseUrl, skip?, inputFor?, headers?, maxRateLimitToTest?, resetBetweenEndpoints?, resetToken?, onResult? })` | Sweep alle `rateLimit: N` endpoints | → docs/rate-limit-tests.md |
|
|
45
|
-
| `runFuzzCheck({ endpoint, baseUrl, headers? })` | Single-endpoint crash-resistance fuzz | → docs/fuzz-tests.md |
|
|
46
|
-
| `runFuzzTests({ apiMethodMap, baseUrl, skip?, headers?, onResult? })` | Sweep fuzz layer (nightly CI) | → docs/fuzz-tests.md |
|
|
47
|
-
| `resetServerState({ baseUrl, token?, only? })` | POST naar `/_test/reset`. Zonder `only` wist hij rate limits + standaard Redis-sessienamespaces; met `only` alleen de genoemde targets (de runner stuurt altijd `only: ['rateLimits']`). Nooit app-DB/custom adapters | → docs/rate-limit-tests.md |
|
|
48
|
-
| `resolveTestBaseUrl({ cwd?, fallbackUrl? })` | Resolves `TEST_BASE_URL` → actually-bound dev port advertisement → caller fallback, so an auto-hop does not create false connection failures. | → docs/contract-tests.md |
|
|
49
|
-
| `resolveTestEnvironment({ loadProjectConfig? })` | Laadt `.env`-lagen en resolveert optionele secret-manager-pointers in het testproces vóór DB/Redis-backed Layer-5 modules importeren. | → docs/contract-tests.md |
|
|
50
|
-
| `sampleSchemaInput(schema, options?)` | Genereert Zod-valid sample payload uit een schema. `options.stringPrefix` tagt UNCONSTRAINED strings (finding #98) — format/checked strings blijven ongeprefixt zodat ze valid blijven. | → docs/contract-tests.md |
|
|
51
|
-
| `createTestDataMarker()` / `TEST_DATA_PREFIX` | Run-unique `lstest_<uuid>_` marker (+ vaste `lstest_` prefix-constant) waarmee `runAllTests` gegenereerde test-strings identificeerbaar maakt. | → docs/contract-tests.md |
|
|
52
|
-
| `logContractResult(result)` | Pretty-print één `ContractCheckResult` | → docs/extension-hooks.md |
|
|
53
|
-
| `logContractSummary(summary)` | Pretty-print aggregate `RunContractSummary` | → docs/extension-hooks.md |
|
|
54
|
-
| `registerTestLayer(layer)` | Plug-in custom test-layer (CORS, business rules, multi-tenant) | → docs/extension-hooks.md |
|
|
55
|
-
| `listTestLayers()` | Lees alle geregistreerde custom layers | → docs/extension-hooks.md |
|
|
56
|
-
| `registerTestFixture(typeKey, fixture)` | Realistic-payload fixtures per typeKey (valid + invalid) | → docs/fuzz-tests.md |
|
|
57
|
-
| `getTestFixture(typeKey)` | Lees fixture voor een typeKey | → docs/fuzz-tests.md |
|
|
58
|
-
| `registerTestReporter(reporter)` | Plug-in onResult/onSummary/webhookUrl callbacks | → docs/extension-hooks.md |
|
|
59
|
-
| `getTestReporter()` | Lees actieve reporter callbacks | → docs/extension-hooks.md |
|
|
60
|
-
| `resetTestExtensionsForTests()` | Clear alle registries (alleen voor interne tests) | → docs/extension-hooks.md |
|
|
61
|
-
| Type: `EndpointDescriptor` | `{ page, name, version, method, fullPath, kind? }` — `kind` ontbreekt = `'api'` | → docs/contract-tests.md |
|
|
62
|
-
| Type: `SyncMetaMap` / `SyncMetaEntry` | Spiegel van de generated `syncMetaMap` (auth + rateLimit per sync route) | → docs/contract-tests.md |
|
|
63
|
-
| Type: `ProbeTransport` / `ProbeTransportRequest` / `ProbeRequestInput` / `ProbeResponse` / `HttpProbeTransportOptions` / `SocketProbeTransportOptions` | Probe-transport contract | → docs/contract-tests.md |
|
|
64
|
-
| Type: `InputSchemaMap` / `CreateSampleInputForOptions` | Inputs voor `createSampleInputFor` | → docs/contract-tests.md |
|
|
65
|
-
| Type: `HttpMethod` | `'GET' \| 'POST' \| 'PUT' \| 'DELETE'` | → docs/contract-tests.md |
|
|
66
|
-
| Type: `ContractCheckResult` | Single-result shape (status, httpStatus, responseStatus, errorCode, reason, durationMs) | → docs/contract-tests.md |
|
|
67
|
-
| Type: `RunContractSummary` | Aggregate shape (total, passed, failed, skipped, results[]) | → docs/contract-tests.md |
|
|
68
|
-
| Type: `TestLayer` / `TestLayerInput` / `TestLayerResult` | Custom-layer interface | → docs/extension-hooks.md |
|
|
69
|
-
| Type: `TestFixture` | `{ valid: T[], invalid: T[] }` per typeKey | → docs/fuzz-tests.md |
|
|
70
|
-
| Type: `TestResult` / `TestSummary` | Aggregate shapes voor extension registry | → docs/extension-hooks.md |
|
|
71
|
-
| Type: `TestReporter` | `{ onResult?, onSummary?, webhookUrl?, webhookAuth? }` | → docs/extension-hooks.md |
|
|
72
|
-
| Type: `RunContractTestsInput` / `ContractCheckInput` | Inputs voor contract layer | → docs/contract-tests.md |
|
|
73
|
-
| Type: `RunAuthEnforcementTestsInput` / `AuthEnforcementCheckInput` | Inputs voor auth layer | → docs/auth-tests.md |
|
|
74
|
-
| Type: `RunRateLimitTestsInput` / `RateLimitCheckInput` | Inputs voor rate-limit layer | → docs/rate-limit-tests.md |
|
|
75
|
-
| Type: `RunFuzzTestsInput` / `FuzzCheckInput` | Inputs voor fuzz layer | → docs/fuzz-tests.md |
|
|
76
|
-
| Type: `ResetServerStateInput` | Input voor `resetServerState` | → docs/rate-limit-tests.md |
|
|
77
|
-
| Type: `TestContext` | `{ callApi, callSync, watchStream, session, prisma, expect }` — handed naar elke Layer-5 custom-tests case. `callSync` volgt `transport.invocation` van het project (`socket` → echte Socket.io emit, `routed-http` → `/sync/*`). | → docs/contract-tests.md |
|
|
78
|
-
| Type: `CallSyncOptions` | `callSync` opts: `receiver`, `ignoreSelf`, `transport` (per-call override), `joinRoom` (default `true`: de case-socket joint eerst `receiver`) | → docs/contract-tests.md |
|
|
79
|
-
| `ctx.watchStream(roomCode)` | Open een second-socket (socket B) joined aan `roomCode` om de chunk stream van `broadcastStream`/`streamTo`/`_client_v{N}` te observeren. Returnt `StreamWatcher<TChunk>` met `.chunks[]`, `.stopAt(predicate, timeoutMs?)`, `.waitForCount(n, timeoutMs?)`, `.close()`. Watchers worden auto-closed na elke case. | → docs/contract-tests.md |
|
|
80
|
-
| `openStreamWatcher(input)` | Lower-level factory voor `watchStream` — direct bruikbaar buiten een `TestContext` (custom layers, ad-hoc harness scripts). | → docs/contract-tests.md |
|
|
81
|
-
| Type: `StreamWatcher<TChunk>` | `{ readonly chunks, stopAt, waitForCount, close }` — observable chunk stream voor één route. | → docs/contract-tests.md |
|
|
82
|
-
| Type: `StreamChunkFrame` | Wire-shape van een sync chunk frame (`{ cb, fullName, status: 'stream', ...payload }`). Default chunk type voor `StreamWatcher`. | → docs/contract-tests.md |
|
|
83
|
-
| Type: `OpenStreamWatcherInput` | `{ baseUrl, roomCode, token, routeFullName, defaultTimeoutMs? }` voor `openStreamWatcher`. | → docs/contract-tests.md |
|
|
84
|
-
| Type: `CustomTestCase` | `{ name, run(ctx) }` — shape die consumers exporteren uit `<name>_v<N>.tests.ts`. | → docs/contract-tests.md |
|
|
85
|
-
| Type: `RunAllTestsSummary` | Aggregate result shape voor `runAllTests` (per-layer summaries + totals). | → docs/contract-tests.md |
|
|
86
|
-
| Type: `RunCustomTestsSummary` | Aggregate result shape voor `runCustomTests` (per-file resultaten + totals). | → docs/contract-tests.md |
|
|
87
|
-
|
|
88
|
-
## Config keys (env vars + register* slots)
|
|
89
|
-
|
|
90
|
-
- `TEST_BASE_URL` (env, test process) — explicit target override consumed first by `resolveTestBaseUrl`; otherwise it reads `node_modules/.luckystack/dev-server.json` and then uses the supplied config-derived fallback.
|
|
91
|
-
- `RunAllTestsInput.loadProjectConfig` / `RunCustomTestsInput.loadProjectConfig` — verplichte lazy loader voor de default export van consumer `config.ts`. De runner laadt eerst `.env`/`.env.local`, leest daarna deze config en draait bij een niet-lege `secretManager.url` `initSecretManager({...config, source:'remote'})` vóór custom test imports. `runAllTests` doet dit één keer voor alle lagen; directe Layer-5-calls doen het zelf. Een ontbrekende loader of geconfigureerd-maar-ontbrekende secret-manager is een harde fout.
|
|
92
|
-
- `NODE_ENV` (env, server-side) — `/_test/reset` is alleen beschikbaar bij exact `development` of `test`.
|
|
93
|
-
- `TEST_RESET_TOKEN` (env, optional, server-side) — wanneer gezet moet `resetServerState({ token })` deze meesturen als `X-Test-Reset-Token`. Verplicht voor staging/preview deploys die het endpoint over het netwerk exposen.
|
|
94
|
-
- `RunRateLimitTestsInput.maxRateLimitToTest` (default `50`) — endpoints met hogere `rateLimit` worden geskipt om duizenden requests in CI te vermijden.
|
|
95
|
-
- `RunRateLimitTestsInput.resetBetweenEndpoints` (default `false`) — hit `/_test/reset` voor elke endpoint zodat het shared IP-bucket schoon is.
|
|
96
|
-
- `RunAllTestsInput.resetBookends` (default `true` wanneer een reset-token beschikbaar is) — POST `/_test/reset?only=rateLimits` één keer vóór en één keer ná de auto-sweep, zodat geen limiter-bucket leeggelopen achterblijft. Wist alleen limiter-state: sessies (ook die van `authToken`) blijven staan, en de app-database wordt nooit aangeraakt — door de sweep aangemaakte `lstest_*` rows blijven dus bestaan. Zonder token (`resetToken`/`TEST_RESET_TOKEN`) worden de bookends met een logregel geskipt, niet gefaald.
|
|
97
|
-
- `RunAllTestsInput.outputFile` (default `TEST_OUTPUT_FILE` env, anders `test-results.json`; `false` = uit) — `runAllTests` schrijft de volledige summary-JSON zelf; een entry-script hoeft dat niet meer te doen.
|
|
98
|
-
- `RunAllTestsInput.syncMetaMap` / `syncInputSchemas` — generated door devkit; zonder `syncMetaMap` worden sync routes niet geswept.
|
|
99
|
-
- `RunAllTestsInput.syncTransport` (`'socket' | 'http'`, default afgeleid van `transport.invocation`) — hoe de sweep sync routes bereikt.
|
|
100
|
-
- `RunAllTestsInput.filter` (het `testAll.ts` entry-script vult hem uit `TEST_FILTER`) — substring op `<page>/<name>/<version>`; niet-matchende routes worden niet aangevraagd (niet alleen uit het rapport gefilterd).
|
|
101
|
-
- `registerTestLayer({ name, run })` — custom check per endpoint (CORS, business rules, custom auth-schemes, multi-tenant isolation).
|
|
102
|
-
- `registerTestFixture(typeKey, { valid, invalid })` — realistic payloads die de fuzz layer prefereert boven schema-random.
|
|
103
|
-
- `registerTestReporter({ onResult?, onSummary?, webhookUrl?, webhookAuth? })` — wire per-result/per-summary callbacks of POST de summary naar een webhook.
|
|
104
|
-
|
|
105
|
-
## Peer dependencies
|
|
106
|
-
|
|
107
|
-
- **Required**: `zod@^4.0.0` (peer), `socket.io-client@^4.8.0` (peer — `streamWatcher.ts` opent een tweede socket voor `ctx.watchStream`), `@luckystack/core` (direct runtime dependency — levert de helpers die de runner consumeert: `tryCatch`/`tryCatchSync`, `getProjectConfig`/`getCsrfConfig`, `getSrcDir` (default src-dir voor custom-test discovery in `customTests.ts`), `getPrismaClient` (Layer-5 `ctx.prisma`) en `clearAllRateLimits`. De `apiMethodMap` zelf wordt door de consumer als argument doorgegeven, niet uit een pad gelezen).
|
|
108
|
-
- **Required server-side**: `@luckystack/server` met `/_test/reset` gemount, exact `NODE_ENV=development|test`, en een niet-lege `TEST_RESET_TOKEN`.
|
|
109
|
-
- **Required generated artefact**: `apiMethodMap.generated.ts` (en `apiMetaMap.generated.ts` voor de auth/rate-limit layers), geproduceerd door `@luckystack/devkit`.
|
|
110
|
-
- **Optional**: `@luckystack/secret-manager@^0.8.4` (optional peer) — alleen dynamisch geladen wanneer `loadProjectConfig` een niet-lege `config.secretManager.url` teruggeeft. Zonder secret-managerconfig blijft de runner een gewone lokale-env flow.
|
|
111
|
-
|
|
112
|
-
## Related
|
|
113
|
-
|
|
114
|
-
- Architecture deep-dives: `/docs/ARCHITECTURE_API.md` (het contract dat deze runner asserteert), `/docs/ARCHITECTURE_PACKAGING.md` (hoe generated maps per preset worden geëmit).
|
|
115
|
-
- Consumer quickstart: `./README.md`.
|
|
116
|
-
- Devkit (genereert de maps die deze runner consumeert): `packages/devkit/CLAUDE.md`.
|
|
117
|
-
- Server (`/_test/reset` endpoint): `packages/server/CLAUDE.md`.
|