// entity 正規化 — exact match(語意合併屬基本盤 embed 模組),走 mock client。 import { describe, it, expect } from 'vitest'; import { createEntity, findEntityByName, listEntities } from '../src/actions/entity-crud'; import { normalizeEntity } from '../src/actions/entity-normalize'; import { mockClient } from './mock-client'; describe('entity-crud', () => { it('建立後可 exact 查回(大小寫不敏感),owner slot 帶真 owner', async () => { const c = mockClient(); const ent = await createEntity(c, 'InkStone', 'leo'); const found = await findEntityByName(c, 'inkstone', 'leo'); expect(found?.canonical).toBe('InkStone'); // owner 落底:record 掛在 leo 名下(非無主),用錯 owner 查不到。 const rec = await c.getRecord(ent.id); expect(rec?.values.owner).toBe('leo'); expect(await findEntityByName(c, 'inkstone', 'someone-else')).toBeNull(); }); it('漏 owner → 插件端 fail(不寫出無主 entity)', async () => { const c = mockClient(); await expect( // @ts-expect-error 蓄意漏 owner:型別上 owner 必填,執行期也應 throw createEntity(c, 'NoOwner'), ).rejects.toThrow(/owner/i); }); it('listEntities 列出', async () => { const c = mockClient(); await createEntity(c, 'A', 'leo'); await createEntity(c, 'B', 'leo'); const all = await listEntities(c); expect(all.map((e) => e.canonical).sort()).toEqual(['A', 'B']); }); }); describe('normalizeEntity', () => { it('已存在回 canonical,不存在建新回原值', async () => { const c = mockClient(); await createEntity(c, 'InkStone', 'leo'); expect(await normalizeEntity(c, 'INKSTONE', 'leo')).toBe('InkStone'); expect(await normalizeEntity(c, '新公司', 'leo')).toBe('新公司'); }); });