From dd32a3dd1162ad2261913c9cde95ca037f26c874 Mon Sep 17 00:00:00 2001 From: "borja (aider)" Date: Mon, 5 May 2025 14:52:38 +0200 Subject: [PATCH] test: use in-memory database for tests --- src/db.ts | 13 +++++++-- tests/unit/db.test.ts | 65 ++++++++++++++++++++++++++----------------- 2 files changed, 50 insertions(+), 28 deletions(-) diff --git a/src/db.ts b/src/db.ts index c1c0482..c68f197 100644 --- a/src/db.ts +++ b/src/db.ts @@ -1,9 +1,16 @@ import { Database } from 'bun:sqlite'; -export const db = new Database('tasks.db'); +// Function to get a database instance. Defaults to 'tasks.db' +export function getDb(filename: string = 'tasks.db'): Database { + return new Database(filename); +} + +// Default export for the main application database +export const db = getDb(); -export function initializeDatabase() { - db.exec(` +// Initialize function now accepts a database instance +export function initializeDatabase(instance: Database) { + instance.exec(` CREATE TABLE IF NOT EXISTS tasks ( id INTEGER PRIMARY KEY AUTOINCREMENT, description TEXT NOT NULL, diff --git a/tests/unit/db.test.ts b/tests/unit/db.test.ts index 27d17f9..39179d2 100644 --- a/tests/unit/db.test.ts +++ b/tests/unit/db.test.ts @@ -1,19 +1,33 @@ -import { db, initializeDatabase } from '../../src/db'; -import { describe, test, expect, beforeEach } from 'bun:test'; +import { Database } from 'bun:sqlite'; +import { initializeDatabase } from '../../src/db'; +import { describe, test, expect, beforeEach, afterAll, beforeAll } from 'bun:test'; describe('Database', () => { + let testDb: Database; + + // Create an in-memory database before any tests run + beforeAll(() => { + testDb = new Database(':memory:'); + }); + + // Close the database connection after all tests have run + afterAll(() => { + testDb.close(); + }); + beforeEach(() => { - // Reset database between tests - db.exec('DROP TABLE IF EXISTS tasks'); - db.exec('DROP TABLE IF EXISTS task_assignments'); - db.exec('DROP TABLE IF EXISTS users'); - db.exec('DROP TABLE IF EXISTS groups'); - initializeDatabase(); + // Reset database schema between tests by dropping tables and re-initializing + testDb.exec('DROP TABLE IF EXISTS tasks'); + testDb.exec('DROP TABLE IF EXISTS task_assignments'); + testDb.exec('DROP TABLE IF EXISTS users'); + testDb.exec('DROP TABLE IF EXISTS groups'); + // Initialize schema on the test database instance + initializeDatabase(testDb); }); describe('Table Creation', () => { test('should create all required tables', () => { - const tables = db + const tables = testDb .query("SELECT name FROM sqlite_master WHERE type='table'") .all() .map((t: any) => t.name); @@ -26,7 +40,7 @@ describe('Database', () => { describe('Table Schemas', () => { test('users table should have correct columns', () => { - const columns = db + const columns = testDb .query("PRAGMA table_info(users)") .all() .map((c: any) => c.name); @@ -34,7 +48,7 @@ describe('Database', () => { }); test('tasks table should have required columns', () => { - const columns = db + const columns = testDb .query("PRAGMA table_info(tasks)") .all() .map((c: any) => c.name); @@ -45,18 +59,18 @@ describe('Database', () => { }); test('groups table should have active flag default to true', () => { - db.exec(` + testDb.exec(` INSERT INTO groups (id, community_id, name) VALUES ('test-group', 'test-community', 'Test Group') `); - const group = db.query("SELECT active FROM groups WHERE id = 'test-group'").get(); - expect(group.active).toBe(1); + const group = testDb.query("SELECT active FROM groups WHERE id = 'test-group'").get(); + expect(group.active).toBe(1); // SQLite uses 1 for TRUE }); }); describe('Foreign Keys', () => { test('task_assignments should reference tasks', () => { - const fkInfo = db + const fkInfo = testDb .query("PRAGMA foreign_key_list(task_assignments)") .all(); expect(fkInfo.length).toBe(1); @@ -66,7 +80,7 @@ describe('Database', () => { }); test('tasks should reference users via created_by', () => { - const fkInfo = db + const fkInfo = testDb .query("PRAGMA foreign_key_list(tasks)") .all(); expect(fkInfo.length).toBe(1); @@ -79,29 +93,30 @@ describe('Database', () => { describe('User Operations', () => { test('should reject duplicate user IDs', () => { // First insert should succeed - const firstInsert = db.prepare(` + const firstInsert = testDb.prepare(` INSERT INTO users (id) VALUES ('34650112233') `).run(); expect(firstInsert.changes).toBe(1); - // Second insert with same ID should fail + // Second insert with same ID should fail due to PRIMARY KEY constraint expect(() => { - db.prepare(` + testDb.prepare(` INSERT INTO users (id) VALUES ('34650112233') `).run(); - }).toThrow(); + }).toThrow(); // Bun's SQLite driver throws an error on constraint violation // Verify only one record exists - const count = db.prepare(` + const countResult = testDb.prepare(` SELECT COUNT(*) as count FROM users WHERE id = '34650112233' `).get(); - expect(count.count).toBe(1); + expect(countResult.count).toBe(1); }); }); describe('Data Operations', () => { beforeEach(() => { - db.exec(` + // Seed necessary data for these tests into the test database + testDb.exec(` INSERT INTO users (id) VALUES ('34650112233'); INSERT INTO groups (id, community_id, name) VALUES ('test-group', 'test-community', 'Test Group') @@ -109,7 +124,7 @@ describe('Database', () => { }); test('should allow inserting group tasks', () => { - const result = db.prepare(` + const result = testDb.prepare(` INSERT INTO tasks (description, created_by, group_id) VALUES ('Test task', '34650112233', 'test-group') `).run(); @@ -117,7 +132,7 @@ describe('Database', () => { }); test('should allow inserting private tasks', () => { - const result = db.prepare(` + const result = testDb.prepare(` INSERT INTO tasks (description, created_by) VALUES ('Private task', '34650112233') `).run();