Cloudflare D1 を bun:sqlite
で代用することで、 wrangler を使わずに bun test
でテストが書けるようにした。ORM も使っていないような簡単なアプリ向け。
まず、 bun:sqlite
をオンメモリで作成して、必要なテーブルを用意しつつ D1 互換のインターフェイスを返すモックを作れるようにする。
import { Database } from 'bun:sqlite';
export function createMockD1Database() {
const db = new Database(':memory:');
db.exec('BEGIN');
db.exec(`
CREATE TABLE ...
`);
db.exec('COMMIT');
return {
prepare: (query: string) => {
const stmt = db.prepare(query);
return {
bind: (...params: any[]) => ({
all: async () => {
try {
const results = stmt.all(...params);
return {
results,
success: true,
meta: {},
};
} catch (error: any) {
return {
results: [],
success: false,
meta: { error: error.message },
};
}
},
first: async () => {
try {
return stmt.get(...params) || null;
} catch (error) {
return null;
}
},
run: async () => {
try {
stmt.run(...params);
return {
success: true,
meta: {
changes: db.changes,
last_row_id: db.lastInsertRowid,
},
};
} catch (error: any) {
return {
success: false,
meta: { error: error.message },
};
}
},
}),
};
},
batch: async (statements: any[]) => {
const results = [];
for (const statement of statements) {
const result = await statement.run();
results.push(result);
}
return results;
},
exec: (sql: string) => {
return db.exec(sql);
},
};
}
このモックを Hono の testClient
で DB
として渡すことで、 D1 の代わりにモックが使用され、 他のツールなしに bun test
でテストが書ける。
describe('Tests', () => {
let client: TestClient;
let mockDB: ReturnType<typeof createMockD1Database>;
beforeEach(() => {
mockDB = createMockD1Database();
client = testClient(app, {
DB: mockDB,
});
});
test('api', async () => {
const res = await client.api.items.$get();
expect(res.status).toBe(200);
const items = await res.json();
expect(Array.isArray(items)).toBe(true);
expect(items).toHaveLength(0);
});
})
事前にテストデータなんかがほしいときは普通に mockDB.exec
を使って入れたりしている。