From 0d46f84ad2f0b1012b38856777f29f7da67c1abf Mon Sep 17 00:00:00 2001 From: AlexanderMitrofanov Date: Mon, 26 Oct 2026 18:27:57 +0100 Subject: [PATCH] fix(gui): decouple browser tests from examples --- ChangeLog | 8 ++++++ scripts/wasm/test-browser.py | 48 ++++++++++++++++++++++++------------ 2 files changed, 40 insertions(+), 16 deletions(-) diff --git a/ChangeLog b/ChangeLog index 54b1340f..cea59293 100644 --- a/ChangeLog +++ b/ChangeLog @@ -14,6 +14,9 @@ ## Interface and handling +- keep real-browser regression inputs stable when maintainers replace the GUI + examples, while continuing to verify that each task's example loads + - refine GUI seed and CSV control widths, filter examples by task, cap result table height and use dark active tabs for additional output views (PR #303 review) @@ -295,6 +298,11 @@ energies, restricted partition sums, and trackers. ################################################################################ ################################################################################ +261026 Alexander Mitrofanov + * scripts/wasm/test-browser.py + * decouple deterministic numerical browser checks from replaceable GUI example + payloads while retaining real-browser coverage of prediction/evaluation loading + 261026 Alexander Mitrofanov * gui/app.js, gui/{index.html,styles.css}, scripts/wasm/test-browser.py * place Explicit seeds beside a half-width Seed constraint selector and halve diff --git a/scripts/wasm/test-browser.py b/scripts/wasm/test-browser.py index 5152f68f..16739c1a 100644 --- a/scripts/wasm/test-browser.py +++ b/scripts/wasm/test-browser.py @@ -41,9 +41,23 @@ def open_group(key): expect(page.locator('#tab-' + key)).to_have_attribute('aria-selected', 'true') assert page.locator('.parameter-group:visible').count() == 1 - def load_example(task='prediction'): + def load_reference(task='prediction'): page.locator('#examples-menu summary').click() - page.get_by_role('button', name='Evaluate a duplex' if task == 'evaluation' else 'Short duplex', exact=False).click() + page.locator(f'#example-options [data-example-task="{task}"]').click() + expect(page.locator('#query')).not_to_have_value('') + expect(page.locator('#target')).not_to_have_value('') + if task == 'evaluation': + expect(page.locator('#rri')).not_to_have_value('') + + # Examples are maintainer-editable content. Exercise their loading, then + # use a fixed small pair so numerical browser regressions stay stable. + page.locator('#reset').click() + if task == 'evaluation': + page.get_by_role('radio', name='Evaluation').check() + page.locator('#query').fill('>query\nGGGAGGAGGG\n') + page.locator('#target').fill('>target\nCCCUCCUCCC\n') + if task == 'evaluation': + page.locator('#rri').fill('1||||||||||&1||||||||||') expect(page.locator('#query')).to_have_value('>query\nGGGAGGAGGG\n') def download_archive(session=None): @@ -90,11 +104,13 @@ def predict(): page.keyboard.press('ArrowLeft') expect(page.get_by_role('radio', name='Prediction')).to_be_checked() page.locator('#examples-menu summary').click() - expect(page.get_by_role('button', name='Short duplex', exact=False)).to_be_visible() - expect(page.get_by_role('button', name='Evaluate a duplex', exact=False)).not_to_be_visible() + prediction_example = page.locator('#example-options [data-example-task="prediction"]') + evaluation_example = page.locator('#example-options [data-example-task="evaluation"]') + expect(prediction_example).to_be_visible() + expect(evaluation_example).not_to_be_visible() page.get_by_role('radio', name='Evaluation').check() - expect(page.get_by_role('button', name='Evaluate a duplex', exact=False)).to_be_visible() - expect(page.get_by_role('button', name='Short duplex', exact=False)).not_to_be_visible() + expect(evaluation_example).to_be_visible() + expect(prediction_example).not_to_be_visible() page.get_by_role('radio', name='Prediction').check() page.locator('#examples-menu summary').click() @@ -229,7 +245,7 @@ def predict(): compute.click() expect(page.locator('#input-error')).to_contain_text('use only') expect(page.locator('#loading')).not_to_be_visible() - load_example() + load_reference() fill('temperature', '101') open_group('sequence-input') compute.click() @@ -238,7 +254,7 @@ def predict(): expect(page.locator('#query')).to_have_value('') expect(page.locator('#target')).to_have_value('') expect(page.locator('#rri')).to_have_value('') - load_example() + load_reference() # Disabled stale edits neither block a run nor leak into JSON. Re-enabling # restores local edits; loading/storing uses effective native settings. @@ -274,7 +290,7 @@ def predict(): page.locator('#qAcc').select_option('C') expect(page.locator('#qShape')).to_have_value('invalid inactive shape') page.locator('#reset').click() - load_example() + load_reference() # Reference prediction, selectable CSV output and independent table visibility. fill('outNumber', 10) @@ -365,7 +381,7 @@ def predict(): page.set_viewport_size({'width': 1440, 'height': 1100}) # Multi-FASTA prediction, signed inclusive output and additional files. - load_example() + load_reference() fill('outNumber', 1) fill('query', '>q1\nGGGAGGAGGG\n>q2\nGGGAGGAGGG') fill('qIdxPos0', -3) @@ -422,7 +438,7 @@ def predict(): fill('rri', '1||||||||||&1||||||||||') compute.click() expect(page.locator('#input-error')).to_contain_text('exactly one') - load_example('evaluation') + load_reference('evaluation') fill('rri', '1||||||||||&1||||||||||:1|||||||||&2|||||||||') open_group('output-options') page.locator('#output-options input[value="detailed"]').check() @@ -462,7 +478,7 @@ def predict(): # Startup and synchronous C++ cancellation both allow a fresh prediction. page.get_by_role('radio', name='Prediction').check() - load_example() + load_reference() held_routes = [] session_count = sessions.count() page.route('**/wasm/intarna.wasm', lambda route: held_routes.append(route)) @@ -481,7 +497,7 @@ def predict(): page.keyboard.press('Escape') expect(status).to_contain_text('aborted') expect(sessions).to_have_count(session_count) - load_example() + load_reference() predict() fill('query', '>no_pairs\nNNNNNNNNNN') @@ -495,7 +511,7 @@ def predict(): assert active.locator('tbody img').count() == 0 assert '