v3.23.4: the event form's numeric option values (v3.22.0 regression)
esc() is string-only, and most EVENT_FORMS option values are numbers
({v:0,l:'Normal service'}, the ACCESSTECH list, ...): the shared event-form
renderer escaped them with esc(o.v), so opening any such event form threw
'str.replace is not a function' - in the Phone tab (pysimEventSendForm) and
the test-script step editor alike (both call the same builder). Introduced
with v3.22.0, when the event action started using the Simulator's forms.
Option values (and the data-gr group) are stringified before escaping, the
pattern the sibling option builder already used; the emitted DOM values are
unchanged ("0", "10").
Test: event_forms.test.js renders every event form (Phone and step-editor
variants) and asserts a numeric option prefills selected - verified to fail
on the pre-fix code. 848 frontend + 830 Python; sw cache simple-v417.
This commit is contained in:
+3
-3
@@ -1905,7 +1905,7 @@
|
|||||||
// ===== Version =====
|
// ===== Version =====
|
||||||
// Single source of truth for the PWA version: shown in the header and used
|
// Single source of truth for the PWA version: shown in the header and used
|
||||||
// by the server version check in pysimConnect().
|
// by the server version check in pysimConnect().
|
||||||
const SIMPLE_VERSION = '3.23.3';
|
const SIMPLE_VERSION = '3.23.4';
|
||||||
document.getElementById('app-version').textContent = 'v' + SIMPLE_VERSION;
|
document.getElementById('app-version').textContent = 'v' + SIMPLE_VERSION;
|
||||||
|
|
||||||
// ===== view history (the browser Back/Forward buttons) =====
|
// ===== view history (the browser Back/Forward buttons) =====
|
||||||
@@ -16157,8 +16157,8 @@ function eventFormFieldsHtml(cfg, fields, values, prefix, withOnchange) {
|
|||||||
html += '<select id="' + prefix + f.id + '"'
|
html += '<select id="' + prefix + f.id + '"'
|
||||||
+ (withOnchange && f.onchange ? ' onchange="' + f.onchange + '"' : '')
|
+ (withOnchange && f.onchange ? ' onchange="' + f.onchange + '"' : '')
|
||||||
+ ' class="w-full border border-gray-300 dark:border-slate-600 text-sm rounded px-2 py-1.5 dark:bg-slate-800">';
|
+ ' class="w-full border border-gray-300 dark:border-slate-600 text-sm rounded px-2 py-1.5 dark:bg-slate-800">';
|
||||||
f.opts.forEach(o => html += '<option value="' + esc(o.v) + '"'
|
f.opts.forEach(o => html += '<option value="' + esc(String(o.v)) + '"'
|
||||||
+ (o.g ? ' data-gr="' + esc(o.g) + '"' : '')
|
+ (o.g ? ' data-gr="' + esc(String(o.g)) + '"' : '')
|
||||||
+ (v !== '' && String(o.v) === v ? ' selected' : '') + '>' + esc(o.l) + '</option>');
|
+ (v !== '' && String(o.v) === v ? ' selected' : '') + '>' + esc(o.l) + '</option>');
|
||||||
html += '</select>';
|
html += '</select>';
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
const CACHE = 'simple-v416';
|
const CACHE = 'simple-v417';
|
||||||
const URLS = [
|
const URLS = [
|
||||||
'index.html',
|
'index.html',
|
||||||
'help.html',
|
'help.html',
|
||||||
|
|||||||
@@ -38,6 +38,8 @@ eval(extractBlock('const EVENT_INNER_MAX = ', 'function pysimEventSendForm').rep
|
|||||||
eval(extractFunc(html, 'eventFieldsForRelease'));
|
eval(extractFunc(html, 'eventFieldsForRelease'));
|
||||||
eval(extractFunc(html, 'encPlmn'));
|
eval(extractFunc(html, 'encPlmn'));
|
||||||
eval(extractFunc(html, 'bytesToHex'));
|
eval(extractFunc(html, 'bytesToHex'));
|
||||||
|
eval(extractFunc(html, 'esc'));
|
||||||
|
eval(extractFunc(html, 'eventFormFieldsHtml'));
|
||||||
|
|
||||||
test('CMD_NAMES decodes timer management and the BIP commands', () => {
|
test('CMD_NAMES decodes timer management and the BIP commands', () => {
|
||||||
assert.strictEqual(CMD_NAMES['01'], 'REFRESH');
|
assert.strictEqual(CMD_NAMES['01'], 'REFRESH');
|
||||||
@@ -344,3 +346,32 @@ test('the shared event vectors match the PWA builders', () => {
|
|||||||
'scts ' + JSON.stringify(v));
|
'scts ' + JSON.stringify(v));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('every event form renders - numeric option values are stringified (v3.23.4)', () => {
|
||||||
|
// esc() is string-only and most EVENT_FORMS option values are numbers
|
||||||
|
// (e.g. {v:0,l:'Normal service'} and the ACCESSTECH list): rendering the
|
||||||
|
// form with esc(o.v) crashed with 'str.replace is not a function' for the
|
||||||
|
// Phone tab and the test-script step editor alike (v3.22.0 regression).
|
||||||
|
globalThis.t = s => s;
|
||||||
|
const bad = [];
|
||||||
|
for (const [ev, cfg] of Object.entries(EVENT_FORMS)) {
|
||||||
|
if (!cfg) continue; // the unimplemented events carry a null form
|
||||||
|
for (const withOnchange of [true, false]) {
|
||||||
|
try {
|
||||||
|
eventFormFieldsHtml(cfg, cfg.fields, {}, 'x-', withOnchange);
|
||||||
|
} catch (e) {
|
||||||
|
bad.push(ev + (withOnchange ? '/phone' : '/step') + ': ' + e.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert.deepStrictEqual(bad, [], 'every event form must render');
|
||||||
|
// a numeric option value lands as its string form and prefills selected
|
||||||
|
const cfg = EVENT_FORMS[0x00];
|
||||||
|
const sel = cfg.fields.find(f => f.type === 'select' && f.opts.some(o => typeof o.v === 'number'));
|
||||||
|
assert.ok(sel, 'a numeric-option select must exist');
|
||||||
|
const num = sel.opts.find(o => typeof o.v === 'number');
|
||||||
|
const out = eventFormFieldsHtml(cfg, cfg.fields, {[sel.id]: num.v}, 'x-', true);
|
||||||
|
assert.ok(out.includes('value="' + String(num.v) + '"'), out);
|
||||||
|
assert.ok(out.includes('value="' + String(num.v) + '" selected'), out);
|
||||||
|
delete globalThis.t;
|
||||||
|
});
|
||||||
|
|||||||
+1
-1
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|||||||
|
|
||||||
[project]
|
[project]
|
||||||
name = "pysim-simple-server"
|
name = "pysim-simple-server"
|
||||||
version = "3.23.3"
|
version = "3.23.4"
|
||||||
description = "HTTP REST server wrapping pysim for the SIMple PWA"
|
description = "HTTP REST server wrapping pysim for the SIMple PWA"
|
||||||
requires-python = ">=3.8"
|
requires-python = ">=3.8"
|
||||||
# pysim is a git-only dependency installed explicitly by setup.bat/setup.sh.
|
# pysim is a git-only dependency installed explicitly by setup.bat/setup.sh.
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ from osmocom.tlv import BER_TLV_IE
|
|||||||
from osmocom.utils import rpad
|
from osmocom.utils import rpad
|
||||||
|
|
||||||
|
|
||||||
VERSION = '3.23.3'
|
VERSION = '3.23.4'
|
||||||
|
|
||||||
MAX_ENVELOPE_SEGMENTS = 5 # max SMS segments for outgoing C-APDU in ENVELOPE
|
MAX_ENVELOPE_SEGMENTS = 5 # max SMS segments for outgoing C-APDU in ENVELOPE
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user