@ricsam/isolate-test-utils 0.1.10 → 0.1.11

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 (45) hide show
  1. package/dist/cjs/fetch-context.cjs +66 -0
  2. package/dist/cjs/fetch-context.cjs.map +10 -0
  3. package/dist/cjs/fs-context.cjs +73 -0
  4. package/dist/cjs/fs-context.cjs.map +10 -0
  5. package/dist/cjs/index.cjs +121 -0
  6. package/dist/cjs/index.cjs.map +10 -0
  7. package/{src/mock-fs.ts → dist/cjs/mock-fs.cjs} +63 -97
  8. package/dist/cjs/mock-fs.cjs.map +10 -0
  9. package/dist/cjs/native-input-test.cjs +347 -0
  10. package/dist/cjs/native-input-test.cjs.map +10 -0
  11. package/dist/cjs/package.json +5 -0
  12. package/dist/cjs/runtime-context.cjs +97 -0
  13. package/dist/cjs/runtime-context.cjs.map +10 -0
  14. package/dist/cjs/server.cjs +109 -0
  15. package/dist/cjs/server.cjs.map +10 -0
  16. package/dist/mjs/fetch-context.mjs +23 -0
  17. package/dist/mjs/fetch-context.mjs.map +10 -0
  18. package/dist/mjs/fs-context.mjs +30 -0
  19. package/dist/mjs/fs-context.mjs.map +10 -0
  20. package/dist/mjs/index.mjs +78 -0
  21. package/dist/mjs/index.mjs.map +10 -0
  22. package/dist/mjs/mock-fs.mjs +181 -0
  23. package/dist/mjs/mock-fs.mjs.map +10 -0
  24. package/{src/native-input-test.ts → dist/mjs/native-input-test.mjs} +60 -169
  25. package/dist/mjs/native-input-test.mjs.map +10 -0
  26. package/dist/mjs/package.json +5 -0
  27. package/dist/mjs/runtime-context.mjs +67 -0
  28. package/dist/mjs/runtime-context.mjs.map +10 -0
  29. package/dist/mjs/server.mjs +79 -0
  30. package/dist/mjs/server.mjs.map +10 -0
  31. package/dist/types/fetch-context.d.ts +7 -0
  32. package/dist/types/fs-context.d.ts +30 -0
  33. package/dist/types/index.d.ts +88 -0
  34. package/dist/types/mock-fs.d.ts +59 -0
  35. package/dist/types/native-input-test.d.ts +29 -0
  36. package/dist/types/runtime-context.d.ts +73 -0
  37. package/dist/types/server.d.ts +53 -0
  38. package/package.json +45 -18
  39. package/CHANGELOG.md +0 -119
  40. package/src/fetch-context.ts +0 -33
  41. package/src/fs-context.ts +0 -65
  42. package/src/index.test.ts +0 -472
  43. package/src/index.ts +0 -177
  44. package/src/runtime-context.ts +0 -148
  45. package/src/server.ts +0 -150
