ken_nogi/NodeSrv/apps/app-portal/test/n8nClient.test.js
Kenichiro NOGI eca5c84c39 feat(app-portal): n8nワークフローのフォルダ構造・実行ログ閲覧ページを追加
n8nのフォルダ/ワークフロー構成をそのままapp-portal(/n8n)に反映し、
Webhookトリガーに限らず任意のワークフローの実行履歴・ノード単位の
成功/失敗・エラー内容を確認できるようにした(get-voice-mail専用にせず
n8n Public API経由で動的取得する汎用設計)。TDDで実装、テスト23件追加。
2026-09-19 12:19:27 +09:00

109 lines
4.4 KiB
JavaScript

const { test } = require('node:test');
const assert = require('node:assert');
function withMockFetch(mockFetch, fn) {
const original = global.fetch;
global.fetch = mockFetch;
return fn().finally(() => {
global.fetch = original;
});
}
test('listFolders calls /projects/{projectId}/folders with the API key header', async () => {
process.env.N8N_BASE_URL = 'https://n8n.test';
process.env.N8N_API_KEY = 'test-key';
delete require.cache[require.resolve('../src/n8nClient')];
const { listFolders } = require('../src/n8nClient');
await withMockFetch(async (url, options) => {
const parsed = new URL(url);
assert.strictEqual(parsed.pathname, '/api/v1/projects/proj-1/folders');
assert.strictEqual(options.headers['X-N8N-API-KEY'], 'test-key');
return { ok: true, json: async () => ({ data: [{ id: 'f1', name: 'フォルダA', parentFolderId: null }] }) };
}, async () => {
const folders = await listFolders('proj-1');
assert.deepStrictEqual(folders, [{ id: 'f1', name: 'フォルダA', parentFolderId: null }]);
});
});
test('listWorkflows calls /workflows and returns the data array', async () => {
process.env.N8N_BASE_URL = 'https://n8n.test';
process.env.N8N_API_KEY = 'test-key';
delete require.cache[require.resolve('../src/n8nClient')];
const { listWorkflows } = require('../src/n8nClient');
await withMockFetch(async (url) => {
const parsed = new URL(url);
assert.strictEqual(parsed.pathname, '/api/v1/workflows');
return {
ok: true,
json: async () => ({ data: [{ id: 'w1', name: 'ワークフローA', active: true, parentFolder: null }] }),
};
}, async () => {
const workflows = await listWorkflows();
assert.deepStrictEqual(workflows, [{ id: 'w1', name: 'ワークフローA', active: true, parentFolder: null }]);
});
});
test('listExecutions passes workflowId and status as query params', async () => {
process.env.N8N_BASE_URL = 'https://n8n.test';
process.env.N8N_API_KEY = 'test-key';
delete require.cache[require.resolve('../src/n8nClient')];
const { listExecutions } = require('../src/n8nClient');
await withMockFetch(async (url) => {
const parsed = new URL(url);
assert.strictEqual(parsed.pathname, '/api/v1/executions');
assert.strictEqual(parsed.searchParams.get('workflowId'), 'w1');
assert.strictEqual(parsed.searchParams.get('status'), 'error');
assert.strictEqual(parsed.searchParams.get('limit'), '20');
return { ok: true, json: async () => ({ data: [{ id: 'e1', status: 'error' }] }) };
}, async () => {
const executions = await listExecutions('w1', { status: 'error', limit: 20 });
assert.deepStrictEqual(executions, [{ id: 'e1', status: 'error' }]);
});
});
test('listExecutions omits status param when not given', async () => {
process.env.N8N_BASE_URL = 'https://n8n.test';
process.env.N8N_API_KEY = 'test-key';
delete require.cache[require.resolve('../src/n8nClient')];
const { listExecutions } = require('../src/n8nClient');
await withMockFetch(async (url) => {
const parsed = new URL(url);
assert.strictEqual(parsed.searchParams.has('status'), false);
return { ok: true, json: async () => ({ data: [] }) };
}, async () => {
await listExecutions('w1', { limit: 20 });
});
});
test('getExecution requests includeData=true when asked and returns the execution', async () => {
process.env.N8N_BASE_URL = 'https://n8n.test';
process.env.N8N_API_KEY = 'test-key';
delete require.cache[require.resolve('../src/n8nClient')];
const { getExecution } = require('../src/n8nClient');
await withMockFetch(async (url) => {
const parsed = new URL(url);
assert.strictEqual(parsed.pathname, '/api/v1/executions/e1');
assert.strictEqual(parsed.searchParams.get('includeData'), 'true');
return { ok: true, json: async () => ({ id: 'e1', status: 'success', data: {} }) };
}, async () => {
const execution = await getExecution('e1', true);
assert.deepStrictEqual(execution, { id: 'e1', status: 'success', data: {} });
});
});
test('n8n client throws when the response is not ok', async () => {
process.env.N8N_BASE_URL = 'https://n8n.test';
process.env.N8N_API_KEY = 'test-key';
delete require.cache[require.resolve('../src/n8nClient')];
const { listWorkflows } = require('../src/n8nClient');
await withMockFetch(async () => ({ ok: false, status: 401 }), async () => {
await assert.rejects(() => listWorkflows(), /401/);
});
});