n8nのフォルダ/ワークフロー構成をそのままapp-portal(/n8n)に反映し、 Webhookトリガーに限らず任意のワークフローの実行履歴・ノード単位の 成功/失敗・エラー内容を確認できるようにした(get-voice-mail専用にせず n8n Public API経由で動的取得する汎用設計)。TDDで実装、テスト23件追加。
109 lines
4.4 KiB
JavaScript
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/);
|
|
});
|
|
});
|