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: '
AArticle 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');
});
});