@ricsam/isolate-test-utils 0.1.10 → 0.1.12
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/dist/cjs/fetch-context.cjs +66 -0
- package/dist/cjs/fetch-context.cjs.map +10 -0
- package/dist/cjs/fs-context.cjs +73 -0
- package/dist/cjs/fs-context.cjs.map +10 -0
- package/dist/cjs/index.cjs +121 -0
- package/dist/cjs/index.cjs.map +10 -0
- package/{src/mock-fs.ts → dist/cjs/mock-fs.cjs} +63 -97
- package/dist/cjs/mock-fs.cjs.map +10 -0
- package/dist/cjs/native-input-test.cjs +347 -0
- package/dist/cjs/native-input-test.cjs.map +10 -0
- package/dist/cjs/package.json +5 -0
- package/dist/cjs/runtime-context.cjs +97 -0
- package/dist/cjs/runtime-context.cjs.map +10 -0
- package/dist/cjs/server.cjs +109 -0
- package/dist/cjs/server.cjs.map +10 -0
- package/dist/mjs/fetch-context.mjs +23 -0
- package/dist/mjs/fetch-context.mjs.map +10 -0
- package/dist/mjs/fs-context.mjs +30 -0
- package/dist/mjs/fs-context.mjs.map +10 -0
- package/dist/mjs/index.mjs +78 -0
- package/dist/mjs/index.mjs.map +10 -0
- package/dist/mjs/mock-fs.mjs +181 -0
- package/dist/mjs/mock-fs.mjs.map +10 -0
- package/{src/native-input-test.ts → dist/mjs/native-input-test.mjs} +60 -169
- package/dist/mjs/native-input-test.mjs.map +10 -0
- package/dist/mjs/package.json +5 -0
- package/dist/mjs/runtime-context.mjs +67 -0
- package/dist/mjs/runtime-context.mjs.map +10 -0
- package/dist/mjs/server.mjs +79 -0
- package/dist/mjs/server.mjs.map +10 -0
- package/dist/types/fetch-context.d.ts +7 -0
- package/dist/types/fs-context.d.ts +30 -0
- package/dist/types/index.d.ts +88 -0
- package/dist/types/mock-fs.d.ts +59 -0
- package/dist/types/native-input-test.d.ts +29 -0
- package/dist/types/runtime-context.d.ts +73 -0
- package/dist/types/server.d.ts +53 -0
- package/package.json +45 -18
- package/CHANGELOG.md +0 -119
- package/src/fetch-context.ts +0 -33
- package/src/fs-context.ts +0 -65
- package/src/index.test.ts +0 -472
- package/src/index.ts +0 -177
- package/src/runtime-context.ts +0 -148
- package/src/server.ts +0 -150
package/src/runtime-context.ts
DELETED
|
@@ -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
|
-
}
|