|
|
@ -1,19 +1,33 @@
|
|
|
|
import { db, initializeDatabase } from '../../src/db';
|
|
|
|
import { Database } from 'bun:sqlite';
|
|
|
|
import { describe, test, expect, beforeEach } from 'bun:test';
|
|
|
|
import { initializeDatabase } from '../../src/db';
|
|
|
|
|
|
|
|
import { describe, test, expect, beforeEach, afterAll, beforeAll } from 'bun:test';
|
|
|
|
|
|
|
|
|
|
|
|
describe('Database', () => {
|
|
|
|
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(() => {
|
|
|
|
beforeEach(() => {
|
|
|
|
// Reset database between tests
|
|
|
|
// Reset database schema between tests by dropping tables and re-initializing
|
|
|
|
db.exec('DROP TABLE IF EXISTS tasks');
|
|
|
|
testDb.exec('DROP TABLE IF EXISTS tasks');
|
|
|
|
db.exec('DROP TABLE IF EXISTS task_assignments');
|
|
|
|
testDb.exec('DROP TABLE IF EXISTS task_assignments');
|
|
|
|
db.exec('DROP TABLE IF EXISTS users');
|
|
|
|
testDb.exec('DROP TABLE IF EXISTS users');
|
|
|
|
db.exec('DROP TABLE IF EXISTS groups');
|
|
|
|
testDb.exec('DROP TABLE IF EXISTS groups');
|
|
|
|
initializeDatabase();
|
|
|
|
// Initialize schema on the test database instance
|
|
|
|
|
|
|
|
initializeDatabase(testDb);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
describe('Table Creation', () => {
|
|
|
|
describe('Table Creation', () => {
|
|
|
|
test('should create all required tables', () => {
|
|
|
|
test('should create all required tables', () => {
|
|
|
|
const tables = db
|
|
|
|
const tables = testDb
|
|
|
|
.query("SELECT name FROM sqlite_master WHERE type='table'")
|
|
|
|
.query("SELECT name FROM sqlite_master WHERE type='table'")
|
|
|
|
.all()
|
|
|
|
.all()
|
|
|
|
.map((t: any) => t.name);
|
|
|
|
.map((t: any) => t.name);
|
|
|
@ -26,7 +40,7 @@ describe('Database', () => {
|
|
|
|
|
|
|
|
|
|
|
|
describe('Table Schemas', () => {
|
|
|
|
describe('Table Schemas', () => {
|
|
|
|
test('users table should have correct columns', () => {
|
|
|
|
test('users table should have correct columns', () => {
|
|
|
|
const columns = db
|
|
|
|
const columns = testDb
|
|
|
|
.query("PRAGMA table_info(users)")
|
|
|
|
.query("PRAGMA table_info(users)")
|
|
|
|
.all()
|
|
|
|
.all()
|
|
|
|
.map((c: any) => c.name);
|
|
|
|
.map((c: any) => c.name);
|
|
|
@ -34,7 +48,7 @@ describe('Database', () => {
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
test('tasks table should have required columns', () => {
|
|
|
|
test('tasks table should have required columns', () => {
|
|
|
|
const columns = db
|
|
|
|
const columns = testDb
|
|
|
|
.query("PRAGMA table_info(tasks)")
|
|
|
|
.query("PRAGMA table_info(tasks)")
|
|
|
|
.all()
|
|
|
|
.all()
|
|
|
|
.map((c: any) => c.name);
|
|
|
|
.map((c: any) => c.name);
|
|
|
@ -45,18 +59,18 @@ describe('Database', () => {
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
test('groups table should have active flag default to true', () => {
|
|
|
|
test('groups table should have active flag default to true', () => {
|
|
|
|
db.exec(`
|
|
|
|
testDb.exec(`
|
|
|
|
INSERT INTO groups (id, community_id, name)
|
|
|
|
INSERT INTO groups (id, community_id, name)
|
|
|
|
VALUES ('test-group', 'test-community', 'Test Group')
|
|
|
|
VALUES ('test-group', 'test-community', 'Test Group')
|
|
|
|
`);
|
|
|
|
`);
|
|
|
|
const group = db.query("SELECT active FROM groups WHERE id = 'test-group'").get();
|
|
|
|
const group = testDb.query("SELECT active FROM groups WHERE id = 'test-group'").get();
|
|
|
|
expect(group.active).toBe(1);
|
|
|
|
expect(group.active).toBe(1); // SQLite uses 1 for TRUE
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
describe('Foreign Keys', () => {
|
|
|
|
describe('Foreign Keys', () => {
|
|
|
|
test('task_assignments should reference tasks', () => {
|
|
|
|
test('task_assignments should reference tasks', () => {
|
|
|
|
const fkInfo = db
|
|
|
|
const fkInfo = testDb
|
|
|
|
.query("PRAGMA foreign_key_list(task_assignments)")
|
|
|
|
.query("PRAGMA foreign_key_list(task_assignments)")
|
|
|
|
.all();
|
|
|
|
.all();
|
|
|
|
expect(fkInfo.length).toBe(1);
|
|
|
|
expect(fkInfo.length).toBe(1);
|
|
|
@ -66,7 +80,7 @@ describe('Database', () => {
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
test('tasks should reference users via created_by', () => {
|
|
|
|
test('tasks should reference users via created_by', () => {
|
|
|
|
const fkInfo = db
|
|
|
|
const fkInfo = testDb
|
|
|
|
.query("PRAGMA foreign_key_list(tasks)")
|
|
|
|
.query("PRAGMA foreign_key_list(tasks)")
|
|
|
|
.all();
|
|
|
|
.all();
|
|
|
|
expect(fkInfo.length).toBe(1);
|
|
|
|
expect(fkInfo.length).toBe(1);
|
|
|
@ -79,29 +93,30 @@ describe('Database', () => {
|
|
|
|
describe('User Operations', () => {
|
|
|
|
describe('User Operations', () => {
|
|
|
|
test('should reject duplicate user IDs', () => {
|
|
|
|
test('should reject duplicate user IDs', () => {
|
|
|
|
// First insert should succeed
|
|
|
|
// First insert should succeed
|
|
|
|
const firstInsert = db.prepare(`
|
|
|
|
const firstInsert = testDb.prepare(`
|
|
|
|
INSERT INTO users (id) VALUES ('34650112233')
|
|
|
|
INSERT INTO users (id) VALUES ('34650112233')
|
|
|
|
`).run();
|
|
|
|
`).run();
|
|
|
|
expect(firstInsert.changes).toBe(1);
|
|
|
|
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(() => {
|
|
|
|
expect(() => {
|
|
|
|
db.prepare(`
|
|
|
|
testDb.prepare(`
|
|
|
|
INSERT INTO users (id) VALUES ('34650112233')
|
|
|
|
INSERT INTO users (id) VALUES ('34650112233')
|
|
|
|
`).run();
|
|
|
|
`).run();
|
|
|
|
}).toThrow();
|
|
|
|
}).toThrow(); // Bun's SQLite driver throws an error on constraint violation
|
|
|
|
|
|
|
|
|
|
|
|
// Verify only one record exists
|
|
|
|
// Verify only one record exists
|
|
|
|
const count = db.prepare(`
|
|
|
|
const countResult = testDb.prepare(`
|
|
|
|
SELECT COUNT(*) as count FROM users WHERE id = '34650112233'
|
|
|
|
SELECT COUNT(*) as count FROM users WHERE id = '34650112233'
|
|
|
|
`).get();
|
|
|
|
`).get();
|
|
|
|
expect(count.count).toBe(1);
|
|
|
|
expect(countResult.count).toBe(1);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
describe('Data Operations', () => {
|
|
|
|
describe('Data Operations', () => {
|
|
|
|
beforeEach(() => {
|
|
|
|
beforeEach(() => {
|
|
|
|
db.exec(`
|
|
|
|
// Seed necessary data for these tests into the test database
|
|
|
|
|
|
|
|
testDb.exec(`
|
|
|
|
INSERT INTO users (id) VALUES ('34650112233');
|
|
|
|
INSERT INTO users (id) VALUES ('34650112233');
|
|
|
|
INSERT INTO groups (id, community_id, name)
|
|
|
|
INSERT INTO groups (id, community_id, name)
|
|
|
|
VALUES ('test-group', 'test-community', 'Test Group')
|
|
|
|
VALUES ('test-group', 'test-community', 'Test Group')
|
|
|
@ -109,7 +124,7 @@ describe('Database', () => {
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
test('should allow inserting group tasks', () => {
|
|
|
|
test('should allow inserting group tasks', () => {
|
|
|
|
const result = db.prepare(`
|
|
|
|
const result = testDb.prepare(`
|
|
|
|
INSERT INTO tasks (description, created_by, group_id)
|
|
|
|
INSERT INTO tasks (description, created_by, group_id)
|
|
|
|
VALUES ('Test task', '34650112233', 'test-group')
|
|
|
|
VALUES ('Test task', '34650112233', 'test-group')
|
|
|
|
`).run();
|
|
|
|
`).run();
|
|
|
@ -117,7 +132,7 @@ describe('Database', () => {
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
test('should allow inserting private tasks', () => {
|
|
|
|
test('should allow inserting private tasks', () => {
|
|
|
|
const result = db.prepare(`
|
|
|
|
const result = testDb.prepare(`
|
|
|
|
INSERT INTO tasks (description, created_by)
|
|
|
|
INSERT INTO tasks (description, created_by)
|
|
|
|
VALUES ('Private task', '34650112233')
|
|
|
|
VALUES ('Private task', '34650112233')
|
|
|
|
`).run();
|
|
|
|
`).run();
|
|
|
|