Communityn8ngithub.com

ashtonfeliciano/n8n 评估运行器

构建并运行零 API 成本逻辑测试套件,用于 n8n 工作流。适用于为筛选逻辑、评分函数、验证器、关键词列表、简历映射或任何纯 JS 代码节点逻辑添加测试覆盖。通过 Telegram 输出分组通过/失败/待处理报告。在逻辑变更前后运行,以在不消耗 API 额度的情况下捕获回归。

n8n 评估运行器 是什么?

该技能提供了一个结构化的方法,用于在 n8n 中创建和执行单元测试,专门针对纯 JavaScript 代码节点,而无需产生 API 成本。它通过定义明确的“评估”工作流运行,其中包含一个使用伪造输入复制生产逻辑的测试运行器 Code 节点,确保测试快速(约 3 秒)且完全在内存中运行。该技能会自动汇总结果,并通过 Telegram 发送详细报告,使用颜色编码的状态指示器(绿色/黄色/红色)指示失败数量。它为编写测试提供了具体的模式,包括拒绝路径覆盖、边界条件以及将过去的错误转化为回归测试,并附带有用的命名约定和应避免的反模式。该技能主要面向希望在 CI/CD 流程或手动测试周期中集成无成本逻辑验证的 n8n 用户,特别是那些使用手动触发器或环境变量进行配置的用户。

兼容平台~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/ashtonfeliciano/claude-skills-pack/tree/HEAD/skills/n8n-evaluations-runner

Installed? Explore more n8n skills: ashtonfeliciano/n8n-workflow-engineer, hubgunter4-ops/configurador-de-nodos-n8n, hubgunter4-ops/experto-en-n8n-mcp · View all 6 →

在你喜欢的 AI 中提问

打开一个已预加载此 Agent Skill 的新对话。

文档

n8n 评估运行器 是做什么的?

何时触发

  • 添加或修改筛选逻辑、关键词列表、验证器或简历映射时
  • 重构 Code 节点的纯函数逻辑时
  • 合并工作流变更前——回归防护
  • 生产事故后——将失败固化到测试中
  • “我如何对 n8n 代码进行单元测试?” / “如何在不消耗 API 额度的情况下进行测试?”

这是什么(以及不是什么)

这是这不是
一个仅含逻辑的 n8n 工作流,使用伪造输入针对实时 API 的集成测试
除了最终报告发送外无外部调用——约 3 秒运行完成性能测试
推送到 Telegram 的通过/失败/待处理计数端到端流程手动冒烟测试的替代品
Code 节点中纯 JS 的回归网络HTTP / Gmail / Telegram 节点行为的覆盖

成本: 无 API 额度。仅内存中的伪造输入。Telegram 报告是唯一的外部调用。

架构

[手动触发器] → [运行所有测试(Code 节点)] → [格式化报告(Code 节点)] → [发送报告(Telegram)]

每个逻辑面一个工作流。按需重新运行。

标准测试运行器 Code 节点

const results = [];

function assert(suite, testName, condition, detail) {
  results.push({ suite, test: testName, pass: condition, detail: detail || '' });
}

// ============================================================
// 套件 1 — <名称>
// ============================================================

// 此处逐字复制生产函数(不要导入——Code 节点不共享作用域)
function passesJs10Filter(job) {
  // ... 与生产节点相同的代码 ...
}

// 测试
assert('js-10', '机密职位被拒绝',
  !passesJs10Filter({
    title: 'Technical Writer',
    description: 'Clearance required.',
    location: 'remote'
  }),
  '需要机密的职位必须触发拒绝');

assert('js-10', '有效的远程技术写手通过',
  passesJs10Filter({
    title: 'Technical Writer',
    description: 'Write API documentation for cloud platform.',
    location: 'remote'
  }),
  '有效的远程技术写手应通过所有筛选');

