Skip to content

Commit 1d41e15

Browse files
committed
fix: Ensure database initialization before test execution
- Add getDatabaseUrl() helper to safely get database URL - Add ensureDatabase() helper to lazy-initialize database connections - Update all tests to use getDatabaseUrl() instead of process.env.DATABASE_URL! - Fix null reference errors in test setup and teardown
1 parent b958aec commit 1d41e15

3 files changed

Lines changed: 85 additions & 56 deletions

File tree

tests/notification-registry.test.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// tests/notification-registry.test.ts
22
import { describe, test, expect, beforeEach, afterEach } from 'bun:test';
3-
import { prisma, resetNotifications, pgClient } from './setup';
3+
import { prisma, resetNotifications, pgClient, getDatabaseUrl, ensureDatabase } from './setup';
44
import { waitForCondition } from './utils';
55
import { TriggerEvent, Registry, createTriggers } from '../src';
66

@@ -103,7 +103,7 @@ describe('Notification Registry and Unified Subscription', () => {
103103

104104
// Create trigger manager
105105
triggerManager = createTriggers<NonNullable<typeof prisma>>(
106-
process.env.DATABASE_URL!
106+
getDatabaseUrl()
107107
);
108108

109109
// Create a registry with channels for all three models
@@ -326,7 +326,7 @@ describe('Notification Registry and Unified Subscription', () => {
326326

327327
// Create trigger manager
328328
triggerManager = createTriggers<NonNullable<typeof prisma>>(
329-
process.env.DATABASE_URL!
329+
getDatabaseUrl()
330330
);
331331

332332
// Create a simple registry for this test
@@ -415,7 +415,7 @@ describe('Notification Registry and Unified Subscription', () => {
415415
test('should handle custom channels and triggers', async () => {
416416
// Create trigger manager
417417
triggerManager = createTriggers<NonNullable<typeof prisma>>(
418-
process.env.DATABASE_URL!
418+
getDatabaseUrl()
419419
);
420420

421421
// Use a static channel name that matches what Registry expects
@@ -515,7 +515,7 @@ describe('Notification Registry and Unified Subscription', () => {
515515
test('should support defining triggers with custom IDs and listening to specific ones', async () => {
516516
// Create trigger manager
517517
triggerManager = createTriggers<NonNullable<typeof prisma>>(
518-
process.env.DATABASE_URL!
518+
getDatabaseUrl()
519519
);
520520

521521
const channelPrefix = `enhanced_${testId}`;
@@ -665,7 +665,7 @@ describe('Notification Registry and Unified Subscription', () => {
665665
test('registry should provide list of all trigger IDs', async () => {
666666
// Create trigger manager
667667
triggerManager = createTriggers<NonNullable<typeof prisma>>(
668-
process.env.DATABASE_URL!
668+
getDatabaseUrl()
669669
);
670670

671671
// Create registry with multiple triggers

tests/setup.ts

Lines changed: 55 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -23,52 +23,74 @@ export const receivedNotifications: Record<string, any[]> = {
2323
condition_test: []
2424
};
2525

26-
// Use direct database connection for tests
27-
// No pg-testdb required - keep it simple!
28-
beforeAll(async () => {
29-
console.log('Setting up test environment...');
30-
console.log('Environment variables:');
31-
console.log('DATABASE_URL:', process.env.DATABASE_URL);
32-
console.log('TEST_DATABASE_URL:', process.env.TEST_DATABASE_URL);
33-
34-
try {
35-
// Use environment variables for connection or fallback to defaults
36-
const DATABASE_URL =
37-
process.env.TEST_DATABASE_URL || process.env.DATABASE_URL;
38-
39-
if (!DATABASE_URL) {
40-
throw new Error(
41-
'Neither TEST_DATABASE_URL nor DATABASE_URL environment variable is set'
42-
);
43-
}
26+
// Helper to get database URL
27+
export function getDatabaseUrl(): string {
28+
const url = process.env.TEST_DATABASE_URL || process.env.DATABASE_URL;
29+
if (!url) {
30+
throw new Error(
31+
'Neither TEST_DATABASE_URL nor DATABASE_URL environment variable is set'
32+
);
33+
}
34+
return url;
35+
}
4436

45-
console.log('Using database:', DATABASE_URL.replace(/:[^:]+@/, ':****@'));
37+
// Helper to ensure database is initialized
38+
export async function ensureDatabase() {
39+
if (prisma && pgClient && triggers) {
40+
return { prisma, pgClient, triggers };
41+
}
42+
43+
console.log('Initializing database connection...');
44+
const DATABASE_URL = getDatabaseUrl();
4645

47-
// Initialize Prisma client with the same adapter configuration as your app
46+
// Initialize if not already done
47+
if (!prisma) {
4848
prisma = new PrismaClient({
4949
adapter: new PrismaPg({
5050
connectionString: DATABASE_URL
5151
})
5252
});
53+
}
5354

54-
// Initialize postgres.js client
55+
if (!pgClient) {
5556
pgClient = postgres(DATABASE_URL);
57+
}
5658

57-
// Initialize triggers client using new API
59+
if (!triggers) {
5860
triggers = createTriggers<typeof prisma>(DATABASE_URL);
61+
}
62+
63+
return { prisma, pgClient, triggers };
64+
}
65+
66+
// Use direct database connection for tests
67+
// No pg-testdb required - keep it simple!
68+
beforeAll(async () => {
69+
console.log('Setting up test environment...');
70+
console.log('Environment variables:');
71+
console.log('DATABASE_URL:', process.env.DATABASE_URL);
72+
console.log('TEST_DATABASE_URL:', process.env.TEST_DATABASE_URL);
73+
74+
try {
75+
// Ensure database is initialized
76+
await ensureDatabase();
77+
78+
const DATABASE_URL = getDatabaseUrl();
79+
80+
console.log('Using database:', DATABASE_URL.replace(/:[^:]+@/, ':****@'));
5981

6082
// Clean up any existing data for a fresh start
6183
console.log('Cleaning up existing data...');
62-
await prisma.item.deleteMany({});
63-
await prisma.list.deleteMany({});
64-
await prisma.uwU.deleteMany({});
65-
await prisma.user.deleteMany({});
84+
await prisma!.item.deleteMany({});
85+
await prisma!.list.deleteMany({});
86+
await prisma!.uwU.deleteMany({});
87+
await prisma!.user.deleteMany({});
6688

6789
// Create notification functions for each test type
6890
console.log('Creating notification functions...');
6991

7092
// Use the transaction API to create functions
71-
await triggers.transaction(async (tx) => {
93+
await triggers!.transaction(async (tx) => {
7294
// These functions are already created in individual tests,
7395
// but we'll create simple versions here for setup
7496
await tx`
@@ -178,7 +200,7 @@ beforeAll(async () => {
178200

179201
// Check what tables actually exist in the database
180202
console.log('Checking existing tables...');
181-
const tablesResult = await pgClient.unsafe(`
203+
const tablesResult = await pgClient!.unsafe(`
182204
SELECT table_name
183205
FROM information_schema.tables
184206
WHERE table_schema = 'public'
@@ -212,10 +234,10 @@ afterAll(async () => {
212234

213235
// Clean up any test data
214236
if (prisma) {
215-
await prisma.item.deleteMany({});
216-
await prisma.list.deleteMany({});
217-
await prisma.uwU.deleteMany({});
218-
await prisma.user.deleteMany({});
237+
await prisma!.item.deleteMany({});
238+
await prisma!.list.deleteMany({});
239+
await prisma!.uwU.deleteMany({});
240+
await prisma!.user.deleteMany({});
219241
}
220242

221243
// Dispose triggers
@@ -224,7 +246,7 @@ afterAll(async () => {
224246
}
225247

226248
// Close connections
227-
// if (prisma) await prisma.$disconnect();
249+
// if (prisma) await prisma!.$disconnect();
228250
// if (pgClient) await pgClient.end();
229251

230252
console.log('Test cleanup complete');

tests/triggers.test.ts

Lines changed: 24 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@ import {
55
triggers,
66
receivedNotifications,
77
resetNotifications,
8-
pgClient
8+
pgClient,
9+
ensureDatabase,
10+
getDatabaseUrl
911
} from './setup';
1012
import { waitForNotifications, assertNotificationPayload } from './utils';
1113
import { createTriggers, TriggerManager, TriggerHandle } from '../src';
@@ -21,25 +23,28 @@ describe('CRUD Triggers', () => {
2123
beforeEach(async () => {
2224
resetNotifications();
2325

26+
// Ensure database is initialized
27+
const { prisma: db } = await ensureDatabase();
28+
2429
// Create a test user first with unique email
2530
const uniqueEmail = `test-${Date.now()}-${Math.random().toString(36).substring(2, 11)}@example.com`;
26-
testUser = await prisma!.user.create({
31+
testUser = await db.user.create({
2732
data: {
2833
email: uniqueEmail,
2934
name: 'Test User'
3035
}
3136
});
3237

3338
// Create a test list
34-
testList = await prisma!.list.create({
39+
testList = await db.list.create({
3540
data: {
3641
name: 'Test List',
3742
ownerId: testUser.id
3843
}
3944
});
4045

4146
// Create a test item for update/delete operations
42-
testItem = await prisma!.item.create({
47+
testItem = await db.item.create({
4348
data: {
4449
name: 'Test Item for CRUD',
4550
status: 'PENDING',
@@ -71,15 +76,17 @@ describe('CRUD Triggers', () => {
7176
}
7277

7378
// Clear any remaining test data
74-
await prisma!.item.deleteMany({});
75-
await prisma!.list.deleteMany({});
79+
const { prisma: db } = await ensureDatabase();
80+
await db.item.deleteMany({});
81+
await db.list.deleteMany({});
7682
});
7783

7884
describe('INSERT Triggers', () => {
7985
test('basic INSERT trigger should fire on item creation', async () => {
8086
// Create a FRESH TriggerManager for this test to avoid condition bleeding
87+
await ensureDatabase();
8188
currentTriggerManager = createTriggers<NonNullable<typeof prisma>>(
82-
process.env.DATABASE_URL!
89+
getDatabaseUrl()
8390
);
8491

8592
// Create function first
@@ -136,7 +143,7 @@ describe('CRUD Triggers', () => {
136143
test('conditional INSERT trigger should only fire when condition is met', async () => {
137144
// Create a FRESH TriggerManager for this test
138145
currentTriggerManager = createTriggers<NonNullable<typeof prisma>>(
139-
process.env.DATABASE_URL!
146+
getDatabaseUrl()
140147
);
141148

142149
// Create function first
@@ -207,7 +214,7 @@ describe('CRUD Triggers', () => {
207214
test('INSERT trigger using raw SQL condition should work', async () => {
208215
// Create a FRESH TriggerManager for this test
209216
currentTriggerManager = createTriggers<NonNullable<typeof prisma>>(
210-
process.env.DATABASE_URL!
217+
getDatabaseUrl()
211218
);
212219

213220
// Create function first
@@ -280,7 +287,7 @@ describe('CRUD Triggers', () => {
280287
test('basic UPDATE trigger should fire on any item update', async () => {
281288
// Create a FRESH TriggerManager for this test
282289
currentTriggerManager = createTriggers<NonNullable<typeof prisma>>(
283-
process.env.DATABASE_URL!
290+
getDatabaseUrl()
284291
);
285292

286293
// Create function first
@@ -337,7 +344,7 @@ describe('CRUD Triggers', () => {
337344
test('UPDATE trigger should only fire when watched column changes', async () => {
338345
// Create a FRESH TriggerManager for this test
339346
currentTriggerManager = createTriggers<NonNullable<typeof prisma>>(
340-
process.env.DATABASE_URL!
347+
getDatabaseUrl()
341348
);
342349

343350
// Create function first
@@ -402,7 +409,7 @@ describe('CRUD Triggers', () => {
402409
test('conditional UPDATE trigger should only fire when condition is met', async () => {
403410
// Create a FRESH TriggerManager for this test
404411
currentTriggerManager = createTriggers<NonNullable<typeof prisma>>(
405-
process.env.DATABASE_URL!
412+
getDatabaseUrl()
406413
);
407414

408415
// Create function first
@@ -466,7 +473,7 @@ describe('CRUD Triggers', () => {
466473
test('UPDATE trigger with field comparison condition should work', async () => {
467474
// Create a FRESH TriggerManager for this test
468475
currentTriggerManager = createTriggers<NonNullable<typeof prisma>>(
469-
process.env.DATABASE_URL!
476+
getDatabaseUrl()
470477
);
471478

472479
// Create function first
@@ -533,7 +540,7 @@ describe('CRUD Triggers', () => {
533540
test('basic DELETE trigger should fire on item deletion', async () => {
534541
// Create a FRESH TriggerManager for this test
535542
currentTriggerManager = createTriggers<NonNullable<typeof prisma>>(
536-
process.env.DATABASE_URL!
543+
getDatabaseUrl()
537544
);
538545

539546
// Create function first
@@ -595,7 +602,7 @@ describe('CRUD Triggers', () => {
595602

596603
// Create a FRESH TriggerManager for this test
597604
currentTriggerManager = createTriggers<NonNullable<typeof prisma>>(
598-
process.env.DATABASE_URL!
605+
getDatabaseUrl()
599606
);
600607

601608
// Create function first
@@ -667,7 +674,7 @@ describe('CRUD Triggers', () => {
667674

668675
// Create a FRESH TriggerManager for this test
669676
currentTriggerManager = createTriggers<NonNullable<typeof prisma>>(
670-
process.env.DATABASE_URL!
677+
getDatabaseUrl()
671678
);
672679

673680
// Create function first
@@ -731,7 +738,7 @@ describe('CRUD Triggers', () => {
731738
test('trigger with multiple events should work for all operations', async () => {
732739
// Create a FRESH TriggerManager for this test
733740
currentTriggerManager = createTriggers<NonNullable<typeof prisma>>(
734-
process.env.DATABASE_URL!
741+
getDatabaseUrl()
735742
);
736743

737744
// Create function first

0 commit comments

Comments
 (0)