import { mkdtemp, rm } from 'node:fs/promises'; import { tmpdir } from 'node:os'; import { join } from 'node:path'; import { afterEach, beforeEach, describe, expect, it } from 'vitest'; import { CatalogDatabase } from '../src/database/store.js'; let dir = ''; beforeEach(async () => { dir = await mkdtemp(join(tmpdir(), 'nlc-db-')); }); afterEach(async () => { await rm(dir, { force: true, recursive: true }); }); describe('CatalogDatabase', () => { it('creates the catalog schema', () => { const db = new CatalogDatabase(join(dir, 'catalog.sqlite')); db.migrate(); expect(db.tableNames()).toEqual([ 'dead_links', 'issues', 'link_occurrences', 'links', 'newsletters', 'runs', 'sponsors' ]); db.close(); }); it('persists catalog payloads and deduplicates canonical URLs', () => { const db = new CatalogDatabase(join(dir, 'catalog.sqlite')); db.migrate(); db.saveCatalogRun({ mode: 'test', newslettersProcessed: 2, linksExtracted: 2, sponsorCount: 1, deadLinkCount: 1, errors: 0, rows: [ { 'Issue Date': '2026-05-17', Category: 'JavaScript', 'Link URL': 'https://example.com/post', Title: 'First mention', Description: 'One', 'Page Title + Meta': '', 'Source Newsletter': 'Alpha Weekly', 'Also In': '' }, { 'Issue Date': '2026-05-18', Category: 'DevOps', 'Link URL': 'https://example.com/post', Title: 'Second mention', Description: 'Two', 'Page Title + Meta': '', 'Source Newsletter': 'Beta Weekly', 'Also In': '' } ], sponsors: [ { Newsletter: 'Alpha Weekly', Sponsor: 'Acme', Link: 'https://sponsor.example', Description: 'Sponsor blurb' } ], deadLinks: [ { URL: 'https://dead.example', Status: '404', Source: 'Alpha Weekly', Date: '2026-05-17' } ] }); expect(db.count('links')).toBe(3); expect(db.count('link_occurrences')).toBe(2); expect(db.count('newsletters')).toBe(2); expect(db.count('issues')).toBe(2); expect(db.count('sponsors')).toBe(1); expect(db.count('dead_links')).toBe(1); expect(db.count('runs')).toBe(1); db.close(); }); });