v3.23.6: the event name keywords in the test-script editor

A script's `event` value may be a code (a hex byte or a number) or one of the
server's name keywords (location_status, access_tech, network_rejection,
data_connection, ... - events.py's EVENT_NAMES); the API accepts both.  The
PWA parsed every value as a hex string: the step list showed
'EVENT 0xaccess_tech' (the unparsed fallback), the editor fell back to event
03 (Location status) with the location field set, and saving then rewrote
the step to that event - silently corrupting name-authored scripts (the two
Alfa2G trigger scripts use access_tech/data_connection).

A mirrored EVENT_ALIASES map plus an eventCode() resolver (number / hex byte
/ name -> code) now feed the step summary, the editor's event block and the
event check; the summary's fallback no longer prefixes a non-numeric value
with 0x, and the editor keeps its canonical hex form on save (the same code).

Drift guard: the aliases live in frontend/tests/event_vectors.json, asserted
by the Node test (the PWA's map + resolver) and the Python test
(events.EVENT_NAMES + resolve_event).  Tests: 856 frontend + 839 Python;
sw cache simple-v419.
This commit is contained in:
2026-10-07 21:56:20 +03:00
parent 02a78fcca6
commit 9fb46b786f
9 changed files with 110 additions and 11 deletions
+28
View File
@@ -31,6 +31,8 @@ function extractFunc(src, name) {
// Rewrite top-level const -> var so the maps leak out of sloppy-mode eval.
eval(extractBlock('const CMD_NAMES = {', 'function cmdQualifierShort').replace(/^const /gm, 'var '));
eval(extractFunc(html, 'cmdQualifierShort'));
eval(extractBlock('const EVENT_ALIASES = {', 'function eventCode').replace(/^const /gm, 'var '));
eval(extractFunc(html, 'eventCode'));
eval(extractBlock('const EVENT_NAMES = {', 'const REJECTION_CAUSES = [').replace(/^const /gm, 'var '));
eval(extractBlock('const REJECTION_CAUSES = [', 'const EVENT_FORMS = {').replace(/^const /gm, 'var '));
eval(extractBlock('const EVENT_FORMS = {', 'const PLI_QUALIFIERS = [').replace(/^const /gm, 'var '));
@@ -324,12 +326,38 @@ test('the event form previews the bytes the send would deliver', () => {
assert.strictEqual(els['event-send-preview'].value, '');
});
test('a name-keyword event points at the right form', () => {
// the server's name keywords (used by the applet test scripts) resolve to
// their code, so the editor shows the right event and prefills its fields
// instead of falling back to event 03
const cfg = EVENT_FORMS[eventCode('access_tech')];
assert.ok(cfg, 'the access-tech form');
assert.deepStrictEqual(cfg.fields.map(f => f.id), ['tech']);
assert.strictEqual(cfg.build({ tech: 8 }), 'BF0108');
const dc = EVENT_FORMS[eventCode('data_connection')];
assert.ok(dc, 'the data-connection form');
assert.ok(dc.fields.some(f => f.id === 'status') && dc.fields.some(f => f.id === 'type'));
});
test('the shared event vectors match the PWA builders', () => {
// the same fixture is asserted against the Python builders by
// tests/test_events.py - a change on either side fails the other suite
// until the fixture and both implementations agree
const vectors = JSON.parse(fs.readFileSync(path.join(__dirname, 'event_vectors.json'), 'utf8'));
assert.ok(vectors.events.length && vectors.scts.length, 'the fixture must not be empty');
// the event name aliases (the server's keywords) resolve to the codes
assert.ok(vectors.aliases, 'the fixture must carry the aliases');
const wantAliases = {};
for (const [name, hex] of Object.entries(vectors.aliases)) {
wantAliases[name] = parseInt(hex, 16);
assert.strictEqual(eventCode(name), parseInt(hex, 16), name);
}
assert.deepStrictEqual(EVENT_ALIASES, wantAliases);
assert.deepStrictEqual(eventCode(0x0B), 0x0B);
assert.deepStrictEqual(eventCode('0B'), 0x0B);
assert.deepStrictEqual(eventCode('0x1d'), 0x1D);
assert.ok(Number.isNaN(eventCode('nonsense')));
assert.ok(Number.isNaN(eventCode('')));
for (const v of vectors.events) {
const build = EVENT_FORMS[parseInt(v.event, 16)].build;
assert.strictEqual(build(v.fields).toUpperCase(), v.hex,