#!/usr/bin/env node /** * Verify asset selection fields are correct in deployed flow. * Checks that supplier/assetType/model/unit values match asset data IDs * so the editor dropdowns will pre-select correctly. */ const http = require('http'); const NR_URL = 'http://localhost:1880'; async function fetchJSON(url) { return new Promise((resolve, reject) => { http.get(url, res => { const chunks = []; res.on('data', c => chunks.push(c)); res.on('end', () => { try { resolve(JSON.parse(Buffer.concat(chunks))); } catch (e) { reject(new Error(`Parse error: ${e.message}`)); } }); }).on('error', reject); }); } (async () => { const flows = await fetchJSON(`${NR_URL}/flows`); const errors = []; console.log('=== Pump Asset Selection Checks ==='); const pumps = flows.filter(n => n.type === 'rotatingMachine' && n.z === 'demo_tab_wwtp'); pumps.forEach(p => { const checks = [ { field: 'supplier', expected: 'hidrostal', actual: p.supplier }, { field: 'assetType', expected: 'pump-centrifugal', actual: p.assetType }, { field: 'category', expected: 'machine', actual: p.category }, ]; checks.forEach(c => { if (c.actual === c.expected) { console.log(` PASS: ${p.id} ${c.field} = "${c.actual}"`); } else { console.log(` FAIL: ${p.id} ${c.field} = "${c.actual}" (expected "${c.expected}")`); errors.push(`${p.id}.${c.field}`); } }); // Model should be one of the known models const validModels = ['hidrostal-H05K-S03R', 'hidrostal-C5-D03R-SHN1']; if (validModels.includes(p.model)) { console.log(` PASS: ${p.id} model = "${p.model}"`); } else { console.log(` FAIL: ${p.id} model = "${p.model}" (expected one of ${validModels})`); errors.push(`${p.id}.model`); } }); console.log('\n=== Measurement Asset Selection Checks ==='); const measurements = flows.filter(n => n.type === 'measurement' && n.z === 'demo_tab_wwtp'); // Valid supplier→type→model combinations from measurement.json const validSuppliers = { 'Endress+Hauser': { types: ['flow', 'pressure', 'level'], models: { flow: ['Promag-W400', 'Promag-W300'], pressure: ['Cerabar-PMC51', 'Cerabar-PMC71'], level: ['Levelflex-FMP50'] } }, 'Hach': { types: ['dissolved-oxygen', 'ammonium', 'nitrate', 'tss'], models: { 'dissolved-oxygen': ['LDO2'], ammonium: ['Amtax-sc'], nitrate: ['Nitratax-sc'], tss: ['Solitax-sc'] } }, 'vega': { types: ['temperature', 'pressure', 'flow', 'level', 'oxygen'], models: {} // not checking Vega models for now } }; measurements.forEach(m => { const supplierData = validSuppliers[m.supplier]; if (!supplierData) { console.log(` FAIL: ${m.id} supplier "${m.supplier}" not in asset data`); errors.push(`${m.id}.supplier`); return; } console.log(` PASS: ${m.id} supplier = "${m.supplier}"`); if (!supplierData.types.includes(m.assetType)) { console.log(` FAIL: ${m.id} assetType "${m.assetType}" not in ${m.supplier} types`); errors.push(`${m.id}.assetType`); } else { console.log(` PASS: ${m.id} assetType = "${m.assetType}"`); } const validModels = supplierData.models[m.assetType] || []; if (validModels.length > 0 && !validModels.includes(m.model)) { console.log(` FAIL: ${m.id} model "${m.model}" not in ${m.supplier}/${m.assetType} models`); errors.push(`${m.id}.model`); } else if (m.model) { console.log(` PASS: ${m.id} model = "${m.model}"`); } }); console.log('\n=== RESULT ==='); if (errors.length === 0) { console.log('ALL ASSET SELECTION CHECKS PASSED'); } else { console.log(`${errors.length} FAILURE(S):`, errors.join(', ')); process.exit(1); } })().catch(err => { console.error('Check failed:', err.message); process.exit(1); });