import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'; import { resetDb } from '../../helpers/db.js'; import { migrateUp } from '../../../lib/db/migrate.js'; import { stopBoss, waitForJob } from '../../helpers/boss.js'; import * as queue from '../../../lib/jobs/queue.js'; import { registerWorkers } from '../../../lib/jobs/index.js'; import * as spaces from '../../../lib/db/repos/spaces.js'; import * as refs from '../../../lib/db/repos/refs.js'; const BM_RESPONSE = JSON.stringify({ id: 'b-1', url: 'https://example.com/a', title: 'A', html_content: 'A

Article body content long enough to satisfy readability heuristics.

Another paragraph.

', tags: [{ name: 'archive' }, { name: 'inbox' }] }); beforeEach(async () => { await resetDb(); await migrateUp(); await queue.start(); await registerWorkers(); global.fetch = vi.fn(async () => new Response(BM_RESPONSE, { status: 200, headers: { 'content-type': 'application/json' } })); }); afterEach(async () => { await stopBoss(); vi.restoreAllMocks(); }); describe('ingest.karakeep worker', () => { it('creates a ref with source_kind=karakeep', async () => { const sp = await spaces.create({ slug: 'k', name: 'K' }, { kind: 'user', id: null }); const id = await queue.enqueue('ingest.karakeep', { bookmark_id: 'b-1', space_id: sp.id }); const j = await waitForJob('ingest.karakeep', id, { timeoutMs: 10_000 }); expect(j.state).toBe('completed'); const rows = await refs.list({ space_id: sp.id }); expect(rows[0].source_kind).toBe('karakeep'); expect(rows[0].title).toBe('A'); expect(rows[0].metadata.tags).toEqual(['archive','inbox']); }); it('idempotent on repeat ingest of the same bookmark_id', async () => { const sp = await spaces.create({ slug: 'k2', name: 'K2' }, { kind: 'user', id: null }); const id1 = await queue.enqueue('ingest.karakeep', { bookmark_id: 'b-1', space_id: sp.id }); await waitForJob('ingest.karakeep', id1, { timeoutMs: 10_000 }); const id2 = await queue.enqueue('ingest.karakeep', { bookmark_id: 'b-1', space_id: sp.id }); const j2 = await waitForJob('ingest.karakeep', id2, { timeoutMs: 10_000 }); expect(j2.output.idempotent).toBe(true); }); it('skipped when bookmark is gone (Karakeep 404)', async () => { global.fetch = vi.fn(async () => new Response('', { status: 404 })); const sp = await spaces.create({ slug: 'k3', name: 'K3' }, { kind: 'user', id: null }); const id = await queue.enqueue('ingest.karakeep', { bookmark_id: 'gone', space_id: sp.id }); const j = await waitForJob('ingest.karakeep', id, { timeoutMs: 10_000 }); expect(j.output.skipped).toBe('gone'); }); });