const test = require('node:test'); const assert = require('node:assert/strict'); const fs = require('node:fs'); const vm = require('node:vm'); test('serial alert keyword saves to the shared rule and survives port switching', async () => { const source = fs.readFileSync(require('node:path').join(__dirname, '../frontend/web/static/js/integration.js'), 'utf8'); const fields = { channel: 'CH01' }; const calls = []; let submit, change; const context = { form: () => ({}), value: (_, name) => fields[name] || '', checked: (_, name) => Boolean(fields[name]), setValue: (_, name, value) => { fields[name] = value; }, field: () => ({ addEventListener: (_, fn) => { change = fn; } }), fillAlarmDelivery: () => {}, alarmDelivery: () => ['syslog'], bindForm: (_, fn) => { submit = fn; }, api: async (path, options) => { if (!options) return [{ rule_id: 'port_ch01_keyword', trigger: '(not configured)', enabled: false }]; calls.push({ path, body: options.body }); return {}; } }; vm.createContext(context); await vm.runInContext(source.slice(source.indexOf(' async function alarmSerialEvents()'), source.indexOf(' async function alarmEmailSettings()')) + '\nalarmSerialEvents()', context); assert.equal(fields.keywordValue, ''); fields.keyword = true; await assert.rejects(submit(), /키워드/); assert.equal(calls.length, 0); fields.keywordValue = ' READY> '; await submit(); assert.equal(calls[0].path, '/alarms/rules/port_ch01_keyword'); assert.equal(calls[0].body.trigger, 'READY>'); assert.equal(calls[1].body.trigger, undefined); fields.channel = 'CH02'; change(); assert.equal(fields.keywordValue, ''); fields.channel = 'CH01'; change(); assert.equal(fields.keywordValue, 'READY>'); fields.keyword = false; fields.keywordValue = ''; await submit(); assert.equal(calls[3].body.trigger, ''); });