// 对于尚未实现的功能:
results.push({
  suite: 'js-10',
  test: '30天截止日期(待处理 — 积压)',
  pass: null,
  detail: '功能尚未实现。添加 postedAt 日期检查,然后重新运行。'
});

// ============================================================
// 汇总
// ============================================================

const passed  = results.filter(r => r.pass === true);
const failed  = results.filter(r => r.pass === false);
const pending = results.filter(r => r.pass === null);

return [{ json: {
  summary: { total: results.length, passed: passed.length, failed: failed.length, pending: pending.length },
  results, failed, pending
}}];

报告格式化器

const { summary, results } = $input.first().json;

const passIcon = '✅';
const failIcon = '❌';
const pendIcon = '⏳';
const topEmoji = summary.failed === 0 ? '🟢' : (summary.failed <= 3 ? '🟡' : '🔴');

const lines = [
  `<b>${topEmoji} <名称> — 逻辑评估</b>`,
  `${passIcon} ${summary.passed} 通过  ${failIcon} ${summary.failed} 失败  ${pendIcon} ${summary.pending} 待处理`,
  ''
];

const suites = {};
for (const r of results) (suites[r.suite] = suites[r.suite] || []).push(r);

for (const [suite, tests] of Object.entries(suites)) {
  const suitePass = tests.every(t => t.pass !== false);
  lines.push(`<b>${suitePass ? passIcon : failIcon} ${suite}</b>`);
  for (const t of tests) {
    const icon = t.pass === true ? passIcon : (t.pass === false ? failIcon : pendIcon);
    lines.push(`  ${icon} ${t.test}`);
    if (t.pass !== true) lines.push(`    <i>→ ${(t.detail || '').substring(0, 140)}</i>`);
  }
  lines.push('');
}

const now = new Date().toLocaleString('en-US', {
  timeZone: 'UTC', dateStyle: 'short', timeStyle: 'short'
});
lines.push(`<i>运行时间:${now} UTC</i>`);

return [{ json: { message: lines.join('\n') } }];

Telegram 发送节点(环境变量模式,无需 n8n 凭证)

{
  "method": "POST",
  "url": "=https://api.telegram.org/bot{{ $env.TELEGRAM_BOT_TOKEN }}/sendMessage",
  "sendBody": true,
  "specifyBody": "keypair",
  "bodyParameters": {
    "parameters": [
      { "name": "chat_id", "value": "={{ $env.TELEGRAM_CHAT_ID }}" },
      { "name": "text", "value": "={{ $json.message }}" },
      { "name": "parse_mode", "value": "HTML" }
    ]
  }
}

测试内容(优先级顺序)

  1. 拒绝路径覆盖 — 记录可能被筛选出的每一个原因
  2. 边界条件 — 阈值处、略低于、略高于
  3. 无效输入回退 — undefined、null、0、'None'、错误类型 → 预期默认值
  4. 已知良好的真实数据 — 至少一个来自过去确认可运行运行的示例
  5. 已知不良的真实数据 — 至少一个曾导致过去事故的示例
  6. 子串匹配与精确匹配 — 例如 'HR Dept' 与 'Human Resources Department'
  7. 待处理功能 — 写为 pass: null,以便在报告中显示为积压项

测试命名约定

<套件>: <人类可读的断言>,详情字段命名底层规则或过去错误引用:

assert('js-22', 'Human Resources Department 被拒绝',
  !isValidContact('Human Resources Department'),
  'BAD_CONTAINS_CONTACT 子串匹配必须捕获此情况(第5次会话错误修复)');

“将过去错误转化为测试”规则

你的经验教训库中每一条命名了特定输入 → 错误行为的条目都是一个等待编写的测试。

来自真实经验的示例:

“聚合扇区报价在计算 1 个月变动而不是 1 天变动,因为 meta.previousClose 在范围=1mo 时返回了图表开始价格。”

→ 测试:

