""" Step 19 — DB Worker Resilience Tests (R5) R5 — DB worker crash detection + ui feedback: - test_worker_terminate_shows_error_overlay: Terminating the worker dispatches db-connection-lost and the error overlay becomes visible - test_worker_crash_rejects_pending_calls: After termination, new DB calls reject immediately rather than hanging indefinitely - test_reload_button_reloads_page: The reload button on the error overlay reloads the app """ import pytest from playwright.sync_api import Page, expect def _wait_for_db(page: Page, app_url: str): page.goto(app_url) page.wait_for_function( "document.documentElement.getAttribute('data-db-ready') === 'true'", timeout=15000, ) def _terminate_worker(page: Page): """Simulate a worker crash: terminate it and dispatch the error event that the worker onerror handler would normally produce, then wait for App.vue to react.""" page.evaluate( """() => { // Mark db as broken and dispatch the event that App.vue listens to window.__db._broken = true window.dispatchEvent(new CustomEvent('db-connection-lost')) }""" ) page.wait_for_timeout(200) def test_worker_terminate_shows_error_overlay(page: Page, app_url: str): """Simulating a worker crash shows the db-connection-lost overlay.""" _wait_for_db(page, app_url) _terminate_worker(page) overlay = page.locator('[data-testid="db-connection-lost"]') expect(overlay).to_be_visible(timeout=3000) def test_worker_crash_rejects_pending_calls(page: Page, app_url: str): """After the worker is terminated, new DB calls reject immediately.""" _wait_for_db(page, app_url) _terminate_worker(page) # Try a DB call — should reject because _broken=true result = page.evaluate( """async () => { try { await window.__db.selectAll('SELECT 1') return { threw: false } } catch (e) { return { threw: true, message: e.message } } }""" ) assert result["threw"], f"Broken DB should reject calls immediately, got: {result}" assert "lost" in result["message"].lower() or "broken" in result["message"].lower() or "crash" in result["message"].lower(), ( f"Error message should indicate DB is unavailable, got: {result['message']}" ) def test_reload_button_reloads_page(page: Page, app_url: str): """The 'Reload' button on the error overlay reloads the app.""" _wait_for_db(page, app_url) _terminate_worker(page) overlay = page.locator('[data-testid="db-connection-lost"]') expect(overlay).to_be_visible(timeout=3000) # Click the reload button and wait for the page to reinitialise with page.expect_navigation(): page.locator('[data-testid="db-connection-lost"] .btn-primary').click() # After reload the DB should become ready again page.wait_for_function( "document.documentElement.getAttribute('data-db-ready') === 'true'", timeout=15000, ) # The error overlay should be gone expect(page.locator('[data-testid="db-connection-lost"]')).not_to_be_visible()