const { test } = require('node:test'); const assert = require('node:assert'); const { renderFolderTree, renderExecutionList, renderExecutionDetail, renderN8nPage } = require('../src/n8nView'); test('renderFolderTree renders nothing for an empty tree', () => { assert.strictEqual(renderFolderTree([]), ''); }); test('renderFolderTree renders a workflow item with its id in a data attribute', () => { const html = renderFolderTree([{ type: 'workflow', id: 'w1', name: 'ワークフローA', active: true }]); assert.ok(html.includes('data-workflow-id="w1"')); assert.ok(html.includes('ワークフローA')); }); test('renderFolderTree marks inactive workflows differently from active ones', () => { const activeHtml = renderFolderTree([{ type: 'workflow', id: 'w1', name: 'A', active: true }]); const inactiveHtml = renderFolderTree([{ type: 'workflow', id: 'w2', name: 'B', active: false }]); assert.ok(activeHtml.includes('bg-success')); assert.ok(inactiveHtml.includes('bg-secondary')); }); test('renderFolderTree escapes HTML in workflow and folder names', () => { const html = renderFolderTree([{ type: 'workflow', id: 'w1', name: '', active: true }]); assert.ok(!html.includes('')); assert.ok(html.includes('<script>')); }); test('renderFolderTree nests folder children inside the folder element', () => { const html = renderFolderTree([ { type: 'folder', id: 'f1', name: 'フォルダA', children: [{ type: 'workflow', id: 'w1', name: 'ワークフローA', active: true }], }, ]); assert.ok(html.includes('フォルダA')); assert.ok(html.includes('data-workflow-id="w1"')); }); test('renderExecutionList renders a row per execution with a status badge', () => { const html = renderExecutionList([ { id: 'e1', status: 'success', startedAt: '2026-09-19T00:00:00.000Z' }, { id: 'e2', status: 'error', startedAt: '2026-09-18T00:00:00.000Z' }, ]); assert.ok(html.includes('data-execution-id="e1"')); assert.ok(html.includes('data-execution-id="e2"')); assert.ok(html.includes('bg-success')); assert.ok(html.includes('bg-danger')); }); test('renderExecutionList shows a message when there are no executions', () => { const html = renderExecutionList([]); assert.ok(html.includes('実行履歴なし')); }); test('renderExecutionDetail lists each node result with its status', () => { const execution = { id: 'e1', status: 'error', data: { resultData: { runData: { 'SSH: 対象wav一覧取得': [{ error: undefined }], 'IF: 未登録ファイルあり': [{ error: { message: 'timeout' } }], }, }, }, }; const html = renderExecutionDetail(execution); assert.ok(html.includes('SSH: 対象wav一覧取得')); assert.ok(html.includes('IF: 未登録ファイルあり')); assert.ok(html.includes('timeout')); }); test('renderN8nPage embeds the folder tree and a container for execution details', () => { const tree = [{ type: 'workflow', id: 'w1', name: 'ワークフローA', active: true }]; const html = renderN8nPage(tree); assert.ok(html.includes('data-workflow-id="w1"')); assert.ok(html.includes('id="executionList"')); assert.ok(html.includes('id="executionDetail"')); assert.ok(html.includes('/n8n.js')); });