/** * GET /workflows/:name/executions — KV 額度事故修復(2026-08-07)路由測試。 * 改打 KBDB GET /execution-log(原走 ANALYTICS_KV list);KBDB=API-as-Wall, * 本檔一律 fetchMock 攔截,不碰任何 D1(比照 tests/portal-data.test.ts 慣例)。 */ import { SELF, env, fetchMock } from 'cloudflare:test'; import { beforeAll, afterEach, describe, it, expect } from 'vitest'; const KBDB = 'https://kbdb.test'; // wrangler.test.toml KBDB_BASE_URL const API_KEY = 'ak_exec_test'; beforeAll(() => { fetchMock.activate(); fetchMock.disableNetConnect(); }); afterEach(() => fetchMock.assertNoPendingInterceptors()); function get(path: string, headers: Record = {}) { return SELF.fetch(`http://localhost${path}`, { headers }); } describe('GET /workflows/:name/executions', () => { it('缺 X-Arcrun-API-Key → 401,不打 KBDB', async () => { const res = await get('/workflows/wf-x/executions'); expect(res.status).toBe(401); }); it('workflow 不存在或不屬於該 api_key → 404,不打 KBDB', async () => { const res = await get('/workflows/nope/executions', { 'X-Arcrun-API-Key': API_KEY }); expect(res.status).toBe(404); }); it('workflow 存在 → 轉發打 KBDB GET /execution-log,回傳其 executions', async () => { await env.WEBHOOKS.put( `${API_KEY}:wf:daily_report`, JSON.stringify({ graph: { id: 'daily_report', nodes: [] }, description: 'x', created_at: '2026-08-07T00:00:00Z' }), ); fetchMock .get(KBDB) .intercept({ path: (p: string) => p.startsWith('/execution-log?'), method: 'GET', }) .reply(200, { success: true, executions: [ { verdict: 'success', duration_ms: 100, message: 'ok', recorded_at: 1783500000 }, { verdict: 'failed', duration_ms: 50, message: '找不到 workflow', target: 'a.md', recorded_at: 1783400000 }, ], }); const res = await get('/workflows/daily_report/executions', { 'X-Arcrun-API-Key': API_KEY }); expect(res.status).toBe(200); const body = await res.json() as { ok: boolean; data: { workflow_name: string; count: number; executions: Array<{ verdict: string; target?: string }> }; }; expect(body.ok).toBe(true); expect(body.data.count).toBe(2); expect(body.data.executions[0].verdict).toBe('success'); expect(body.data.executions[1].target).toBe('a.md'); await env.WEBHOOKS.delete(`${API_KEY}:wf:daily_report`); }); it('KBDB 回非 success(例如全降級停記錄後空清單)→ 誠實回空陣列,不是假資料', async () => { await env.WEBHOOKS.put( `${API_KEY}:wf:empty_wf`, JSON.stringify({ graph: { id: 'empty_wf', nodes: [] }, description: 'x', created_at: '2026-08-07T00:00:00Z' }), ); fetchMock .get(KBDB) .intercept({ path: (p: string) => p.startsWith('/execution-log?'), method: 'GET' }) .reply(200, { success: true, executions: [] }); const res = await get('/workflows/empty_wf/executions', { 'X-Arcrun-API-Key': API_KEY }); const body = await res.json() as { data: { count: number; executions: unknown[] } }; expect(body.data.count).toBe(0); expect(body.data.executions).toEqual([]); await env.WEBHOOKS.delete(`${API_KEY}:wf:empty_wf`); }); });