@gcoredev/fastedge-test 0.1.6 → 0.2.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.
Files changed (43) hide show
  1. package/dist/frontend/assets/{index-BpdzhbRl.js → index-CiqeJ9rz.js} +24 -24
  2. package/dist/frontend/index.html +1 -1
  3. package/dist/lib/index.cjs +164 -66
  4. package/dist/lib/index.d.ts +1 -0
  5. package/dist/lib/index.js +164 -66
  6. package/dist/lib/runner/HeaderManager.d.ts +6 -4
  7. package/dist/lib/runner/HostFunctions.d.ts +5 -5
  8. package/dist/lib/runner/HttpWasmRunner.d.ts +22 -5
  9. package/dist/lib/runner/IStateManager.d.ts +7 -7
  10. package/dist/lib/runner/IWasmRunner.d.ts +42 -10
  11. package/dist/lib/runner/PortManager.d.ts +4 -1
  12. package/dist/lib/runner/PropertyResolver.d.ts +3 -3
  13. package/dist/lib/runner/ProxyWasmRunner.d.ts +5 -2
  14. package/dist/lib/runner/standalone.d.ts +1 -1
  15. package/dist/lib/runner/types.d.ts +17 -8
  16. package/dist/lib/schemas/api.d.ts +2 -8
  17. package/dist/lib/schemas/config.d.ts +2 -13
  18. package/dist/lib/schemas/index.d.ts +2 -2
  19. package/dist/lib/test-framework/assertions.d.ts +18 -4
  20. package/dist/lib/test-framework/index.cjs +18634 -115
  21. package/dist/lib/test-framework/index.d.ts +2 -0
  22. package/dist/lib/test-framework/index.js +18651 -104
  23. package/dist/lib/test-framework/mock-origins.d.ts +56 -0
  24. package/dist/lib/test-framework/suite-runner.d.ts +16 -0
  25. package/dist/lib/test-framework/types.d.ts +1 -5
  26. package/dist/server.js +33 -33
  27. package/docs/API.md +48 -54
  28. package/docs/DEBUGGER.md +7 -8
  29. package/docs/INDEX.md +4 -1
  30. package/docs/RUNNER.md +126 -74
  31. package/docs/TEST_CONFIG.md +79 -40
  32. package/docs/TEST_FRAMEWORK.md +235 -36
  33. package/docs/WEBSOCKET.md +25 -21
  34. package/docs/quickstart.md +1 -13
  35. package/package.json +4 -1
  36. package/schemas/api-config.schema.json +5 -24
  37. package/schemas/api-load.schema.json +5 -0
  38. package/schemas/api-send.schema.json +0 -20
  39. package/schemas/fastedge-config.test.schema.json +5 -24
  40. package/schemas/full-flow-result.schema.json +17 -7
  41. package/schemas/hook-call.schema.json +16 -6
  42. package/schemas/hook-result.schema.json +16 -6
  43. package/schemas/http-response.schema.json +227 -5
package/docs/API.md CHANGED
@@ -2,6 +2,8 @@
2
2
 
3
3
  The `@gcoredev/fastedge-test` debugger server exposes a REST API for loading WASM modules, executing requests, and managing test configuration.
4
4
 
5
+ > **Note on header values.** Response-side and hook-result headers use `Record<string, string | string[]>` — single-valued headers are a `string`, multi-valued headers (notably `Set-Cookie` per RFC 6265) are a `string[]`. Request-side header inputs are single-valued `Record<string, string>`.
6
+
5
7
  ## Base URL
6
8
 
7
9
  ```
@@ -93,16 +95,19 @@ Loads a WASM binary into the runner. Accepts either a file path or a base64-enco
93
95
 
94
96
  **Request Body**
95
97
 
96
- Exactly one of `wasmPath` or `wasmBase64` must be provided.
98
+ Exactly one of `wasmPath` or `wasmBase64` must be provided; providing both is an error.
97
99
 
98
100
  ```typescript
