87f6de7c9f
leo 2026-08-15「有效才正式開發」下一格:紙上考卷驗過的動作集做成真的 n8n 節點。 詞彙照定案(sheet/field/record,InkStoneCo system-dev/wiki/kbdb-詞彙表.md)。 - 動作 ↔ API 映射收斂在 nodes/Kbdb/actions.ts(純函式),20 個 vitest 釘死 ——就是動作對照表 ✅ 那半的機器版;🔴/◐ 的動作刻意不存在,呼叫丟 「沒有這個能力」(07-thin-shell §3.1:API 沒有的能力不拼裝) - 對外走 cypher-executor /kbdb/* proxy(X-Arcrun-API-Key),不直連 kbdb worker - Add a field 不掛:proxy 無 PATCH /kbdb/templates(實測 404);base 端 PATCH /templates/:id 語意是 slots 整組覆蓋(本地實測),不是加一欄 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
110 lines
4.1 KiB
TypeScript
110 lines
4.1 KiB
TypeScript
/**
|
||
* 動作 → API 的映射測試=「kbdb-動作對照表」✅ 那半的機器版。
|
||
* 表若改(路由變動),這裡會先紅——防對照表漂移(表自己的「過期時會教錯」段)。
|
||
*/
|
||
import { describe, expect, it } from 'vitest';
|
||
import { buildRequest } from '../nodes/Kbdb/actions';
|
||
|
||
describe('對照表 ✅ 那半:每個動作恰好對到一支現行 API', () => {
|
||
it('Append record → POST /kbdb/records', () => {
|
||
expect(buildRequest('record', 'append', { sheet: 'contact', values: { name: '王小明' } })).toEqual({
|
||
method: 'POST',
|
||
path: '/kbdb/records',
|
||
body: { template: 'contact', values: { name: '王小明' } },
|
||
});
|
||
});
|
||
|
||
it('Get a record → GET /kbdb/records/:recordId', () => {
|
||
expect(buildRequest('record', 'get', { recordId: 'rec_1' })).toEqual({
|
||
method: 'GET',
|
||
path: '/kbdb/records/rec_1',
|
||
});
|
||
});
|
||
|
||
it('Get many records → GET /kbdb/records/by-template/:sheet', () => {
|
||
expect(buildRequest('record', 'getMany', { sheet: 'contact' })).toEqual({
|
||
method: 'GET',
|
||
path: '/kbdb/records/by-template/contact',
|
||
});
|
||
});
|
||
|
||
it('Update a record → PATCH /kbdb/records/:recordId(只帶要改的欄)', () => {
|
||
expect(buildRequest('record', 'update', { recordId: 'rec_1', values: { phone: '0912' } })).toEqual({
|
||
method: 'PATCH',
|
||
path: '/kbdb/records/rec_1',
|
||
body: { values: { phone: '0912' } },
|
||
});
|
||
});
|
||
|
||
it('Create a sheet → POST /kbdb/templates(name + slots[])', () => {
|
||
expect(buildRequest('sheet', 'create', { sheet: 'teacher_list', slots: ['name', 'hired_at'] })).toEqual({
|
||
method: 'POST',
|
||
path: '/kbdb/templates',
|
||
body: { name: 'teacher_list', slots: ['name', 'hired_at'] },
|
||
});
|
||
});
|
||
|
||
it('Get sheet schema → GET /kbdb/templates/:idOrName', () => {
|
||
expect(buildRequest('sheet', 'getSchema', { sheet: 'contact' })).toEqual({
|
||
method: 'GET',
|
||
path: '/kbdb/templates/contact',
|
||
});
|
||
});
|
||
|
||
it('List sheets → GET /kbdb/templates', () => {
|
||
expect(buildRequest('sheet', 'list', {})).toEqual({ method: 'GET', path: '/kbdb/templates' });
|
||
});
|
||
|
||
it('Search → GET /kbdb/search(q 必填、mode/filters 透傳)', () => {
|
||
expect(
|
||
buildRequest('search', 'search', {
|
||
query: '牛肉麵',
|
||
mode: 'keyword',
|
||
filters: { library: 'general' },
|
||
}),
|
||
).toEqual({
|
||
method: 'GET',
|
||
path: '/kbdb/search',
|
||
qs: { q: '牛肉麵', mode: 'keyword', library: 'general' },
|
||
});
|
||
});
|
||
|
||
it('路徑參數會被 URL encode(中文 sheet 名不炸)', () => {
|
||
expect(buildRequest('record', 'getMany', { sheet: '通訊錄' }).path).toBe(
|
||
`/kbdb/records/by-template/${encodeURIComponent('通訊錄')}`,
|
||
);
|
||
});
|
||
});
|
||
|
||
describe('對照表 🔴/◐ 那半:沒有的能力要誠實丟錯,不拼裝(07-thin-shell §3.1)', () => {
|
||
const missing: Array<[string, string]> = [
|
||
['sheet', 'addField'], // ◐→實測:PATCH /templates 是整組覆蓋且 proxy 未暴露 ⇒ 對外沒有這能力
|
||
['sheet', 'archive'], // 🔴 API 連 DELETE 都沒有
|
||
['record', 'archive'], // 🔴 只有 DELETE(真的刪掉),語意不符不掛上來
|
||
['record', 'link'], // 🔴 關係整組沒有 API
|
||
['record', 'addToSheet'], // 🔴 同上
|
||
['record', 'getLinked'], // 🔴 同上
|
||
['record', 'unlink'], // 🔴 同上
|
||
];
|
||
for (const [resource, operation] of missing) {
|
||
it(`${resource}.${operation} → 明確丟「沒有這個能力」`, () => {
|
||
expect(() => buildRequest(resource, operation, {})).toThrow(/沒有.*能力/);
|
||
});
|
||
}
|
||
});
|
||
|
||
describe('必要參數缺漏要在薄殼層就講清楚', () => {
|
||
it('append 缺 values → 錯誤訊息點名 values', () => {
|
||
expect(() => buildRequest('record', 'append', { sheet: 'contact' })).toThrow(/values/);
|
||
});
|
||
it('create sheet 缺欄位 → 錯誤訊息點名 fields', () => {
|
||
expect(() => buildRequest('sheet', 'create', { sheet: 'x' })).toThrow(/fields/);
|
||
});
|
||
it('create sheet 空欄位陣列 → 擋', () => {
|
||
expect(() => buildRequest('sheet', 'create', { sheet: 'x', slots: [] })).toThrow(/至少要有一欄/);
|
||
});
|
||
it('search 缺 query → 錯誤訊息點名 query', () => {
|
||
expect(() => buildRequest('search', 'search', {})).toThrow(/query/);
|
||
});
|
||
});
|