feat(09-03): create database seeding fixture for E2E tests
- 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
This commit is contained in:
174
tests/e2e/fixtures/db.ts
Normal file
174
tests/e2e/fixtures/db.ts
Normal file
@@ -0,0 +1,174 @@
|
||||
/**
|
||||
* 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();
|
||||
}
|
||||
});
|
||||
7
tests/e2e/index.ts
Normal file
7
tests/e2e/index.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
/**
|
||||
* E2E test exports with database fixtures
|
||||
*
|
||||
* Import { test, expect } from this file to get tests with seeded database.
|
||||
*/
|
||||
export { test, testData } from './fixtures/db';
|
||||
export { expect } from '@playwright/test';
|
||||
Reference in New Issue
Block a user