- Add test fixture with seededDb for predictable test data - Include 5 entries: tasks and thoughts with various states - Include 3 tags with entry-tag relationships - Export extended test with fixtures from tests/e2e/index.ts - Install drizzle-seed dependency
175 lines
4.4 KiB
TypeScript
175 lines
4.4 KiB
TypeScript
/**
|
|
* Database seeding fixture for E2E tests
|
|
*
|
|
* Uses direct SQL for cleanup and drizzle for typed inserts.
|
|
* Each test gets a known starting state that can be asserted against.
|
|
*
|
|
* Note: drizzle-seed is installed but we use manual cleanup for better control
|
|
* and to avoid type compatibility issues with reset().
|
|
*/
|
|
import { test as base } from '@playwright/test';
|
|
import Database from 'better-sqlite3';
|
|
import { drizzle } from 'drizzle-orm/better-sqlite3';
|
|
import * as schema from '../../../src/lib/server/db/schema';
|
|
|
|
// Test database path - same as application for E2E tests
|
|
const DATA_DIR = process.env.DATA_DIR || './data';
|
|
const DB_PATH = `${DATA_DIR}/taskplaner.db`;
|
|
|
|
// Known test data with predictable IDs for assertions
|
|
export const testData = {
|
|
entries: [
|
|
{
|
|
id: 'test-entry-001',
|
|
title: null,
|
|
content: 'Buy groceries for the week',
|
|
type: 'task' as const,
|
|
status: 'open' as const,
|
|
pinned: false,
|
|
dueDate: '2026-02-10',
|
|
createdAt: '2026-02-01T10:00:00.000Z',
|
|
updatedAt: '2026-02-01T10:00:00.000Z'
|
|
},
|
|
{
|
|
id: 'test-entry-002',
|
|
title: null,
|
|
content: 'Completed task from yesterday',
|
|
type: 'task' as const,
|
|
status: 'done' as const,
|
|
pinned: false,
|
|
dueDate: null,
|
|
createdAt: '2026-02-02T09:00:00.000Z',
|
|
updatedAt: '2026-02-02T15:00:00.000Z'
|
|
},
|
|
{
|
|
id: 'test-entry-003',
|
|
title: null,
|
|
content: 'Important pinned thought about project architecture',
|
|
type: 'thought' as const,
|
|
status: null,
|
|
pinned: true,
|
|
dueDate: null,
|
|
createdAt: '2026-02-01T08:00:00.000Z',
|
|
updatedAt: '2026-02-01T08:00:00.000Z'
|
|
},
|
|
{
|
|
id: 'test-entry-004',
|
|
title: null,
|
|
content: 'Meeting notes with stakeholders',
|
|
type: 'thought' as const,
|
|
status: null,
|
|
pinned: false,
|
|
dueDate: null,
|
|
createdAt: '2026-02-03T14:00:00.000Z',
|
|
updatedAt: '2026-02-03T14:00:00.000Z'
|
|
},
|
|
{
|
|
id: 'test-entry-005',
|
|
title: null,
|
|
content: 'Review pull request for feature branch',
|
|
type: 'task' as const,
|
|
status: 'open' as const,
|
|
pinned: false,
|
|
dueDate: '2026-02-05',
|
|
createdAt: '2026-02-03T11:00:00.000Z',
|
|
updatedAt: '2026-02-03T11:00:00.000Z'
|
|
}
|
|
],
|
|
tags: [
|
|
{
|
|
id: 'test-tag-001',
|
|
name: 'work',
|
|
createdAt: '2026-02-01T00:00:00.000Z'
|
|
},
|
|
{
|
|
id: 'test-tag-002',
|
|
name: 'personal',
|
|
createdAt: '2026-02-01T00:00:00.000Z'
|
|
},
|
|
{
|
|
id: 'test-tag-003',
|
|
name: 'urgent',
|
|
createdAt: '2026-02-01T00:00:00.000Z'
|
|
}
|
|
],
|
|
entryTags: [
|
|
{ entryId: 'test-entry-001', tagId: 'test-tag-002' }, // groceries -> personal
|
|
{ entryId: 'test-entry-003', tagId: 'test-tag-001' }, // architecture -> work
|
|
{ entryId: 'test-entry-004', tagId: 'test-tag-001' }, // meeting notes -> work
|
|
{ entryId: 'test-entry-005', tagId: 'test-tag-001' }, // PR review -> work
|
|
{ entryId: 'test-entry-005', tagId: 'test-tag-003' } // PR review -> urgent
|
|
]
|
|
};
|
|
|
|
/**
|
|
* Clear all data from the database (respecting foreign key order)
|
|
*/
|
|
function clearDatabase(sqlite: Database.Database) {
|
|
// Delete in order that respects foreign key constraints
|
|
sqlite.exec('DELETE FROM entry_tags');
|
|
sqlite.exec('DELETE FROM images');
|
|
sqlite.exec('DELETE FROM tags');
|
|
sqlite.exec('DELETE FROM entries');
|
|
}
|
|
|
|
/**
|
|
* Seed the database with known test data
|
|
*/
|
|
async function seedDatabase() {
|
|
const sqlite = new Database(DB_PATH);
|
|
sqlite.pragma('journal_mode = WAL');
|
|
const db = drizzle(sqlite, { schema });
|
|
|
|
// Clear existing data
|
|
clearDatabase(sqlite);
|
|
|
|
// Insert test entries
|
|
for (const entry of testData.entries) {
|
|
db.insert(schema.entries).values(entry).run();
|
|
}
|
|
|
|
// Insert test tags
|
|
for (const tag of testData.tags) {
|
|
db.insert(schema.tags).values(tag).run();
|
|
}
|
|
|
|
// Insert entry-tag relationships
|
|
for (const entryTag of testData.entryTags) {
|
|
db.insert(schema.entryTags).values(entryTag).run();
|
|
}
|
|
|
|
sqlite.close();
|
|
}
|
|
|
|
/**
|
|
* Clean up test data after tests
|
|
*/
|
|
async function cleanupDatabase() {
|
|
const sqlite = new Database(DB_PATH);
|
|
sqlite.pragma('journal_mode = WAL');
|
|
|
|
// Clear all test data
|
|
clearDatabase(sqlite);
|
|
|
|
sqlite.close();
|
|
}
|
|
|
|
// Export fixture type for TypeScript
|
|
export type SeededDbFixture = {
|
|
testData: typeof testData;
|
|
};
|
|
|
|
// Extend Playwright test with seeded database fixture
|
|
export const test = base.extend<{ seededDb: SeededDbFixture }>({
|
|
seededDb: async ({}, use) => {
|
|
// Setup: seed database before test
|
|
await seedDatabase();
|
|
|
|
// Provide test data for assertions
|
|
await use({ testData });
|
|
|
|
// Teardown: clean up after test
|
|
await cleanupDatabase();
|
|
}
|
|
});
|