99
101
  {
100
- wasmPath?: string; // Absolute path to a .wasm file on the server filesystem
101
- wasmBase64?: string; // Base64-encoded WASM binary
102
+ wasmPath?: string; // Absolute path to a .wasm file on the server filesystem
103
+ wasmBase64?: string; // Base64-encoded WASM binary; mutually exclusive with wasmPath
102
104
  dotenv?: {
103
- enabled: boolean; // Whether to load .env files for this module
104
- path?: string; // Directory containing .env files (defaults to server CWD)
105
+ enabled?: boolean; // Whether to load .env files for this module
106
+ path?: string; // Directory containing .env files (defaults to server CWD)
105
107
  };
108
+ httpPort?: number; // HTTP-WASM only. Pin the runner subprocess to this port (1024–65535).
109
+ // Load fails immediately if the port is already in use.
110
+ // Ignored for proxy-wasm modules.
106
111
  }
107
112
  ```
108
113
 
@@ -153,11 +158,31 @@ curl -X POST http://localhost:5179/api/load \
153
158
  }
154
159
  ```
155
160
 
161
+ **Example — pin HTTP-WASM to a specific port**
162
+
163
+ ```bash
164
+ curl -X POST http://localhost:5179/api/load \
165
+ -H "Content-Type: application/json" \
166
+ -d '{
167
+ "wasmPath": "/home/user/project/build/app.wasm",
168
+ "httpPort": 8100
169
+ }'
170
+ ```
171
+
172
+ ```json
173
+ {
174
+ "ok": true,
175
+ "wasmType": "http-wasm",
176
+ "resolvedPath": "/home/user/project/build/app.wasm"
177
+ }
178
+ ```
179
+
156
180
  **Error Responses**
157
181
 
158
182
  | Status | Condition |
159
183
  | ------ | ----------------------------------------------------------------------------------------------------------- |
160
184
  | `400` | Validation failed, missing both `wasmPath` and `wasmBase64`, invalid path, or path does not end in `.wasm` |
185
+ | `400` | `httpPort` is specified and already in use (HTTP-WASM only) |
161
186
  | `500` | WASM load failed or runner initialization error |
162
187
 
163
188
  ---
@@ -234,22 +259,16 @@ For **HTTP-WASM**, provide either `path` (preferred) or `url` (legacy). When `pa
234
259
  }
235
260
  ```
236
261
 
237
- For **Proxy-WASM**, the top-level `url` field is required. The full CDN flow is controlled via nested `request`, `response`, and `properties` fields:
262
+ For **Proxy-WASM**, the top-level `url` field is required. The full CDN flow is controlled via nested `request` and `properties` fields. The upstream response is generated at runtime — either by a real fetch against `url`, or by the built-in responder when `url === "built-in"`:
238
263
 
239
264
  ```typescript
240
265
  {
241
- url: string; // Request URL (required)
266
+ url: string; // Request URL, or "built-in" (required)
242
267
  request?: {
243
268
  method?: string; // HTTP method (default: "GET")
244
269
  headers?: Record<string, string>; // Request headers (default: {})
245
270
  body?: string; // Request body (default: "")
246
271
  };
247
- response?: {
248
- headers?: Record<string, string>; // Simulated upstream response headers (default: {})
249
- body?: string; // Simulated upstream response body (default: "")
250
- status?: number; // Simulated upstream response status (default: 200)
251
- statusText?: string; // Simulated upstream response status text (default: "OK")
252
- };
253
272
  properties?: Record<string, unknown>; // CDN properties (default: {})
254
273
  }
255
274
  ```