assert('aggregate', '1天变动从 closes[] 计算,而非 meta.previousClose',
  computeChange({
    chart: { result: [{ meta: { previousClose: 100 }, indicators: { quote: [{ close: [100, 98, 99, 105] }] } }] }
  }) === ((105 - 99) / 99) * 100,
  'meta.previousClose 可能不可靠;必须使用 closes[-2]');

何时运行

  • 对筛选逻辑、关键词列表、验证器、简历映射进行任何更改之前
  • 更改之后——确认没有回归
  • 添加任何经验教训库条目之后——编写本可以捕获该问题的测试
  • 部署任何新工作流版本之前

状态图标含义

图标含义
🟢(绿色)0 个失败——此套件通过;仅在其他检查也通过时部署
🟡(黄色)1-3 个失败——修复前阻止部署
🔴(红色)4 个以上失败——阻止部署;可能是更广泛的故障

待处理(⏳)不计入红色/黄色——它作为积压项单独跟踪。待处理测试是覆盖缺口:在部署说明中列出它们。

反模式

反模式应该怎么做
针对实时 API 测试仅伪造输入——评估套件仅限逻辑
跳过待处理功能(失去可见性)添加为 pass: null,附带解释缺失内容的详情
导入生产代码逐字复制——Code 节点不共享作用域
一个巨大的测试函数每个断言一个 assert()——生成可读报告
错误修复后丢弃测试永远保留——这就是回归防护
仅测试快乐路径拒绝路径覆盖是最有价值的测试
仅在更改后运行在更改前后都运行——确认你没有引入回归
在 workflow JSON 中硬编码聊天 ID / 令牌使用 $env.TELEGRAM_BOT_TOKEN / $env.TELEGRAM_CHAT_ID

部署前检查清单

  • 评估工作流在 < 10 秒内运行
  • 所有套件在报告中分组
  • 生产代码已逐字复制(非改写)
  • 每个拒绝路径至少 1 个测试
  • 每个套件至少 1 个“已知良好的真实数据”测试
  • 待处理功能表示为 pass: null 并附带详情
  • 报告适合一条 Telegram 消息(< 4000 字符)

参考

Individual skills in this repo

This repo contains 1 individual skill — each has its own dedicated page.

相关技能

ashtonfeliciano/n8n-workflow-engineer

Build, debug, and harden n8n workflows. Use when the user is editing n8n workflow JSON, debugging silent failures, working with Code nodes, Telegram / Gmail / HTTP Request nodes, scheduled triggers, paired-item tracking, dedup with static data, or doing bulk operations via the n8n REST API. Covers v2.x UI specifics. Not for non-n8n automation.

community

hubgunter4-ops/configurador-de-nodos-n8n

Ayuda a configurar nodos de n8n con reglas de dependencia complejas y conexiones de IA. Agiliza la creación de flujos de trabajo automatizados gestionando dependencias de nodos intrincadas e integraciones de IA.

community

hubgunter4-ops/experto-en-n8n-mcp

Guía a los desarrolladores a seleccionar y configurar herramientas y formatos de nodo del Protocolo de Contexto de Modelo MCP dentro de los flujos de trabajo de n8n. Proporciona orientación estructurada para integrar herramientas MCP.

community

caiqueDeOliveira-dev/homelab

HomeLab Agent — Gerencia Home Assistant, ESP32 satellites, dispositivos Zigbee/Matter/Thread, automações físicas, cameras, sensores. Camada de decisão e execução no hardware (não orquestração de software = Automação/n8n).

community

hubgunter4-ops/experto-en-n8n-mcp

Guía a los desarrolladores a seleccionar y configurar herramientas y formatos de nodo del Protocolo de Contexto de Modelo MCP dentro de los flujos de trabajo de n8n. Proporciona orientación estructurada para integrar herramientas MCP.

community

hubgunter4-ops/experto-en-validacion-de-n8n

Corrige errores de validación de n8n consultando un catálogo de errores integrado. Optimiza el proceso de depuración, permitiendo identificar rápidamente problemas y resolver problemas de configuración del flujo de trabajo.

community