n8n Public APIはworkflow.parentFolderIdがwriteOnlyでフォルダ→ワークフロー 対応を読み取れない仕様上の制約が判明したため、フォルダ階層表示を断念し タグ単位のフラットなグルーピング(未分類は最後)に切り替えた。n8n側は 既存6フォルダ相当のタグを作成、44ワークフローへ割当済み。
92 lines
3.6 KiB
JavaScript
92 lines
3.6 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('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/);
|
|
});
|
|
});
|