import { mkdtempSync, rmSync } from 'node:fs'; import { tmpdir } from 'node:os'; import { join } from 'node:path'; import { DatabaseSync } from 'node:sqlite'; import { afterEach, beforeEach, describe, expect, it } from 'vitest'; import { RssStore } from './rss.store.js'; describe('RssStore (real SQLite file)', () => { let dir: string; let store: RssStore; beforeEach(() => { dir = mkdtempSync(join(tmpdir(), 'mesh-bot-rss-')); const db = new DatabaseSync(join(dir, 'test.db')); store = new RssStore(db); }); afterEach(() => { rmSync(dir, { recursive: true, force: true }); }); it('adds and lists sources with tags round-tripped through the comma string', () => { store.add({ name: 'Hacker News', url: 'https://news.ycombinator.com/rss', tags: ['tech', 'news'], }); store.add({ name: 'LWN', url: 'https://lwn.net/headlines.rss', tags: [] }); expect(store.list()).toEqual([ { name: 'Hacker News', url: 'https://news.ycombinator.com/rss', tags: ['tech', 'news'], createdAt: expect.any(Number), }, { name: 'LWN', url: 'https://lwn.net/headlines.rss', tags: [], createdAt: expect.any(Number), }, ]); }); it('looks up and checks existence case-insensitively', () => { store.add({ name: 'My Feed', url: 'https://example.com/rss', tags: ['a'] }); expect(store.get('my feed')?.url).toBe('https://example.com/rss'); expect(store.get('MY FEED')).toBeDefined(); expect(store.exists('mY fEeD')).toBe(true); expect(store.exists('other')).toBe(false); }); it('removes case-insensitively and reports whether a row went', () => { store.add({ name: 'Gone', url: 'https://example.com/gone', tags: [] }); expect(store.remove('gone')).toBe(true); expect(store.list()).toEqual([]); expect(store.remove('gone')).toBe(false); }); it('collects all distinct tags across sources, sorted', () => { store.add({ name: 'A', url: 'https://a.example/rss', tags: ['zeta', 'alpha'], }); store.add({ name: 'B', url: 'https://b.example/rss', tags: ['beta', 'alpha'], }); expect(store.allTags()).toEqual(['alpha', 'beta', 'zeta']); }); it('persists across a second connection to the same file (the production shape)', () => { store.add({ name: 'Durable', url: 'https://d.example/rss', tags: ['x'] }); const db2 = new DatabaseSync(join(dir, 'test.db')); expect(new RssStore(db2).get('durable')?.tags).toEqual(['x']); }); });