Testing
Test your Models and Worker against a real D1 database, with your migrations applied. Miniflare runs Cloudflare’s runtime, D1 included, inside Node:
sh
npm install --save-dev vitest miniflare@4Creating a test database
Start Miniflare with a D1 database, and apply your migrations to it, in order:
ts
import { readdirSync, readFileSync } from "node:fs";
import { Miniflare } from "miniflare";
export async function testDatabase() {
const mf = new Miniflare({ modules: true, script: "export default {}", d1Databases: ["DB"] });
const binding = await mf.getD1Database("DB");
for (const file of readdirSync("migrations").sort()) {
// Each migration's statements, without its comments, applied together.
const statements = readFileSync(`migrations/${file}`, "utf8")
.replace(/^\s*--.*$/gm, "")
.split(/;\s*$/m)
.map((statement) => statement.trim())
.filter(Boolean);
if (statements.length > 0)
await binding.batch(statements.map((statement) => binding.prepare(statement)));
}
return { binding, dispose: () => mf.dispose() };
}Testing Models
Outside a Worker there’s no binding, so run the test’s code inside withDatabase:
ts
import { connect, withDatabase } from "@forestfuture/d1-record";
import { afterAll, beforeAll, expect, test } from "vitest";
import { User } from "../src/models/user";
import { testDatabase } from "./d1";
let database: Awaited<ReturnType<typeof testDatabase>>;
beforeAll(async () => (database = await testDatabase()));
afterAll(() => database.dispose());
test("emails are saved in lowercase", async () => {
await withDatabase(connect(database.binding), async () => {
const user = await User.create({ email: "Ada@Example.com" });
expect((await User.find(user.id)).email).toBe("ada@example.com");
});
});Outside a Worker, the database given to withDatabase serves every Model, whatever binding its base class names. For code that takes a database explicitly, pass it one: connect(database.binding).model(User).
Testing your Worker
Call your Worker’s fetch handler inside withDatabase too, and its queries use the test’s database:
ts
import { connect, withDatabase } from "@forestfuture/d1-record";
import { afterAll, beforeAll, expect, test } from "vitest";
import worker from "../src/index";
import { testDatabase } from "./d1";
let database: Awaited<ReturnType<typeof testDatabase>>;
beforeAll(async () => (database = await testDatabase()));
afterAll(() => database.dispose());
test("GET lists users", async () => {
const response = await withDatabase(connect(database.binding), () =>
worker.fetch(new Request("https://example.com/")),
);
expect(response.status).toBe(200);
});Each test file gets its own database.
TIP
To run tests inside the Workers runtime itself, use Cloudflare’s Vitest integration.