@@ -262,7 +281,7 @@ For **Proxy-WASM**, the top-level `url` field is required. The full CDN flow is
262
281
  result: {
263
282
  status: number;
264
283
  statusText: string;
265
- headers: Record<string, string>;
284
+ headers: Record<string, string | string[]>;
266
285
  body: string;
267
286
  contentType: string | null;
268
287
  isBase64?: boolean;
@@ -280,7 +299,7 @@ For **Proxy-WASM**, the top-level `url` field is required. The full CDN flow is
280
299
  finalResponse: {
281
300
  status: number;
282
301
  statusText: string;
283
- headers: Record<string, string>;
302
+ headers: Record<string, string | string[]>;
284
303
  body: string;
285
304
  contentType: string;
286
305
  isBase64?: boolean;
@@ -296,13 +315,13 @@ type HookResult = {
296
315
  returnCode: number | null;
297
316
  logs: Array<{ level: number; message: string }>;
298
317
  input: {
299
- request: { headers: Record<string, string>; body: string };
300
- response: { headers: Record<string, string>; body: string };
318
+ request: { headers: Record<string, string | string[]>; body: string };
319
+ response: { headers: Record<string, string | string[]>; body: string };
301
320
  properties?: Record<string, unknown>;
302
321
  };
303
322
  output: {
304
- request: { headers: Record<string, string>; body: string };
305
- response: { headers: Record<string, string>; body: string };
323
+ request: { headers: Record<string, string | string[]>; body: string };
324
+ response: { headers: Record<string, string | string[]>; body: string };
306
325
  properties?: Record<string, unknown>;
307
326
  };
308
327
  properties: Record<string, unknown>;
@@ -354,12 +373,6 @@ curl -X POST http://localhost:5179/api/execute \
354
373
  "headers": { "host": "example.com" },
355
374
  "body": ""
356
375
  },
357
- "response": {
358
- "headers": { "content-type": "text/html" },
359
- "body": "<html/>",
360
- "status": 200,
361
- "statusText": "OK"
362
- },
363
376
  "properties": {}
364
377
  }'
365
378
  ```
@@ -452,13 +465,13 @@ type HookResult = {
452
465
  returnCode: number | null;
453
466
  logs: Array<{ level: number; message: string }>;
454
467
  input: {
455
- request: { headers: Record<string, string>; body: string };
456
- response: { headers: Record<string, string>; body: string };
468
+ request: { headers: Record<string, string | string[]>; body: string };
469
+ response: { headers: Record<string, string | string[]>; body: string };
457
470
  properties?: Record<string, unknown>;
458
471
  };
459
472
  output: {
460
- request: { headers: Record<string, string>; body: string };
461
- response: { headers: Record<string, string>; body: string };
473
+ request: { headers: Record<string, string | string[]>; body: string };
474
+ response: { headers: Record<string, string | string[]>; body: string };
462
475
  properties?: Record<string, unknown>;
463
476
  };
464
477
  properties: Record<string, unknown>;
@@ -533,22 +546,18 @@ Requires a WASM module to be loaded via `POST /api/load`. Accepts an optional [`
533
546
 
534
547
  ```typescript
535
548
  {
536
- url: string | "built-in"; // Full request URL, or "built-in" to use the URL from loaded config
549
+ url: string | "built-in"; // Full request URL, or "built-in" to use the built-in responder
537
550
  request?: {
538
551
  method?: string; // HTTP method (default: "GET")
539
552
  url?: string;
540
553
  headers?: Record<string, string>; // Request headers (default: {})
541
554
  body?: string; // Request body (default: "")
542
555
  };
543
- response?: {
544
- headers?: Record<string, string>; // Simulated upstream response headers (default: {})
545
- body?: string; // Simulated upstream response body (default: "")
546
- };
547
556
  properties: Record<string, unknown>; // CDN properties (required; use {} if none)
548
557
  }
549
558
  ```
550
559
 
551
- The `response` object for this endpoint does not accept `status` or `statusText` the full flow always uses `200 OK` as the simulated upstream status. Use `POST /api/execute` if you need to control those values.
560
+ The upstream response is generated at runtimeeither by a real fetch against `url`, or by the built-in responder when `url === "built-in"`.
552
561
 
553
562
  **Response**
554
563
 
@@ -559,7 +568,7 @@ The `response` object for this endpoint does not accept `status` or `statusText`
559
568
  finalResponse: {
560
569
  status: number;
561
570
  statusText: string;
562
- headers: Record<string, string>;
571
+ headers: Record<string, string | string[]>;
563
572
  body: string;
564
573
  contentType: string;
565
574
  isBase64?: boolean;
@@ -583,10 +592,6 @@ curl -X POST http://localhost:5179/api/send \
583
592
  "headers": { "content-type": "application/json" },
584
593
  "body": "{\"key\":\"value\"}"
585
594
  },
586
- "response": {
587
- "headers": { "content-type": "application/json" },
588
- "body": "{\"result\":\"ok\"}"
589
- },
590
595
  "properties": {
591
596
  "client.geo.country": "DE"
592
597
  }
@@ -647,8 +652,8 @@ curl -X POST http://localhost:5179/api/send \
647
652
 
648
653
  **Error Responses**
649
654
 
650
- | Status | Condition |
651
- | ------ | --------------------------------------------------------------------------- |
655
+ | Status | Condition |
656
+ | ------ | ---------------------------------------------------------------------------- |
652
657
  | `400` | Validation failed (missing `url` or `properties`), or no WASM module loaded |
653
658
  | `500` | Execution failed |
654
659
 
@@ -689,10 +694,6 @@ type ProxyWasmConfig = {
689
694
  headers: Record<string, string>;
690
695
  body: string;
691
696
  };
692
- response?: {
693
- headers: Record<string, string>;
694
- body: string;
695
- };
696
697
  properties: Record<string, unknown>;
697
698
  dotenv?: { enabled?: boolean; path?: string };
698
699
  };
