- tests/golden/run.mjs : chaîne complète des 5 nodes (code réel) en sandbox vm, horloge simulée par scénario, snapshot HA réel comme fixture. - 16 scénarios attendus figés après revue : nuit HC (P7), solaire, abondance P6, provocation P3, gardes SOC, force_grid/force_charge, stop, overload. - n8n-push.mjs exécute la suite avant tout PUT du workflow EVCS : golden rouge = push refusé (--skip-golden en échappatoire consciente). - Validé par mutation : P7 cassé volontairement -> 2 échecs détectés + push bloqué. - tools/fetch-snapshot-fixture.mjs : recapture d'un snapshot production.
51 lines
2.1 KiB
JavaScript
51 lines
2.1 KiB
JavaScript
#!/usr/bin/env node
|
|
// Capture un snapshot HA RÉEL depuis une exécution n8n récente du workflow EVCS
|
|
// → tests/golden/fixture-snapshot.json (base des scénarios golden).
|
|
// Usage: node tools/fetch-snapshot-fixture.mjs [executionId]
|
|
|
|
import fs from 'fs';
|
|
import os from 'os';
|
|
import path from 'path';
|
|
|
|
const WORKFLOW_ID = 'ATswvGfG4KJUls0K';
|
|
const SNAPSHOT_NODE = 'HA Snapshot EVCS Surplus Controller V2.2';
|
|
const OUT = 'tests/golden/fixture-snapshot.json';
|
|
|
|
function loadApiConfig() {
|
|
const cfgPath = path.join(os.homedir(), '.config/opencode/opencode.json');
|
|
const cfg = JSON.parse(fs.readFileSync(cfgPath, 'utf8'));
|
|
const env = cfg?.mcp?.['n8n-mcp']?.environment || {};
|
|
return {
|
|
url: (env.N8N_API_URL || '').replace(/\/api\/v1\/?$/, ''),
|
|
key: env.N8N_API_KEY
|
|
};
|
|
}
|
|
const { url, key } = loadApiConfig();
|
|
const headers = { 'X-N8N-API-KEY': key };
|
|
|
|
let execId = process.argv[2];
|
|
if (!execId) {
|
|
const res = await fetch(`${url}/api/v1/executions?workflowId=${WORKFLOW_ID}&status=success&limit=1`, { headers });
|
|
const list = await res.json();
|
|
execId = list.data?.[0]?.id;
|
|
if (!execId) { console.error('Aucune exécution trouvée'); process.exit(1); }
|
|
}
|
|
|
|
const res = await fetch(`${url}/api/v1/executions/${execId}?includeData=true`, { headers });
|
|
if (!res.ok) { console.error(`GET exécution ${execId}: ${res.status}`); process.exit(1); }
|
|
const exec = await res.json();
|
|
|
|
const runData = exec.data?.resultData?.runData;
|
|
if (!runData?.[SNAPSHOT_NODE]) {
|
|
console.error(`Node "${SNAPSHOT_NODE}" absent des données. Nodes dispo: ${Object.keys(runData || {}).join(', ')}`);
|
|
process.exit(1);
|
|
}
|
|
const items = runData[SNAPSHOT_NODE][0]?.data?.main?.[0];
|
|
if (!items?.length) { console.error('Pas de données de sortie sur le node snapshot'); process.exit(1); }
|
|
|
|
const snapshot = items[0].json;
|
|
fs.mkdirSync(path.dirname(OUT), { recursive: true });
|
|
fs.writeFileSync(OUT, JSON.stringify(snapshot, null, 2) + '\n');
|
|
console.log(`Fixture écrite: ${OUT} (exécution ${execId}, ${Object.keys(snapshot).length} champs)`);
|
|
console.log(`Champs: ${Object.keys(snapshot).sort().join(', ')}`);
|