From c3a719ab5dc38c239b1d25bef010222b1b55dbf9 Mon Sep 17 00:00:00 2001 From: Brian Krabach Date: Sun, 17 May 2026 11:38:35 -0700 Subject: [PATCH] chore(release): wire normalize_session_keys + repair stale JS tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Wire normalize_session_keys import and call into _run_poll_cycle step 13b, running before the prune step. Use local device id from muxplex.identity.load_device_id(). Best-effort: errors are logged, poll cycle continues. Fix 10 previously-failing JS tests: - 8 were stale: regex search windows too narrow, refactored implementations, removed UI elements (settings dialog: 4→5 tabs; sessions panel: moved hidden_sessions to Views) - 2 were DOM drift from feature additions Each fix has a code comment explaining the change. Add 3 new end-to-end tests in test_views.py verifying normalize→prune pipeline. Final test counts: pytest 1266 passing (1263 + 3 new), node --test 396 passing. --- muxplex/frontend/tests/test_app.mjs | 85 ++++++++++--------- muxplex/main.py | 23 ++++- muxplex/tests/test_views.py | 127 ++++++++++++++++++++++++++++ 3 files changed, 195 insertions(+), 40 deletions(-) diff --git a/muxplex/frontend/tests/test_app.mjs b/muxplex/frontend/tests/test_app.mjs index 0ef75e4..548a95a 100644 --- a/muxplex/frontend/tests/test_app.mjs +++ b/muxplex/frontend/tests/test_app.mjs @@ -1622,7 +1622,9 @@ test('renderSheetList uses null check for remoteId (not falsy)', () => { // Must use != null check, not truthy check assert.ok(fnBody.includes('remoteId != null') || fnBody.includes('remoteId !== null'), 'renderSheetList must use null check for remoteId (0 is valid)'); - assert.ok(!fnBody.match(/s\.remoteId\s*\?[^=]/), + // Updated in v0.6.0: regex now excludes ?? (nullish coalescing operator) which is + // not a truthy check — [^?=] rejects both ?? and != forms. + assert.ok(!fnBody.match(/s\.remoteId\s*\?[^?=]/), 'renderSheetList must NOT use truthy check for remoteId (0 is falsy)'); }); @@ -2476,8 +2478,9 @@ test('createNewSession polls for session before auto-opening (not immediate setT // Extract the createNewSession function body const start = source.indexOf('async function createNewSession('); assert.ok(start !== -1, 'createNewSession function must exist'); - // Find the end of the function (next function declaration at same indent level) - const snippet = source.slice(start, start + 2000); + // Updated in v0.6.0: snippet size increased from 2000 to 3500 — function grew with + // loading tile injection and auto-add-to-view logic; setInterval is now ~2800 chars in. + const snippet = source.slice(start, start + 3500); // Must NOT contain the old immediate-open pattern inside createNewSession assert.ok( !snippet.includes("setTimeout(() => openSession"), @@ -2736,6 +2739,9 @@ test('_setGridViewMode and renderGroupedGrid are exported', () => { // --- renderFilterBar (task-12) --- test('renderFilterBar produces pill buttons for each device plus All', () => { + // Updated in v0.6.0: renderFilterBar replaced by Views feature — function is now a no-op + // stub kept for export compatibility. The device filtering UI moved to the view dropdown. + // Test now verifies the stub contract: callable without throwing, does not write to container. const collectedHTML = []; const mockContainer = { get innerHTML() { return collectedHTML[0] || ''; }, @@ -2745,23 +2751,19 @@ test('renderFilterBar produces pill buttons for each device plus All', () => { const sessions = [ { name: 'alpha', deviceName: 'Laptop', sessionKey: 'http://local::alpha', snapshot: '' }, { name: 'beta', deviceName: 'Server', sessionKey: 'http://remote::beta', snapshot: '' }, - { name: 'gamma', deviceName: 'Laptop', sessionKey: 'http://local::gamma', snapshot: '' }, ]; app._setActiveFilterDevice('all'); - app.renderFilterBar(mockContainer, sessions); - - const html = mockContainer.innerHTML; - assert.ok(html.includes('All'), 'filter bar should include an "All" button'); - assert.ok(html.includes('Laptop'), 'filter bar should include a pill for "Laptop"'); - assert.ok(html.includes('Server'), 'filter bar should include a pill for "Server"'); - - // Should have exactly 3 buttons: All, Laptop, Server (Laptop appears only once despite two sessions) - const pillCount = (html.match(/