@@ -703,6 +704,7 @@ type HttpWasmConfig = {
703
704
  description?: string;
704
705
  appType: "http-wasm";
705
706
  wasm?: { path: string; description?: string };
707
+ httpPort?: number; // Pin the runner subprocess to this port (1024–65535)
706
708
  request: {
707
709
  method: string;
708
710
  path: string;
@@ -734,10 +736,6 @@ curl http://localhost:5179/api/config
734
736
  "headers": {},
735
737
  "body": ""
736
738
  },
737
- "response": {
738
- "headers": {},
739
- "body": ""
740
- },
741
739
  "properties": {}
742
740
  },
743
741
  "valid": true
@@ -792,10 +790,6 @@ curl -X POST http://localhost:5179/api/config \
792
790
  "headers": { "accept": "text/html" },
793
791
  "body": ""
794
792
  },
795
- "response": {
796
- "headers": {},
797
- "body": ""
798
- },
799
793
  "properties": {
800
794
  "client.geo.country": "US"
801
795
  }
package/docs/DEBUGGER.md CHANGED
@@ -71,7 +71,7 @@ process.kill(process.pid, "SIGTERM");
71
71
  PORT=8080 npx fastedge-debug
72
72
  ```
73
73
 
74
- If the preferred port is already in use, the server tries the next port sequentially, repeating up to 10 times (for example, `5179` through `5188` by default). If no free port is found in that range, the server exits with an error. Set `PORT` to a specific value to bypass auto-increment when a predictable port is required.
74
+ If the preferred port is already in use, the server tries the next port sequentially, up to 50 ports (for example, `5179` through `5228` by default). If no free port is found in that range, the server exits with an error. Set `PORT` to a specific value to bypass auto-increment when a predictable port is required.
75
75
 
76
76
  The server writes the bound port number to `.fastedge-debug/.debug-port` under `WORKSPACE_PATH` (if set) or the current working directory, and deletes the file on shutdown. Use this file for programmatic port discovery when starting the server as a subprocess.
77
77
 
@@ -98,13 +98,12 @@ curl http://localhost:5179/health
98
98
 
99
99
  ## Environment Variables
100
100
 
101
- | Variable | Type | Default | Description |
102
- | -------------------- | -------- | ------- | -------------------------------------------------------------------------------------------------------------------------- |
103
- | `PORT` | `number` | unset | Port the HTTP server listens on. Defaults to `5179` when not set. |
104
- | `PROXY_RUNNER_DEBUG` | `"1"` | unset | Enable verbose debug logging for WebSocket and runner activity. |
105
- | `VSCODE_INTEGRATION` | `"true"` | unset | Set to `"true"` when running in VSCode extension context; enables the `<workspace>` path placeholder in WASM path loading. |
106
- | `WORKSPACE_PATH` | `string` | unset | Absolute path to the workspace root; used as the `.env` file base and for port file placement. |
107
- | `FASTEDGE_RUN_PATH` | `string` | unset | Override the path to the `fastedge-run` CLI binary used to execute WASM modules. |
101
+ | Variable | Type | Default | Description |
102
+ | -------------------- | -------- | ------- | ----------------------------------------------------------------------------------------------- |
103
+ | `PORT` | `number` | unset | Port the HTTP server listens on. Defaults to `5179` when not set. |
104
+ | `PROXY_RUNNER_DEBUG` | `"1"` | unset | Enable verbose debug logging for WebSocket and runner activity. |
105
+ | `WORKSPACE_PATH` | `string` | unset | Absolute path to the workspace root; used as the `.env` file base and for port file placement. |
106
+ | `FASTEDGE_RUN_PATH` | `string` | unset | Override the path to the `fastedge-run` CLI binary used to execute WASM modules. |
108
107
 
109
108
  ### Usage examples
110
109
 
package/docs/INDEX.md CHANGED
@@ -79,12 +79,13 @@ import { defineTestSuite, runAndExit } from "@gcoredev/fastedge-test/test";
79
79
  | `runFlow` | function | Executes a single request flow directly |
80
80
  | `runHttpRequest` | function | Executes a single HTTP request directly |
81
81
  | `loadConfigFile` | function | Loads and validates a `fastedge-config.test.json` file |
82
+ | `mockOrigins` | function | Creates mock HTTP origins that respond to outgoing HTTP calls |
82
83
  | `assertRequestHeader` | function | Asserts a header is present on the outgoing request |
83
84
  | `assertNoRequestHeader` | function | Asserts a header is absent from the outgoing request |
84
85
  | `assertResponseHeader` | function | Asserts a header is present on the final response |
85
86
  | `assertNoResponseHeader` | function | Asserts a header is absent from the final response |
86
87
  | `assertFinalStatus` | function | Asserts the final HTTP status code |
87
- | `assertFinalHeader` | function | Asserts a header on the final response (alias for response header) |
88
+ | `assertFinalHeader` | function | Asserts a header on the final response |
88
89
  | `assertReturnCode` | function | Asserts the proxy-wasm return code |
89
90
  | `assertLog` | function | Asserts a log entry was emitted |
90
91
  | `assertNoLog` | function | Asserts a log entry was not emitted |
@@ -101,6 +102,8 @@ import { defineTestSuite, runAndExit } from "@gcoredev/fastedge-test/test";
101
102
  | `assertHttpContentType` | function | Asserts the HTTP response Content-Type header |
102
103
  | `assertHttpLog` | function | Asserts a log entry was emitted during HTTP request handling |
103
104
  | `assertHttpNoLog` | function | Asserts a log entry was not emitted during HTTP request handling |
105
+ | `MockOriginsHandle` | type | Handle returned by `mockOrigins` — use to stop the mock servers |
106
+ | `MockOriginsOptions` | type | Options accepted by `mockOrigins` |
104
107
  | `TestSuite` | type | Suite definition — one of `wasmPath` or `wasmBuffer` plus test cases |
105
108
  | `TestCase` | type | A single test scenario with config and assertions |
106
109
  | `TestResult` | type | Result of a single test case execution |