Add db seed and integration, update scripts in package.json
CI/CD Pipeline / test (push) Successful in 1m41s
CI/CD Pipeline / deploy-internal (push) Successful in 52s

This commit is contained in:
chris committed 2026-08-28 21:10:27 -04:00
1 parent d505320c50
commit 45ca4de0ad
4 files changed
+112 -1

No files matched your search

+1 -1
View File
@@ -4,7 +4,7 @@
"description": "",
"main": "index.js",
"scripts": {
"test": "tsx run-tests.ts",
"test": "node --import tsx --test \"src/**/*.test.ts\"",
"db:migrate": "dotenv dbmate up"
},
"keywords": [],
+65
View File
@@ -0,0 +1,65 @@
import { describe, it, before, after } from 'node:test';
import assert from 'node:assert/strict';
import { Pool } from 'pg';
import { CategoryRepository } from './category.repository.ts';
import { seedCategoryTable, clearCategoryTable } from './test-seed.ts';
import { join } from 'node:path';
import process from 'node:process';
// load the local .env file
try {
process.loadEnvFile(join(process.cwd(), '.env'));
} catch (e) {
console.warn('⚠️ Warning: No local .env file found. Falling back to default system environment tokens.');
}
const pool = new Pool({
connectionString: process.env.DATABASE_URL || process.env.INTERNAL_PROD_DB_URL
});
describe('CategoryRepository - Live Database Integration Tests', () => {
const repository = new CategoryRepository(pool);
// Setup: Seed the database before executing integration items
before(async () => {
await seedCategoryTable(pool);
});
// Teardown: Clean out the database after tests wrap up
after(async () => {
await clearCategoryTable(pool);
await pool.end();
});
it('should fetch all deep descendants using the <@ ltree operator', async () => {
const results = await repository.findAllDescendants('Top.Science');
// Should return Science, Astronomy, and Astrophysics (3 nodes)
assert.equal(results.length, 3);
assert.equal(results[0].name, 'Science');
assert.equal(results[1].name, 'Astronomy');
assert.equal(results[2].name, 'Astrophysics');
});
it('should isolate only immediate structural child links via findDirectChildren()', async () => {
const results = await repository.findDirectChildren('Top');
// Top has two immediate children: Science and Hobbies
assert.equal(results.length, 2);
const names = results.map(r => r.name);
assert.ok(names.includes('Science'));
assert.ok(names.includes('Hobbies'));
assert.ok(!names.includes('Astronomy')); // Deeper descendant, should be skipped
});
it('should resolve breadcrumb history using the @> ltree operator', async () => {
const results = await repository.findAncestors('Top.Science.Astronomy');
// Should trace: Root (Top) -> Science -> Astronomy
assert.equal(results.length, 3);
assert.equal(results[0].path, 'Top');
assert.equal(results[1].path, 'Top.Science');
assert.equal(results[2].path, 'Top.Science.Astronomy');
});
});
+19
View File
@@ -0,0 +1,19 @@
import { Pool } from 'pg';
import { seedCategoryTable } from './test-seed.ts';
import 'dotenv/config'; // Requires npm install dotenv if you want to parse local .env assets
const pool = new Pool({ connectionString: process.env.DATABASE_URL });
async function run() {
console.log('🌱 Seeding target database connection schema...');
try {
await seedCategoryTable(pool);
console.log('✅ Database hierarchy seed operations completed successfully.');
} catch (error) {
console.error('❌ Database seed operations failed:', error);
} finally {
await pool.end();
}
}
run();
+27
View File
@@ -0,0 +1,27 @@
import { Pool } from 'pg';
export async function seedCategoryTable(pool: Pool): Promise<void> {
// 1. Wipe old records to ensure clean execution states
await pool.query('TRUNCATE TABLE categories RESTART IDENTITY CASCADE;');
// 2. Insert standard ltree seed records
const seedQueries = [
{ name: 'Root', path: 'Top' },
{ name: 'Science', path: 'Top.Science' },
{ name: 'Astronomy', path: 'Top.Science.Astronomy' },
{ name: 'Astrophysics', path: 'Top.Science.Astronomy.Astrophysics' },
{ name: 'Hobbies', path: 'Top.Hobbies' },
{ name: 'Gardening', path: 'Top.Hobbies.Gardening' },
];
for (const record of seedQueries) {
await pool.query(
'INSERT INTO categories (name, path) VALUES ($1, $2::ltree);',
[record.name, record.path]
);
}
}
export async function clearCategoryTable(pool: Pool): Promise<void> {
await pool.query('TRUNCATE TABLE categories RESTART IDENTITY CASCADE;');
}