cf-bun-mocks 0.1.0-alpha.2 → 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.
- package/README.md +70 -17
- package/package.json +4 -4
- package/src/d1.ts +24 -8
- package/src/index.ts +1 -1
- package/src/workers.ts +33 -0
- package/src/env.ts +0 -17
package/README.md
CHANGED
|
@@ -26,12 +26,12 @@ const db = new D1Mock("./test.db");
|
|
|
26
26
|
|
|
27
27
|
### With Migrations
|
|
28
28
|
|
|
29
|
-
Use `
|
|
29
|
+
Use `createD1Mock` to create an in-memory database and run your migrations:
|
|
30
30
|
|
|
31
31
|
```typescript
|
|
32
|
-
import {
|
|
32
|
+
import { createD1Mock } from "cf-bun-mocks";
|
|
33
33
|
|
|
34
|
-
const db = await
|
|
34
|
+
const db = await createD1Mock("./migrations");
|
|
35
35
|
```
|
|
36
36
|
|
|
37
37
|
This reads all `.sql` files from the migrations directory in sorted order and executes them.
|
|
@@ -107,30 +107,79 @@ const env: Env = {
|
|
|
107
107
|
const response = await worker.fetch(request, env);
|
|
108
108
|
```
|
|
109
109
|
|
|
110
|
-
## Environment
|
|
110
|
+
## Workers Environment
|
|
111
111
|
|
|
112
|
-
|
|
112
|
+
For testing Cloudflare Workers, use the `useWorkersEnv` helper to create test environments:
|
|
113
113
|
|
|
114
114
|
```typescript
|
|
115
115
|
import { describe, test, expect } from "bun:test";
|
|
116
|
-
import {
|
|
116
|
+
import { useWorkersEnv, D1Mock } from "cf-bun-mocks";
|
|
117
117
|
import type { Env } from "./worker";
|
|
118
118
|
|
|
119
119
|
describe("my worker", () => {
|
|
120
|
-
|
|
120
|
+
const { env } = useWorkersEnv<Env>(() => ({
|
|
121
121
|
DB: new D1Mock(":memory:"),
|
|
122
122
|
MY_SECRET: "test-secret",
|
|
123
123
|
}));
|
|
124
124
|
|
|
125
|
-
test("uses
|
|
126
|
-
//
|
|
127
|
-
const
|
|
128
|
-
|
|
129
|
-
expect(result).toBeDefined();
|
|
125
|
+
test("uses test environment", async () => {
|
|
126
|
+
// Pass the env to your worker handler
|
|
127
|
+
const response = await worker.fetch(request, env);
|
|
128
|
+
expect(response.status).toBe(200);
|
|
130
129
|
});
|
|
131
130
|
});
|
|
132
131
|
```
|
|
133
132
|
|
|
133
|
+
### Module Mocking (Advanced)
|
|
134
|
+
|
|
135
|
+
For mocking `cloudflare:workers` module imports, use `setupWorkersMock` in a preload script and combine it with `useWorkersEnv`:
|
|
136
|
+
|
|
137
|
+
Create a `test-setup.ts` file:
|
|
138
|
+
|
|
139
|
+
```typescript
|
|
140
|
+
// test-setup.ts
|
|
141
|
+
import { setupWorkersMock } from "cf-bun-mocks";
|
|
142
|
+
|
|
143
|
+
// Set up module mocks before any test files load
|
|
144
|
+
await setupWorkersMock();
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
Then run tests with preload:
|
|
148
|
+
|
|
149
|
+
```bash
|
|
150
|
+
bun test --preload ./test-setup.ts
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
Or configure it in `bunfig.toml`:
|
|
154
|
+
|
|
155
|
+
```toml
|
|
156
|
+
[test]
|
|
157
|
+
preload = ["./test-setup.ts"]
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
Then use in your tests:
|
|
161
|
+
|
|
162
|
+
```typescript
|
|
163
|
+
import { describe, test, expect } from "bun:test";
|
|
164
|
+
import { useWorkersEnv, D1Mock } from "cf-bun-mocks";
|
|
165
|
+
|
|
166
|
+
describe("worker with module imports", () => {
|
|
167
|
+
useWorkersEnv(() => ({
|
|
168
|
+
DB: new D1Mock(":memory:"),
|
|
169
|
+
API_KEY: "test-key",
|
|
170
|
+
}));
|
|
171
|
+
|
|
172
|
+
test("uses mocked module", async () => {
|
|
173
|
+
// The env object reference stays the same, only properties change
|
|
174
|
+
const { env } = await import("cloudflare:workers");
|
|
175
|
+
expect(env.DB).toBeDefined();
|
|
176
|
+
expect(env.API_KEY).toBe("test-key");
|
|
177
|
+
});
|
|
178
|
+
});
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
> **Note**: `setupWorkersMock` uses Bun's `mock.module()` function. Module mocks must be set up before any imports happen. See [Bun's test lifecycle docs](https://bun.com/docs/test/lifecycle#global-setup-and-teardown) for preload details and [Bun's mocking docs](https://bun.sh/docs/test/mocking) for more on module mocking.
|
|
182
|
+
|
|
134
183
|
## API
|
|
135
184
|
|
|
136
185
|
### `D1Mock`
|
|
@@ -139,17 +188,21 @@ Implements the full `D1Database` interface from `@cloudflare/workers-types`:
|
|
|
139
188
|
|
|
140
189
|
- `prepare(query: string)` - Create a prepared statement
|
|
141
190
|
- `batch(statements: D1PreparedStatement[])` - Execute multiple statements
|
|
142
|
-
- `exec(query: string)` - Execute raw SQL
|
|
191
|
+
- `exec(query: string)` - Execute raw SQL (supports multiple statements)
|
|
143
192
|
- `dump()` - Serialize the database to an ArrayBuffer
|
|
144
193
|
- `withSession(constraint?)` - Get a session (bookmark tracking is stubbed)
|
|
145
194
|
|
|
146
|
-
### `
|
|
195
|
+
### `createD1Mock(migrationsPath: string)`
|
|
196
|
+
|
|
197
|
+
Creates an in-memory D1Mock and runs all `.sql` migration files from the specified directory in sorted order.
|
|
198
|
+
|
|
199
|
+
### `useWorkersEnv<TEnv>(createEnv: () => Partial<TEnv> | Promise<Partial<TEnv>>)`
|
|
147
200
|
|
|
148
|
-
|
|
201
|
+
Updates the global workers mock environment for each test. Must be used with `setupWorkersMock()`.
|
|
149
202
|
|
|
150
|
-
### `
|
|
203
|
+
### `setupWorkersMock<TEnv>(createMock?: () => WorkersModuleMock<TEnv> | Promise<WorkersModuleMock<TEnv>>)`
|
|
151
204
|
|
|
152
|
-
|
|
205
|
+
Sets up the `cloudflare:workers` module mock using Bun's `mock.module()`. **Must be called in a preload script before any test files load.** Use Bun's `--preload` flag or configure it in `bunfig.toml`. Call once at the start of your test suite, then use `useWorkersEnv()` to update the environment per test.
|
|
153
206
|
|
|
154
207
|
## Requirements
|
|
155
208
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cf-bun-mocks",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Cloudflare Workers mocks and helpers for Bun testing",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/index.ts",
|
|
@@ -15,9 +15,9 @@
|
|
|
15
15
|
"import": "./src/d1.ts",
|
|
16
16
|
"types": "./src/d1.ts"
|
|
17
17
|
},
|
|
18
|
-
"./
|
|
19
|
-
"import": "./src/
|
|
20
|
-
"types": "./src/
|
|
18
|
+
"./workers": {
|
|
19
|
+
"import": "./src/workers.ts",
|
|
20
|
+
"types": "./src/workers.ts"
|
|
21
21
|
}
|
|
22
22
|
},
|
|
23
23
|
"files": [
|
package/src/d1.ts
CHANGED
|
@@ -147,12 +147,20 @@ export class D1Mock implements D1Database {
|
|
|
147
147
|
|
|
148
148
|
async exec(query: string): Promise<D1ExecResult> {
|
|
149
149
|
const start = performance.now();
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
150
|
+
try {
|
|
151
|
+
const { changes: count } = this.#db.run(query);
|
|
152
|
+
const duration = performance.now() - start;
|
|
153
|
+
return {
|
|
154
|
+
count,
|
|
155
|
+
duration,
|
|
156
|
+
};
|
|
157
|
+
} catch (error) {
|
|
158
|
+
throw new Error(
|
|
159
|
+
`D1Mock exec failed: ${
|
|
160
|
+
error instanceof Error ? error.message : String(error)
|
|
161
|
+
}\nQuery: ${query}`
|
|
162
|
+
);
|
|
163
|
+
}
|
|
156
164
|
}
|
|
157
165
|
|
|
158
166
|
withSession(
|
|
@@ -173,14 +181,22 @@ export class D1Mock implements D1Database {
|
|
|
173
181
|
}
|
|
174
182
|
}
|
|
175
183
|
|
|
176
|
-
export async function
|
|
184
|
+
export async function createD1Mock(migrationsPath: string): Promise<D1Mock> {
|
|
177
185
|
const files = readdirSync(migrationsPath)
|
|
178
186
|
.filter((file) => file.endsWith(".sql"))
|
|
179
187
|
.sort();
|
|
180
188
|
const db = new D1Mock(":memory:");
|
|
181
189
|
for (const file of files) {
|
|
182
190
|
const migration = await Bun.file(path.join(migrationsPath, file)).text();
|
|
183
|
-
|
|
191
|
+
try {
|
|
192
|
+
await db.exec(migration);
|
|
193
|
+
} catch (error) {
|
|
194
|
+
throw new Error(
|
|
195
|
+
`Failed to execute migration ${file}: ${
|
|
196
|
+
error instanceof Error ? error.message : String(error)
|
|
197
|
+
}`
|
|
198
|
+
);
|
|
199
|
+
}
|
|
184
200
|
}
|
|
185
201
|
return db;
|
|
186
202
|
}
|
package/src/index.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export * from "./d1.ts";
|
|
2
|
-
export * from "./
|
|
2
|
+
export * from "./workers.ts";
|
package/src/workers.ts
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/// <reference types="@cloudflare/workers-types" />
|
|
2
|
+
import { beforeEach, mock, afterAll } from "bun:test";
|
|
3
|
+
|
|
4
|
+
type WorkersModuleMock<TEnv extends Cloudflare.Env = Cloudflare.Env> = {
|
|
5
|
+
env: Partial<TEnv>;
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
let moduleMock: WorkersModuleMock = { env: {} };
|
|
9
|
+
|
|
10
|
+
export async function setupWorkersMock<
|
|
11
|
+
TEnv extends Cloudflare.Env = Cloudflare.Env
|
|
12
|
+
>(createMock?: () => Bun.MaybePromise<WorkersModuleMock<TEnv>>) {
|
|
13
|
+
if (createMock) {
|
|
14
|
+
moduleMock = await createMock();
|
|
15
|
+
}
|
|
16
|
+
mock.module("cloudflare:workers", () => moduleMock);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function useWorkersEnv<TEnv extends Cloudflare.Env = Cloudflare.Env>(
|
|
20
|
+
createEnv: () => Bun.MaybePromise<Partial<TEnv>>
|
|
21
|
+
) {
|
|
22
|
+
beforeEach(async () => {
|
|
23
|
+
const env = await createEnv();
|
|
24
|
+
for (const key in moduleMock.env) {
|
|
25
|
+
delete (moduleMock.env as any)[key];
|
|
26
|
+
}
|
|
27
|
+
Object.assign(moduleMock.env, env);
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
afterAll(() => {
|
|
31
|
+
moduleMock.env = {};
|
|
32
|
+
});
|
|
33
|
+
}
|
package/src/env.ts
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
/// <reference types="@cloudflare/workers-types" />
|
|
2
|
-
import { beforeEach, afterEach, mock } from "bun:test";
|
|
3
|
-
|
|
4
|
-
const MODULE_NAME = "cloudflare:workers";
|
|
5
|
-
|
|
6
|
-
export function useEnv<TEnv extends Cloudflare.Env = Cloudflare.Env>(
|
|
7
|
-
setup: () => Bun.MaybePromise<Partial<TEnv>>
|
|
8
|
-
) {
|
|
9
|
-
beforeEach(async () => {
|
|
10
|
-
const env = await setup();
|
|
11
|
-
mock.module(MODULE_NAME, () => env);
|
|
12
|
-
});
|
|
13
|
-
|
|
14
|
-
afterEach(() => {
|
|
15
|
-
mock.module(MODULE_NAME, () => {});
|
|
16
|
-
});
|
|
17
|
-
}
|