@@ -1,148 +0,0 @@
1
- import { MockFileSystem } from "./mock-fs.ts";
2
-
3
- export interface MockResponse {
4
- status?: number;
5
- body?: string;
6
- headers?: Record<string, string>;
7
- }
8
-
9
- export interface RuntimeTestContextOptions {
10
- /** Enable file system APIs with mock file system */
11
- fs?: boolean;
12
- }
13
-
14
- export interface RuntimeTestContext {
15
- /** Execute code in the runtime (ES module mode, supports top-level await) */
16
- eval(code: string): Promise<void>;
17
- /** Clear all pending timers */
18
- clearTimers(): void;
19
- /** Dispatch an HTTP request to the serve() handler */
20
- dispatchRequest(request: Request): Promise<Response>;
21
- /** Dispose all resources */
22
- dispose(): Promise<void>;
23
- /** Captured console.log calls */
24
- logs: Array<{ level: string; stdout: string }>;
25
- /** Captured fetch calls */
26
- fetchCalls: Array<{ url: string; method: string; headers: [string, string][] }>;
27
- /** Set the mock response for the next fetch call */
28
- setMockResponse(response: MockResponse): void;
29
- /** Mock file system (only available if fs option is true) */
30
- mockFs: MockFileSystem;
31
- /**
32
- * Get a result from the isolate. Call `await setResult(value)` in your eval code
33
- * to pass a value back to the host.
34
- */
35
- getResult<T = unknown>(): T | undefined;
36
- /** Clear the stored result */
37
- clearResult(): void;
38
- }
39
-
40
- /**
41
- * Create a full runtime test context with all APIs set up.
42
- * Includes console logging capture, fetch mocking, and optionally file system.
43
- *
44
- * @example
45
- * const ctx = await createRuntimeTestContext({ fs: true });
46
- *
47
- * // Set up mock response for fetch
48
- * ctx.setMockResponse({ status: 200, body: '{"data": "test"}' });
49
- *
50
- * // Run code and pass result back via setResult
51
- * await ctx.eval(`
52
- * console.log("Starting fetch...");
53
- * const response = await fetch("https://api.example.com/data");
54
- * const data = await response.json();
55
- * console.log("Got data:", data);
56
- * setResult(data);
57
- * `);
58
- *
59
- * // Get the result
60
- * console.log(ctx.getResult()); // { data: "test" }
61
- *
62
- * // Check logs
63
- * console.log(ctx.logs); // [{ level: "log", stdout: "Starting fetch..." }, ...]
64
- *
65
- * // Check fetch calls
66
- * console.log(ctx.fetchCalls); // [{ url: "https://api.example.com/data", method: "GET", ... }]
67
- *
68
- * await ctx.dispose();
69
- */
70
- export async function createRuntimeTestContext(
71
- options?: RuntimeTestContextOptions
72
- ): Promise<RuntimeTestContext> {
73
- const opts = options ?? {};
74
- const { createRuntime } = await import("@ricsam/isolate-runtime");
75
- const { clearAllInstanceState } = await import("@ricsam/isolate-core");
76
-
77
- // Clear any previous instance state
78
- clearAllInstanceState();
79
-
80
- // State for capturing logs and fetch calls
81
- const logs: Array<{ level: string; stdout: string }> = [];
82
- const fetchCalls: Array<{
83
- url: string;
84
- method: string;
85
- headers: [string, string][];
86
- }> = [];
87
-
88
- let mockResponse: MockResponse = { status: 200, body: "" };
89
- let storedResult: unknown = undefined;
90
-
91
- // Create mock file system
92
- const mockFs = new MockFileSystem();
93
-
94
- // Create runtime with configured handlers
95
- const runtime = await createRuntime({
96
- console: {
97
- onEntry: (entry) => {
98
- if (entry.type === "output") {
99
- logs.push({ level: entry.level, stdout: entry.stdout });
100
- } else if (entry.type === "assert") {
101
- logs.push({ level: "error", stdout: entry.stdout });
102
- }
103
- },
104
- },
105
- fetch: async (request: Request) => {
106
- // Capture fetch call
107
- fetchCalls.push({
108
- url: request.url,
109
- method: request.method,
110
- headers: [...request.headers.entries()],
111
- });
112
-
113
- // Return mock response
114
- return new Response(mockResponse.body ?? "", {
115
- status: mockResponse.status ?? 200,
116
- headers: mockResponse.headers,
117
- });
118
- },
119
- fs: opts.fs ? { getDirectory: async () => mockFs } : undefined,
120
- customFunctions: {
121
- setResult: {
122
- fn: (value: unknown) => {
123
- storedResult = value;
124
- },
125
- type: 'sync',
126
- },
127
- },
128
- });
129
-
130
- return {
131
- eval: runtime.eval.bind(runtime),
132
- clearTimers: runtime.timers.clearAll.bind(runtime.timers),
133
- dispatchRequest: runtime.fetch.dispatchRequest.bind(runtime.fetch),
134
- dispose: runtime.dispose.bind(runtime),
135
- logs,
136
- fetchCalls,
137
- setMockResponse(response: MockResponse) {
138
- mockResponse = response;
139
- },
140
- mockFs,
141
- getResult<T = unknown>(): T | undefined {
142
- return storedResult as T | undefined;
143
- },
144
- clearResult() {
145
- storedResult = undefined;
146
- },
147
- };
148
- }
package/src/server.ts DELETED
@@ -1,150 +0,0 @@
1
- import { createServer, type Server, type IncomingMessage, type ServerResponse } from "node:http";
2
-
3
- export interface MockServerResponse {
4
- status?: number;
5
- body?: string;
6
- headers?: Record<string, string>;
7
- }
8
-
9
- export interface RecordedRequest {
10
- method: string;
11
- path: string;
12
- headers: Record<string, string>;
13
- body?: string;
14
- }
15
-
16
- export interface IntegrationServer {
17
- /** The base URL of the server (e.g., "http://localhost:3000") */
18
- url: string;
19
- /** The port the server is listening on */
20
- port: number;
21
- /** Close the server */
22
- close(): Promise<void>;
23
- /** Set the response for a specific path */
24
- setResponse(path: string, response: MockServerResponse): void;
25
- /** Set a default response for any unmatched path */
26
- setDefaultResponse(response: MockServerResponse): void;
27
- /** Get all recorded requests */
28
- getRequests(): RecordedRequest[];
29
- /** Clear all recorded requests */
30
- clearRequests(): void;
31
- /** Clear all configured responses */
32
- clearResponses(): void;
33
- }
34
-
35
- /**
36
- * Start an HTTP server for integration tests.
37
- * Useful for testing fetch operations against a real server.
38
- *
39
- * @example
40
- * const server = await startIntegrationServer();
41
- *
42
- * server.setResponse("/api/data", {
43
- * status: 200,
44
- * body: JSON.stringify({ message: "Hello" }),
45
- * headers: { "Content-Type": "application/json" }
46
- * });
47
- *
48
- * // In your test
49
- * const response = await fetch(`${server.url}/api/data`);
50
- * const data = await response.json();
51
- *
52
- * // Check what requests were made
53
- * const requests = server.getRequests();
54
- * console.log(requests[0].path); // "/api/data"
55
- *
56
- * await server.close();
57
- */
58
- export async function startIntegrationServer(
59
- port?: number
60
- ): Promise<IntegrationServer> {
61
- const responses = new Map<string, MockServerResponse>();
62
- const requests: RecordedRequest[] = [];
63
- let defaultResponse: MockServerResponse = { status: 404, body: "Not Found" };
64
-
65
- const server: Server = createServer(
66
- async (req: IncomingMessage, res: ServerResponse) => {
67
- const path = req.url ?? "/";
68
- const method = req.method ?? "GET";
69
-
70
- // Read request body
71
- const chunks: Buffer[] = [];
72
- for await (const chunk of req) {
73
- chunks.push(chunk as Buffer);
74
- }
75
- const body = chunks.length > 0 ? Buffer.concat(chunks).toString() : undefined;
76
-
77
- // Record the request
78
- const headers: Record<string, string> = {};
79
- for (const [key, value] of Object.entries(req.headers)) {
80
- if (typeof value === "string") {
81
- headers[key] = value;
82
- } else if (Array.isArray(value)) {
83
- headers[key] = value.join(", ");
84
- }
85
- }
86
- requests.push({ method, path, headers, body });
87
-
88
- // Find and send response
89
- const mockResponse = responses.get(path) ?? defaultResponse;
90
-
91
- res.statusCode = mockResponse.status ?? 200;
92
-
93
- if (mockResponse.headers) {
94
- for (const [key, value] of Object.entries(mockResponse.headers)) {
95
- res.setHeader(key, value);
96
- }
97
- }
98
-
99
- res.end(mockResponse.body ?? "");
100
- }
101
- );
102
-
103
- // Find an available port
104
- const actualPort = await new Promise<number>((resolve, reject) => {
105
- server.listen(port ?? 0, () => {
106
- const address = server.address();
107
- if (address && typeof address === "object") {
108
- resolve(address.port);
109
- } else {
110
- reject(new Error("Failed to get server address"));
111
- }
112
- });
113
- server.on("error", reject);
114
- });
115
-
116
- return {
117
- url: `http://localhost:${actualPort}`,
118
- port: actualPort,
119
-
120
- async close() {
121
- return new Promise((resolve, reject) => {
122
- server.close((err) => {
123
- if (err) reject(err);
124
- else resolve();
125
- });
126
- });
127
- },
128
-
129
- setResponse(path: string, response: MockServerResponse) {
130
- responses.set(path, response);
131
- },
132
-
133
- setDefaultResponse(response: MockServerResponse) {
134
- defaultResponse = response;
135
- },
136
-
137
- getRequests() {
138
- return [...requests];
139
- },
140
-
141
- clearRequests() {
142
- requests.length = 0;
143
- },
144
-
145
- clearResponses() {
146
- responses.clear();
147
- defaultResponse = { status: 404, body: "Not Found" };
148
- },
149
- };
150
- }