diff --git a/frontend/index.html b/frontend/index.html index 25392c0..840e52a 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -2546,15 +2546,22 @@ async function startCapture() { } } -async function stopCapture() { +// Stopping when nothing is capturing answers 400 ('No active capture'), and +// 403 when capture is disabled — both mean "there is no capture to stop", +// not a failure. +async function stopCaptureIfRunning() { try { await API.stopCapture(); - STATE.captureActive = false; - STATE.currentSessionId = null; - STATE.sessionViewId = null; - updateCaptureButton(); - updateStatus(); - } catch (e) {} + } catch (e) { /* nothing to stop */ } +} + +async function stopCapture() { + await stopCaptureIfRunning(); + STATE.captureActive = false; + STATE.currentSessionId = null; + STATE.sessionViewId = null; + updateCaptureButton(); + updateStatus(); } function updateCaptureButton() { @@ -2891,8 +2898,9 @@ async function confirmComprionImport() { async function loadSession(id) { if (STATE.captureActive && !confirm(t('Opening a session stops the active capture. Continue?'))) return; try { - // Stop any active capture so it can't write into the session being viewed. - await API.stopCapture(); + // Stop any active capture so it can't write into the session being + // viewed (a 400/403 means there is none — not an error). + await stopCaptureIfRunning(); STATE.captureActive = false; STATE.currentSessionId = null; stopPolling(); @@ -3164,7 +3172,7 @@ function onFilterChange() { } // ──────────────────── Versioning ──────────────────── -const PWA_VERSION = '2.4.0'; +const PWA_VERSION = '2.4.1'; const MIN_SERVER_VERSION = '2.3.0'; function parseVersion(v) { diff --git a/frontend/sw.js b/frontend/sw.js index 6c14a72..46b983c 100644 --- a/frontend/sw.js +++ b/frontend/sw.js @@ -1,4 +1,4 @@ -const CACHE = 'simtrace-analyser-v65'; +const CACHE = 'simtrace-analyser-v66'; const PRECACHE = [ 'index.html', diff --git a/frontend/tests/comprion.test.js b/frontend/tests/comprion.test.js index 194a7e1..325ca2b 100644 --- a/frontend/tests/comprion.test.js +++ b/frontend/tests/comprion.test.js @@ -498,3 +498,29 @@ test('Change details modal: header, summary, legend and both views', () => { assert.match(el('file-diff-sub').textContent, /Record 2 \/ 5/); assert.match(el('file-diff-body').innerHTML, /image is frozen/); }); + +// ── Session loading must survive "no active capture" ─────────────────── +eval(extractFunc(src, 'stopCaptureIfRunning')); + +test('stopCaptureIfRunning tolerates "no active capture" (400)', async () => { + let calls = 0; + API.stopCapture = async () => { + calls++; + throw Object.assign(new Error('No active capture'), {status: 400}); + }; + await stopCaptureIfRunning(); // must resolve, not reject + assert.equal(calls, 1); + API.stopCapture = async () => { calls++; }; + await stopCaptureIfRunning(); + assert.equal(calls, 2); +}); + +test('loadSession stops a capture tolerantly', () => { + const body = extractFunc(src, 'loadSession'); + assert.match(body, /await stopCaptureIfRunning\(\)/); + assert.doesNotMatch(body, /await API\.stopCapture\(\)/); + // The capture button also resets its state after a tolerated stop. + const stop = extractFunc(src, 'stopCapture'); + assert.match(stop, /await stopCaptureIfRunning\(\)/); + assert.match(stop, /STATE\.captureActive = false;/); +}); diff --git a/pyproject.toml b/pyproject.toml index b4bf5d7..41276e8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.backends._legacy:_Backend" [project] name = "simtrace-analyser" -version = "2.4.0" +version = "2.4.1" description = "SIMtrace Analyser — APDU trace analyser for GSMTAP/PCAP captures (bundles the simtrace2-pysniff utility)" readme = {file = "README.md", content-type = "text/markdown"} license = {text = "GPL-2.0-or-later"} diff --git a/simtrace_analyser/version.py b/simtrace_analyser/version.py index 2c9091b..e756343 100644 --- a/simtrace_analyser/version.py +++ b/simtrace_analyser/version.py @@ -1,3 +1,3 @@ """Single source of truth for the SIMtrace Analyser version.""" -__version__ = '2.4.0' +__version__ = '2.4.1' diff --git a/tests/test_pcap_import.py b/tests/test_pcap_import.py index 62e8dc7..13748aa 100644 --- a/tests/test_pcap_import.py +++ b/tests/test_pcap_import.py @@ -224,7 +224,7 @@ class TestImportEndpoint(unittest.TestCase): class TestVersion(unittest.TestCase): def test_package_version(self): from simtrace2_pysniff import __version__ - self.assertEqual(__version__, '2.4.0') + self.assertEqual(__version__, '2.4.1') def test_status_includes_version(self): import os