// triplet CRUD — 走 mock KbdbClient(API-as-Wall),零 SQL。 import { describe, it, expect } from 'vitest'; import { createTriplet, queryTriplets, getTriplet } from '../src/actions/triplet-crud'; import { mockClient } from './mock-client'; describe('createTriplet → records API', () => { it('建立後可由 id 取回', async () => { const c = mockClient(); const r = await createTriplet(c, { subject: 'InkStone', predicate: '是', object: '創業 OS', owner_id: 'leo' }); expect(r.id).toBeDefined(); expect(r.subject).toBe('InkStone'); const got = await getTriplet(c, r.id); expect(got?.predicate).toBe('是'); expect(got?.object).toBe('創業 OS'); }); it('漏 owner → 插件端 fail(不靜默送空,不寫出無主 triplet)', async () => { const c = mockClient(); await expect( // @ts-expect-error 蓄意漏 owner:型別上 owner 必填,執行期也應 throw createTriplet(c, { subject: 'X', predicate: 'p', object: 'Y' }), ).rejects.toThrow(/owner/i); const { count } = await queryTriplets(c, { includeDeprecated: true }); expect(count).toBe(0); }); }); describe('queryTriplets → 插件層 filter', () => { it('by subject 過濾', async () => { const c = mockClient(); await createTriplet(c, { subject: 'KBDB', predicate: '使用', object: 'D1', owner_id: 'leo' }); await createTriplet(c, { subject: 'Other', predicate: '使用', object: 'X', owner_id: 'leo' }); const { triplets, count } = await queryTriplets(c, { subject: 'KBDB' }); expect(count).toBe(1); expect(triplets[0].object).toBe('D1'); }); it('limit/offset 分頁', async () => { const c = mockClient(); for (let i = 0; i < 5; i++) await createTriplet(c, { subject: `s${i}`, predicate: 'p', object: 'o', owner_id: 'leo' }); const { triplets } = await queryTriplets(c, { limit: 2, offset: 1 }); expect(triplets.length).toBe(2); }); });