From 87695df5f7e483db15cdcabbc30af94c5b3ba9dd Mon Sep 17 00:00:00 2001 From: Egor Kostan <20955183+ikostan@users.noreply.github.com> Date: Fri, 14 Aug 2026 21:34:25 -0700 Subject: [PATCH 01/35] Add telemetry hook and normalize handlers Consolidates engine configuration by merging a custom onProgress telemetry hook that logs assembly transfer percent, and initializes Engine with the merged config. Updates the loading UI comment to mention accessibility and normalizes multiple button handler assignments by removing inline comments/formatting. Small refactor/cleanup in custom_shell.html to add telemetry and improve clarity. --- custom_shell.html | 31 +++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/custom_shell.html b/custom_shell.html index adca2787a..9f6052ff9 100644 --- a/custom_shell.html +++ b/custom_shell.html @@ -188,13 +188,24 @@ From 11e2936a56249c9f07d4c36baa33527b08a410cf Mon Sep 17 00:00:00 2001 From: Egor Kostan <20955183+ikostan@users.noreply.github.com> Date: Fri, 14 Aug 2026 21:45:28 -0700 Subject: [PATCH 02/35] Create splash_transition_flow_test.py --- tests/splash_transition_flow_test.py | 168 +++++++++++++++++++++++++++ 1 file changed, 168 insertions(+) create mode 100644 tests/splash_transition_flow_test.py diff --git a/tests/splash_transition_flow_test.py b/tests/splash_transition_flow_test.py new file mode 100644 index 000000000..d750092f3 --- /dev/null +++ b/tests/splash_transition_flow_test.py @@ -0,0 +1,168 @@ +# Copyright (C) 2025-2026 Egor Kostan +# SPDX-License-Identifier: GPL-3.0-or-later +# tests/splash_transition_flow_test.py +""" +Splash Screen Transition & Telemetry Test Suite (Playwright + UI Automation) +============================================================================= + +Overview +-------- +Verifies the asynchronous web loading workflow, custom shell initialization pipeline, +and in-game progress transition mechanics. Eliminates race conditions by validating +orderly handshakes between the DOM layout engine and the WebAssembly runtime graphics context. + +Prerequisites +------------- +- http://localhost:8080/index.html (HTML5 export with preloader & overlays) +- pytest, playwright + +Running +------- +pytest -k splash_transition_flow -q + +Artifacts +--------- +v8_coverage_splash_transition_flow_test.json, artifacts/test_splash_failure_*.png/txt/html +""" + +import json +import os +import time +from typing import Any + +from playwright.sync_api import Page, expect + +from tests.test_utils import DEFAULT_TIMEOUT, TEST_TIMEOUT + + +# DO NOT REFACTOR: Must consume function-scoped `page` to capture preloader & startup telemetry. +def test_splash_transition_flow(page: Page) -> None: + """ + Validates assembly stream metrics, WebGL frame canvas presentation, + and the removal of preloader DOM layers without structural rendering anomalies. + """ + logs: list[dict[str, str]] = [] + page_errors: list[str] = [] + cdp_session = None + + def on_console(msg: Any) -> None: + """Capture all console logs to track runtime lifecycle telemetry.""" + logs.append({"type": msg.type, "text": msg.text}) + + def on_page_error(exc: Any) -> None: + """Capture uncaught runtime errors during engine boot.""" + page_errors.append(f"Uncaught Exception: {exc.message}\n{exc.stack}") + + # Register listeners BEFORE page navigation + page.on("console", on_console) + page.on("pageerror", on_page_error) + + try: + # 1. INITIALIZE V8 PRECISE COVERAGE VIA CDP + cdp_session = page.context.new_cdp_session(page) + cdp_session.send("Profiler.enable") + cdp_session.send( + "Profiler.startPreciseCoverage", {"callCount": True, "detailed": True} + ) + + # 2. MONITOR INITIAL BROWSER LOADING LAYER + page.goto( + "http://localhost:8080/index.html", + wait_until="domcontentloaded", + timeout=DEFAULT_TIMEOUT, + ) + + # Verify custom HTML layout preloader maps instantly to the viewport + loading_overlay = page.locator("#loading") + expect(loading_overlay).to_be_visible(timeout=TEST_TIMEOUT) + + # 3. VERIFY ENGINE INITIALIZATION & RUNTIME TELEMETRY + page.wait_for_function( + "() => window.godotInitialized === true", timeout=DEFAULT_TIMEOUT + ) + + # Confirm the customized configuration object processed data transfers + transfer_logs = [ + log["text"] + for log in logs + if "Telemetry - Assembly Transfer:" in log["text"] + ] + assert ( + len(transfer_logs) > 0 + ), "No 'Telemetry - Assembly Transfer:' telemetry marks captured during load." + + # 4. ASSIGN RENDERING CANVAS HANDSHAKE INVARIANTS + canvas_element = page.locator("#canvas") + expect(canvas_element).to_be_visible(timeout=TEST_TIMEOUT) + assert ( + "SkyLockAssault" in page.title() + ), f"Unexpected page execution title: '{page.title()}'" + + # Verify HTML shell overlay deflates cleanly out of view + expect(loading_overlay).to_be_hidden(timeout=TEST_TIMEOUT) + assert page.evaluate( + "() => document.getElementById('loading').getAttribute('aria-hidden') === 'true'" + ), "Loading container missing aria-hidden='true' post-initialization" + + # 5. AUDIT FATAL PARSING & SCRIPT COMPILATION EXCEPTIONS + critical_faults = [ + log["text"] + for log in logs + if log["type"] == "error" + and not any( + phrase in log["text"].lower() + for phrase in ["encryption aborted", "salt is empty"] + ) + ] + page_errors + + assert ( + len(critical_faults) == 0 + ), f"Critical exceptions found during web handshake:\n" + "\n".join(critical_faults) + + except Exception as e: + print(f"Test: 'test_splash_transition_flow' failed: {e!s}") + os.makedirs("artifacts", exist_ok=True) + timestamp: int = int(time.time()) + + # Isolate diagnostic files on execution crashes + page.screenshot(path=f"artifacts/test_splash_failure_screenshot_{timestamp}.png") + + with open( + f"artifacts/test_splash_failure_console_logs_{timestamp}.txt", + "w", + encoding="utf-8", + ) as f: + f.write("--- CONSOLE LOGS ---\n") + for log in logs: + f.write(f"[{log['type']}] {log['text']}\n") + f.write("\n--- PAGE ERRORS ---\n") + for p_err in page_errors: + f.write(f"{p_err}\n") + + with open( + f"artifacts/test_splash_failure_html_{timestamp}.html", + "w", + encoding="utf-8", + ) as f: + f.write(page.content()) + raise + + finally: + try: + page.remove_listener("console", on_console) + page.remove_listener("pageerror", on_page_error) + except Exception: + pass + + if cdp_session: + try: + coverage = cdp_session.send("Profiler.takePreciseCoverage")["result"] + cdp_session.send("Profiler.stopPreciseCoverage") + cdp_session.send("Profiler.disable") + cdp_session.detach() + with open( + "v8_coverage_splash_transition_flow_test.json", "w", encoding="utf-8" + ) as f: + json.dump(coverage, f) + except Exception as cov_err: + print(f"Warning: Failed to harvest V8 coverage data: {cov_err}") From cafa39656cefcb72e63e2b1facdb8661d147ac65 Mon Sep 17 00:00:00 2001 From: Egor Kostan <20955183+ikostan@users.noreply.github.com> Date: Fri, 14 Aug 2026 21:47:29 -0700 Subject: [PATCH 03/35] Add canvas geometry assertions to splash test tests/splash_transition_flow_test.py: update comment to include GEOMETRY and add assertions verifying canvas_element.bounding_box() is not None and that its width/height are > 0. Ensures the rendering canvas is actually laid out (detects headless/renderer failures) during the splash transition test. --- tests/splash_transition_flow_test.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/tests/splash_transition_flow_test.py b/tests/splash_transition_flow_test.py index d750092f3..c5a27182f 100644 --- a/tests/splash_transition_flow_test.py +++ b/tests/splash_transition_flow_test.py @@ -91,9 +91,15 @@ def on_page_error(exc: Any) -> None: len(transfer_logs) > 0 ), "No 'Telemetry - Assembly Transfer:' telemetry marks captured during load." - # 4. ASSIGN RENDERING CANVAS HANDSHAKE INVARIANTS + # 4. ASSIGN RENDERING CANVAS HANDSHAKE & GEOMETRY INVARIANTS canvas_element = page.locator("#canvas") expect(canvas_element).to_be_visible(timeout=TEST_TIMEOUT) + + canvas_box = canvas_element.bounding_box() + assert canvas_box is not None, "Canvas has no rendered bounding box" + assert canvas_box["width"] > 0, "Canvas rendered width is zero" + assert canvas_box["height"] > 0, "Canvas rendered height is zero" + assert ( "SkyLockAssault" in page.title() ), f"Unexpected page execution title: '{page.title()}'" From 815c46e2bb5d460c1bf613974326af30a7e62e83 Mon Sep 17 00:00:00 2001 From: Egor Kostan <20955183+ikostan@users.noreply.github.com> Date: Fri, 14 Aug 2026 21:50:13 -0700 Subject: [PATCH 04/35] Enhance splash transition telemetry checks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Parse 'Telemetry - Assembly Transfer: X%' marks using regex and assert their presence, bounds (0–100), and monotonic progression. Added re import, improved test docstring and comments, and strengthened canvas/title assertion messages. Added invariant check that window.godotInitialized remains true after overlay teardown. Miscellaneous readability tweaks. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- tests/splash_transition_flow_test.py | 55 ++++++++++++++++++---------- 1 file changed, 35 insertions(+), 20 deletions(-) diff --git a/tests/splash_transition_flow_test.py b/tests/splash_transition_flow_test.py index c5a27182f..f6096d6bc 100644 --- a/tests/splash_transition_flow_test.py +++ b/tests/splash_transition_flow_test.py @@ -8,8 +8,9 @@ Overview -------- Verifies the asynchronous web loading workflow, custom shell initialization pipeline, -and in-game progress transition mechanics. Eliminates race conditions by validating -orderly handshakes between the DOM layout engine and the WebAssembly runtime graphics context. +progressive assembly telemetry, and in-game progress transition mechanics. Eliminates +race conditions by validating orderly handshakes between the DOM layout engine and the +WebAssembly runtime graphics context. Prerequisites ------------- @@ -27,6 +28,7 @@ import json import os +import re import time from typing import Any @@ -38,8 +40,8 @@ # DO NOT REFACTOR: Must consume function-scoped `page` to capture preloader & startup telemetry. def test_splash_transition_flow(page: Page) -> None: """ - Validates assembly stream metrics, WebGL frame canvas presentation, - and the removal of preloader DOM layers without structural rendering anomalies. + Validates assembly stream metrics, progressive telemetry monotonicity, + WebGL frame canvas presentation, and orderly removal of preloader DOM layers. """ logs: list[dict[str, str]] = [] page_errors: list[str] = [] @@ -53,7 +55,7 @@ def on_page_error(exc: Any) -> None: """Capture uncaught runtime errors during engine boot.""" page_errors.append(f"Uncaught Exception: {exc.message}\n{exc.stack}") - # Register listeners BEFORE page navigation + # Register listeners BEFORE navigation to capture early boot telemetry & errors page.on("console", on_console) page.on("pageerror", on_page_error) @@ -81,36 +83,49 @@ def on_page_error(exc: Any) -> None: "() => window.godotInitialized === true", timeout=DEFAULT_TIMEOUT ) - # Confirm the customized configuration object processed data transfers - transfer_logs = [ - log["text"] - for log in logs - if "Telemetry - Assembly Transfer:" in log["text"] - ] + # Parse progressive assembly transfer marks ("Telemetry - Assembly Transfer: X%") + progress_values: list[int] = [] + for log in logs: + match = re.search(r"Telemetry - Assembly Transfer:\s*(\d+)%", log["text"]) + if match: + progress_values.append(int(match.group(1))) + + # Assert telemetry presence, range bounds, and monotonic forward progression assert ( - len(transfer_logs) > 0 - ), "No 'Telemetry - Assembly Transfer:' telemetry marks captured during load." + len(progress_values) > 0 + ), "No 'Telemetry - Assembly Transfer:' marks captured during engine boot." + assert all( + 0 <= val <= 100 for val in progress_values + ), f"Telemetry percentage out of bounds [0, 100]: {progress_values}" + assert ( + progress_values == sorted(progress_values) + ), f"Assembly transfer telemetry did not progress monotonically: {progress_values}" - # 4. ASSIGN RENDERING CANVAS HANDSHAKE & GEOMETRY INVARIANTS + # 4. ASSIGN RENDERING CANVAS HANDSHAKE & STRUCTURAL GEOMETRY canvas_element = page.locator("#canvas") expect(canvas_element).to_be_visible(timeout=TEST_TIMEOUT) canvas_box = canvas_element.bounding_box() - assert canvas_box is not None, "Canvas has no rendered bounding box" - assert canvas_box["width"] > 0, "Canvas rendered width is zero" - assert canvas_box["height"] > 0, "Canvas rendered height is zero" + assert canvas_box is not None, "Canvas element has no rendered bounding box" + assert canvas_box["width"] > 0, "Canvas rendered width is zero (viewport layout failure)" + assert canvas_box["height"] > 0, "Canvas rendered height is zero (viewport layout failure)" assert ( "SkyLockAssault" in page.title() - ), f"Unexpected page execution title: '{page.title()}'" + ), f"Target application title mismatch: '{page.title()}'" - # Verify HTML shell overlay deflates cleanly out of view + # 5. VERIFY DOM TEARDOWN & LIFECYCLE INVARIANTS expect(loading_overlay).to_be_hidden(timeout=TEST_TIMEOUT) assert page.evaluate( "() => document.getElementById('loading').getAttribute('aria-hidden') === 'true'" ), "Loading container missing aria-hidden='true' post-initialization" - # 5. AUDIT FATAL PARSING & SCRIPT COMPILATION EXCEPTIONS + # Invariant: engine initialization state must remain true after overlay teardown + assert page.evaluate( + "() => window.godotInitialized === true" + ), "window.godotInitialized lost its truthy state after splash transition completed" + + # 6. AUDIT FATAL PARSING & SCRIPT COMPILATION EXCEPTIONS critical_faults = [ log["text"] for log in logs From cbcc5ffbc4703abde312f271c11f5c2a495a3bc7 Mon Sep 17 00:00:00 2001 From: "deepsource-autofix[bot]" <62050782+deepsource-autofix[bot]@users.noreply.github.com> Date: Sat, 15 Aug 2026 04:52:18 +0000 Subject: [PATCH 05/35] style: format code with Black and isort This commit fixes the style issues introduced in 815c46e according to the output from Black and isort. Details: https://github.com/ikostan/SkyLockAssault/pull/895 --- tests/splash_transition_flow_test.py | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/tests/splash_transition_flow_test.py b/tests/splash_transition_flow_test.py index f6096d6bc..e4a25d13c 100644 --- a/tests/splash_transition_flow_test.py +++ b/tests/splash_transition_flow_test.py @@ -97,8 +97,8 @@ def on_page_error(exc: Any) -> None: assert all( 0 <= val <= 100 for val in progress_values ), f"Telemetry percentage out of bounds [0, 100]: {progress_values}" - assert ( - progress_values == sorted(progress_values) + assert progress_values == sorted( + progress_values ), f"Assembly transfer telemetry did not progress monotonically: {progress_values}" # 4. ASSIGN RENDERING CANVAS HANDSHAKE & STRUCTURAL GEOMETRY @@ -107,8 +107,12 @@ def on_page_error(exc: Any) -> None: canvas_box = canvas_element.bounding_box() assert canvas_box is not None, "Canvas element has no rendered bounding box" - assert canvas_box["width"] > 0, "Canvas rendered width is zero (viewport layout failure)" - assert canvas_box["height"] > 0, "Canvas rendered height is zero (viewport layout failure)" + assert ( + canvas_box["width"] > 0 + ), "Canvas rendered width is zero (viewport layout failure)" + assert ( + canvas_box["height"] > 0 + ), "Canvas rendered height is zero (viewport layout failure)" assert ( "SkyLockAssault" in page.title() @@ -138,7 +142,9 @@ def on_page_error(exc: Any) -> None: assert ( len(critical_faults) == 0 - ), f"Critical exceptions found during web handshake:\n" + "\n".join(critical_faults) + ), f"Critical exceptions found during web handshake:\n" + "\n".join( + critical_faults + ) except Exception as e: print(f"Test: 'test_splash_transition_flow' failed: {e!s}") @@ -146,7 +152,9 @@ def on_page_error(exc: Any) -> None: timestamp: int = int(time.time()) # Isolate diagnostic files on execution crashes - page.screenshot(path=f"artifacts/test_splash_failure_screenshot_{timestamp}.png") + page.screenshot( + path=f"artifacts/test_splash_failure_screenshot_{timestamp}.png" + ) with open( f"artifacts/test_splash_failure_console_logs_{timestamp}.txt", @@ -182,7 +190,9 @@ def on_page_error(exc: Any) -> None: cdp_session.send("Profiler.disable") cdp_session.detach() with open( - "v8_coverage_splash_transition_flow_test.json", "w", encoding="utf-8" + "v8_coverage_splash_transition_flow_test.json", + "w", + encoding="utf-8", ) as f: json.dump(coverage, f) except Exception as cov_err: From 4b737d937db68d8ce516317ee9c4f47b2c3be7cf Mon Sep 17 00:00:00 2001 From: Egor Kostan <20955183+ikostan@users.noreply.github.com> Date: Fri, 14 Aug 2026 22:00:20 -0700 Subject: [PATCH 06/35] Cleanup & minor fixes in splash_transition_flow_test Reflowed long docstrings/comments and split artifact listing for readability. Tightened logging/assert messages and multiline formatting for regex and function calls. Capture diagnostic paths into variables (screenshot/log/html) before writing. Handle CDP coverage response safely by extracting the "result" key. Overall non-functional cleanup and small robustness improvements to error handling and telemetry parsing. --- tests/splash_transition_flow_test.py | 100 +++++++++++++++++---------- 1 file changed, 62 insertions(+), 38 deletions(-) diff --git a/tests/splash_transition_flow_test.py b/tests/splash_transition_flow_test.py index f6096d6bc..abf942955 100644 --- a/tests/splash_transition_flow_test.py +++ b/tests/splash_transition_flow_test.py @@ -7,10 +7,10 @@ Overview -------- -Verifies the asynchronous web loading workflow, custom shell initialization pipeline, -progressive assembly telemetry, and in-game progress transition mechanics. Eliminates -race conditions by validating orderly handshakes between the DOM layout engine and the -WebAssembly runtime graphics context. +Verifies the asynchronous web loading workflow, custom shell initialization +pipeline, progressive assembly telemetry, and in-game progress transition +mechanics. Eliminates race conditions by validating orderly handshakes +between the DOM layout engine and the WebAssembly runtime graphics context. Prerequisites ------------- @@ -23,7 +23,8 @@ Artifacts --------- -v8_coverage_splash_transition_flow_test.json, artifacts/test_splash_failure_*.png/txt/html +v8_coverage_splash_transition_flow_test.json +artifacts/test_splash_failure_*.png/txt/html """ import json @@ -37,11 +38,12 @@ from tests.test_utils import DEFAULT_TIMEOUT, TEST_TIMEOUT -# DO NOT REFACTOR: Must consume function-scoped `page` to capture preloader & startup telemetry. +# DO NOT REFACTOR: Must consume function-scoped `page` to capture preloader +# and early startup telemetry. def test_splash_transition_flow(page: Page) -> None: """ Validates assembly stream metrics, progressive telemetry monotonicity, - WebGL frame canvas presentation, and orderly removal of preloader DOM layers. + WebGL frame canvas presentation, and orderly removal of preloader DOM. """ logs: list[dict[str, str]] = [] page_errors: list[str] = [] @@ -55,7 +57,7 @@ def on_page_error(exc: Any) -> None: """Capture uncaught runtime errors during engine boot.""" page_errors.append(f"Uncaught Exception: {exc.message}\n{exc.stack}") - # Register listeners BEFORE navigation to capture early boot telemetry & errors + # Register listeners BEFORE navigation to capture early boot telemetry page.on("console", on_console) page.on("pageerror", on_page_error) @@ -64,7 +66,8 @@ def on_page_error(exc: Any) -> None: cdp_session = page.context.new_cdp_session(page) cdp_session.send("Profiler.enable") cdp_session.send( - "Profiler.startPreciseCoverage", {"callCount": True, "detailed": True} + "Profiler.startPreciseCoverage", + {"callCount": True, "detailed": True}, ) # 2. MONITOR INITIAL BROWSER LOADING LAYER @@ -74,41 +77,53 @@ def on_page_error(exc: Any) -> None: timeout=DEFAULT_TIMEOUT, ) - # Verify custom HTML layout preloader maps instantly to the viewport + # Verify custom HTML layout preloader maps instantly to viewport loading_overlay = page.locator("#loading") expect(loading_overlay).to_be_visible(timeout=TEST_TIMEOUT) # 3. VERIFY ENGINE INITIALIZATION & RUNTIME TELEMETRY page.wait_for_function( - "() => window.godotInitialized === true", timeout=DEFAULT_TIMEOUT + "() => window.godotInitialized === true", + timeout=DEFAULT_TIMEOUT, ) - # Parse progressive assembly transfer marks ("Telemetry - Assembly Transfer: X%") + # Parse progressive assembly transfer marks + # Format: "Telemetry - Assembly Transfer: X%" progress_values: list[int] = [] for log in logs: - match = re.search(r"Telemetry - Assembly Transfer:\s*(\d+)%", log["text"]) + match = re.search( + r"Telemetry - Assembly Transfer:\s*(\d+)%", + log["text"], + ) if match: progress_values.append(int(match.group(1))) - # Assert telemetry presence, range bounds, and monotonic forward progression + # Assert telemetry presence, range bounds, and progression assert ( len(progress_values) > 0 - ), "No 'Telemetry - Assembly Transfer:' marks captured during engine boot." + ), "No 'Telemetry - Assembly Transfer:' marks captured during load." assert all( 0 <= val <= 100 for val in progress_values ), f"Telemetry percentage out of bounds [0, 100]: {progress_values}" - assert ( - progress_values == sorted(progress_values) - ), f"Assembly transfer telemetry did not progress monotonically: {progress_values}" + assert progress_values == sorted(progress_values), ( + "Assembly transfer telemetry did not progress monotonically: " + f"{progress_values}" + ) # 4. ASSIGN RENDERING CANVAS HANDSHAKE & STRUCTURAL GEOMETRY canvas_element = page.locator("#canvas") expect(canvas_element).to_be_visible(timeout=TEST_TIMEOUT) canvas_box = canvas_element.bounding_box() - assert canvas_box is not None, "Canvas element has no rendered bounding box" - assert canvas_box["width"] > 0, "Canvas rendered width is zero (viewport layout failure)" - assert canvas_box["height"] > 0, "Canvas rendered height is zero (viewport layout failure)" + assert ( + canvas_box is not None + ), "Canvas element has no rendered bounding box" + assert ( + canvas_box["width"] > 0 + ), "Canvas rendered width is zero (viewport layout failure)" + assert ( + canvas_box["height"] > 0 + ), "Canvas rendered height is zero (viewport layout failure)" assert ( "SkyLockAssault" in page.title() @@ -117,13 +132,17 @@ def on_page_error(exc: Any) -> None: # 5. VERIFY DOM TEARDOWN & LIFECYCLE INVARIANTS expect(loading_overlay).to_be_hidden(timeout=TEST_TIMEOUT) assert page.evaluate( - "() => document.getElementById('loading').getAttribute('aria-hidden') === 'true'" + "() => document.getElementById('loading')" + ".getAttribute('aria-hidden') === 'true'" ), "Loading container missing aria-hidden='true' post-initialization" - # Invariant: engine initialization state must remain true after overlay teardown + # Invariant: engine initialization state persists after overlay teardown assert page.evaluate( "() => window.godotInitialized === true" - ), "window.godotInitialized lost its truthy state after splash transition completed" + ), ( + "window.godotInitialized lost its truthy state after splash " + "transition completed" + ) # 6. AUDIT FATAL PARSING & SCRIPT COMPILATION EXCEPTIONS critical_faults = [ @@ -138,7 +157,10 @@ def on_page_error(exc: Any) -> None: assert ( len(critical_faults) == 0 - ), f"Critical exceptions found during web handshake:\n" + "\n".join(critical_faults) + ), ( + "Critical exceptions found during web handshake:\n" + + "\n".join(critical_faults) + ) except Exception as e: print(f"Test: 'test_splash_transition_flow' failed: {e!s}") @@ -146,13 +168,15 @@ def on_page_error(exc: Any) -> None: timestamp: int = int(time.time()) # Isolate diagnostic files on execution crashes - page.screenshot(path=f"artifacts/test_splash_failure_screenshot_{timestamp}.png") + screenshot_path = ( + f"artifacts/test_splash_failure_screenshot_{timestamp}.png" + ) + page.screenshot(path=screenshot_path) - with open( - f"artifacts/test_splash_failure_console_logs_{timestamp}.txt", - "w", - encoding="utf-8", - ) as f: + logs_path = ( + f"artifacts/test_splash_failure_console_logs_{timestamp}.txt" + ) + with open(logs_path, "w", encoding="utf-8") as f: f.write("--- CONSOLE LOGS ---\n") for log in logs: f.write(f"[{log['type']}] {log['text']}\n") @@ -160,11 +184,8 @@ def on_page_error(exc: Any) -> None: for p_err in page_errors: f.write(f"{p_err}\n") - with open( - f"artifacts/test_splash_failure_html_{timestamp}.html", - "w", - encoding="utf-8", - ) as f: + html_path = f"artifacts/test_splash_failure_html_{timestamp}.html" + with open(html_path, "w", encoding="utf-8") as f: f.write(page.content()) raise @@ -177,12 +198,15 @@ def on_page_error(exc: Any) -> None: if cdp_session: try: - coverage = cdp_session.send("Profiler.takePreciseCoverage")["result"] + coverage_res = cdp_session.send("Profiler.takePreciseCoverage") + coverage = coverage_res["result"] cdp_session.send("Profiler.stopPreciseCoverage") cdp_session.send("Profiler.disable") cdp_session.detach() with open( - "v8_coverage_splash_transition_flow_test.json", "w", encoding="utf-8" + "v8_coverage_splash_transition_flow_test.json", + "w", + encoding="utf-8", ) as f: json.dump(coverage, f) except Exception as cov_err: From 08b0354fe16992a1370707b720abaef738ab465e Mon Sep 17 00:00:00 2001 From: "coderabbitai[bot]" <136622811+coderabbitai[bot]@users.noreply.github.com> Date: Sat, 15 Aug 2026 05:00:55 +0000 Subject: [PATCH 07/35] CodeRabbit Generated Unit Tests: Add Generated Unit Tests for PR Changes --- tests/splash_transition_flow_test.py | 431 +++++++++++++++++++++++++++ 1 file changed, 431 insertions(+) create mode 100644 tests/splash_transition_flow_test.py diff --git a/tests/splash_transition_flow_test.py b/tests/splash_transition_flow_test.py new file mode 100644 index 000000000..01982ea63 --- /dev/null +++ b/tests/splash_transition_flow_test.py @@ -0,0 +1,431 @@ +# Copyright (C) 2025-2026 Egor Kostan +# SPDX-License-Identifier: GPL-3.0-or-later +# tests/splash_transition_flow_test.py +""" +Splash Screen Transition & Telemetry Test Suite (Playwright + UI Automation) +============================================================================= + +Overview +-------- +Verifies the asynchronous web loading workflow, custom shell initialization pipeline, +progressive assembly telemetry, and in-game progress transition mechanics. Eliminates +race conditions by validating orderly handshakes between the DOM layout engine and the +WebAssembly runtime graphics context. + +Prerequisites +------------- +- http://localhost:8080/index.html (HTML5 export with preloader & overlays) +- pytest, playwright + +Running +------- +pytest -k splash_transition_flow -q + +Artifacts +--------- +v8_coverage_splash_transition_flow_test.json, artifacts/test_splash_failure_*.png/txt/html +""" + +import json +import os +import re +import time +from pathlib import Path +from typing import Any + +from playwright.sync_api import Page, expect + +from tests.test_utils import DEFAULT_TIMEOUT, TEST_TIMEOUT + + +# DO NOT REFACTOR: Must consume function-scoped `page` to capture preloader & startup telemetry. +def test_splash_transition_flow(page: Page) -> None: + """ + Validates assembly stream metrics, progressive telemetry monotonicity, + WebGL frame canvas presentation, and orderly removal of preloader DOM layers. + """ + logs: list[dict[str, str]] = [] + page_errors: list[str] = [] + cdp_session = None + + def on_console(msg: Any) -> None: + """Capture all console logs to track runtime lifecycle telemetry.""" + logs.append({"type": msg.type, "text": msg.text}) + + def on_page_error(exc: Any) -> None: + """Capture uncaught runtime errors during engine boot.""" + page_errors.append(f"Uncaught Exception: {exc.message}\n{exc.stack}") + + # Register listeners BEFORE navigation to capture early boot telemetry & errors + page.on("console", on_console) + page.on("pageerror", on_page_error) + + try: + # 1. INITIALIZE V8 PRECISE COVERAGE VIA CDP + cdp_session = page.context.new_cdp_session(page) + cdp_session.send("Profiler.enable") + cdp_session.send( + "Profiler.startPreciseCoverage", {"callCount": True, "detailed": True} + ) + + # 2. MONITOR INITIAL BROWSER LOADING LAYER + page.goto( + "http://localhost:8080/index.html", + wait_until="domcontentloaded", + timeout=DEFAULT_TIMEOUT, + ) + + # Verify custom HTML layout preloader maps instantly to the viewport + loading_overlay = page.locator("#loading") + expect(loading_overlay).to_be_visible(timeout=TEST_TIMEOUT) + + # 3. VERIFY ENGINE INITIALIZATION & RUNTIME TELEMETRY + page.wait_for_function( + "() => window.godotInitialized === true", timeout=DEFAULT_TIMEOUT + ) + + # Parse progressive assembly transfer marks ("Telemetry - Assembly Transfer: X%") + progress_values: list[int] = [] + for log in logs: + match = re.search(r"Telemetry - Assembly Transfer:\s*(\d+)%", log["text"]) + if match: + progress_values.append(int(match.group(1))) + + # Assert telemetry presence, range bounds, and monotonic forward progression + assert ( + len(progress_values) > 0 + ), "No 'Telemetry - Assembly Transfer:' marks captured during engine boot." + assert all( + 0 <= val <= 100 for val in progress_values + ), f"Telemetry percentage out of bounds [0, 100]: {progress_values}" + assert progress_values == sorted( + progress_values + ), f"Assembly transfer telemetry did not progress monotonically: {progress_values}" + + # 4. ASSIGN RENDERING CANVAS HANDSHAKE & STRUCTURAL GEOMETRY + canvas_element = page.locator("#canvas") + expect(canvas_element).to_be_visible(timeout=TEST_TIMEOUT) + + canvas_box = canvas_element.bounding_box() + assert canvas_box is not None, "Canvas element has no rendered bounding box" + assert ( + canvas_box["width"] > 0 + ), "Canvas rendered width is zero (viewport layout failure)" + assert ( + canvas_box["height"] > 0 + ), "Canvas rendered height is zero (viewport layout failure)" + + assert ( + "SkyLockAssault" in page.title() + ), f"Target application title mismatch: '{page.title()}'" + + # 5. VERIFY DOM TEARDOWN & LIFECYCLE INVARIANTS + expect(loading_overlay).to_be_hidden(timeout=TEST_TIMEOUT) + assert page.evaluate( + "() => document.getElementById('loading').getAttribute('aria-hidden') === 'true'" + ), "Loading container missing aria-hidden='true' post-initialization" + + # Invariant: engine initialization state must remain true after overlay teardown + assert page.evaluate( + "() => window.godotInitialized === true" + ), "window.godotInitialized lost its truthy state after splash transition completed" + + # 6. AUDIT FATAL PARSING & SCRIPT COMPILATION EXCEPTIONS + critical_faults = [ + log["text"] + for log in logs + if log["type"] == "error" + and not any( + phrase in log["text"].lower() + for phrase in ["encryption aborted", "salt is empty"] + ) + ] + page_errors + + assert ( + len(critical_faults) == 0 + ), f"Critical exceptions found during web handshake:\n" + "\n".join( + critical_faults + ) + + except Exception as e: + print(f"Test: 'test_splash_transition_flow' failed: {e!s}") + os.makedirs("artifacts", exist_ok=True) + timestamp: int = int(time.time()) + + # Isolate diagnostic files on execution crashes + page.screenshot( + path=f"artifacts/test_splash_failure_screenshot_{timestamp}.png" + ) + + with open( + f"artifacts/test_splash_failure_console_logs_{timestamp}.txt", + "w", + encoding="utf-8", + ) as f: + f.write("--- CONSOLE LOGS ---\n") + for log in logs: + f.write(f"[{log['type']}] {log['text']}\n") + f.write("\n--- PAGE ERRORS ---\n") + for p_err in page_errors: + f.write(f"{p_err}\n") + + with open( + f"artifacts/test_splash_failure_html_{timestamp}.html", + "w", + encoding="utf-8", + ) as f: + f.write(page.content()) + raise + + finally: + try: + page.remove_listener("console", on_console) + page.remove_listener("pageerror", on_page_error) + except Exception: + pass + + if cdp_session: + try: + coverage = cdp_session.send("Profiler.takePreciseCoverage")["result"] + cdp_session.send("Profiler.stopPreciseCoverage") + cdp_session.send("Profiler.disable") + cdp_session.detach() + with open( + "v8_coverage_splash_transition_flow_test.json", + "w", + encoding="utf-8", + ) as f: + json.dump(coverage, f) + except Exception as cov_err: + print(f"Warning: Failed to harvest V8 coverage data: {cov_err}") + + +# --------------------------------------------------------------------------- +# Unit tests for the `onProgress` telemetry callback introduced in +# custom_shell.html. These tests extract the real callback source verbatim +# (via brace-matching, not a hardcoded copy) and exercise it in an isolated +# JS context, independent of the Godot WASM boot flow / dev server. +# --------------------------------------------------------------------------- + +_CUSTOM_SHELL_PATH = Path(__file__).resolve().parents[1] / "custom_shell.html" +_ON_PROGRESS_MARKER = "onProgress: function(current, total)" + + +def _read_custom_shell_source() -> str: + """Reads the raw custom_shell.html source from the repository root.""" + return _CUSTOM_SHELL_PATH.read_text(encoding="utf-8") + + +def _extract_on_progress_function_source() -> str: + """Extracts the `onProgress` telemetry callback verbatim from custom_shell.html. + + Uses brace counting (rather than a fixed-indentation regex) so extraction + keeps working even if the surrounding code is reformatted or re-indented. + """ + html = _read_custom_shell_source() + + try: + marker_idx = html.index(_ON_PROGRESS_MARKER) + except ValueError as exc: + raise AssertionError( + "onProgress telemetry handler not found in custom_shell.html; " + "source may have changed shape" + ) from exc + + brace_start = html.index("{", marker_idx) + depth = 0 + idx = brace_start + while idx < len(html): + if html[idx] == "{": + depth += 1 + elif html[idx] == "}": + depth -= 1 + if depth == 0: + break + idx += 1 + else: + raise AssertionError( + "Could not find matching closing brace for onProgress function body" + ) + + body = html[brace_start : idx + 1] + return f"function(current, total) {body}" + + +def _run_on_progress(page: Page, fn_source: str, calls: list[tuple[int, int]]) -> list[str]: + """Evaluates the extracted onProgress function against a series of + (current, total) calls and returns every console.log message it emitted. + """ + return page.evaluate( + """([fnSource, calls]) => { + const onProgress = new Function('return (' + fnSource + ')')(); + const outputs = []; + const originalLog = console.log; + console.log = (msg) => { outputs.push(msg); }; + try { + for (const [current, total] of calls) { + onProgress(current, total); + } + } finally { + console.log = originalLog; + } + return outputs; + }""", + [fn_source, calls], + ) + + +def test_on_progress_telemetry_math_is_correct(page: Page) -> None: + """ + Unit-tests the `onProgress` telemetry callback added to custom_shell.html + in isolation, locking down its percentage math independently of the full + Godot WASM boot flow exercised by `test_splash_transition_flow`. + """ + fn_source = _extract_on_progress_function_source() + + outputs = _run_on_progress( + page, fn_source, [(0, 200), (50, 200), (100, 200), (200, 200)] + ) + + assert outputs == [ + "Telemetry - Assembly Transfer: 0%", + "Telemetry - Assembly Transfer: 25%", + "Telemetry - Assembly Transfer: 50%", + "Telemetry - Assembly Transfer: 100%", + ] + + +def test_on_progress_floors_fractional_percentages(page: Page) -> None: + """Regression test: fractional percentages must be floored, not rounded.""" + fn_source = _extract_on_progress_function_source() + + outputs = _run_on_progress( + page, + fn_source, + [ + (1, 3), # 33.33...% -> must floor to 33%, not round to 33% or 34% + (2, 3), # 66.66...% -> must floor to 66%, not round to 67% + (99, 100), # 99% exactly + ], + ) + + assert outputs == [ + "Telemetry - Assembly Transfer: 33%", + "Telemetry - Assembly Transfer: 66%", + "Telemetry - Assembly Transfer: 99%", + ] + + +def test_on_progress_skips_logging_when_total_is_zero(page: Page) -> None: + """ + Edge case: onProgress must not emit any telemetry (or divide by zero, + producing NaN/Infinity) when `total` is 0. This guards the + `if (total > 0)` check in the callback. + """ + fn_source = _extract_on_progress_function_source() + + outputs = _run_on_progress(page, fn_source, [(0, 0), (5, 0)]) + + assert outputs == [], f"Expected no telemetry logs when total is 0, got: {outputs}" + + +def test_on_progress_message_format_matches_expected_pattern(page: Page) -> None: + """ + Regression test: the emitted telemetry text must match the exact + "Telemetry - Assembly Transfer: %" format that + `test_splash_transition_flow` parses with a regular expression. + """ + fn_source = _extract_on_progress_function_source() + + outputs = _run_on_progress(page, fn_source, [(37, 41)]) + + assert len(outputs) == 1 + assert re.fullmatch( + r"Telemetry - Assembly Transfer: \d+%", outputs[0] + ), f"Unexpected telemetry message format: {outputs[0]!r}" + + +# --------------------------------------------------------------------------- +# Additional integration-level checks against the live Godot HTML5 export, +# complementing the monotonicity/bounds assertions already covered by +# `test_splash_transition_flow`. +# --------------------------------------------------------------------------- + + +def test_splash_transition_flow_progress_reaches_completion(page: Page) -> None: + """ + Regression test: telemetry must not merely progress monotonically, it must + actually approach completion (>=90%) by the time the engine reports + itself initialized, guarding against a stalled/truncated progress stream. + """ + logs: list[dict[str, str]] = [] + + def on_console(msg: Any) -> None: + logs.append({"type": msg.type, "text": msg.text}) + + page.on("console", on_console) + + try: + page.goto( + "http://localhost:8080/index.html", + wait_until="domcontentloaded", + timeout=DEFAULT_TIMEOUT, + ) + page.wait_for_function( + "() => window.godotInitialized === true", timeout=DEFAULT_TIMEOUT + ) + + progress_values: list[int] = [] + for log in logs: + match = re.search(r"Telemetry - Assembly Transfer:\s*(\d+)%", log["text"]) + if match: + progress_values.append(int(match.group(1))) + + assert progress_values, "No telemetry captured during engine boot." + assert max(progress_values) >= 90, ( + "Assembly transfer telemetry never approached completion before " + f"godotInitialized became true: {progress_values}" + ) + finally: + try: + page.remove_listener("console", on_console) + except Exception: + pass + + +def test_splash_transition_flow_no_malformed_telemetry_values(page: Page) -> None: + """ + Negative test: guards against malformed telemetry (e.g. "NaN%" or + "Infinity%") that would appear if the `total > 0` division-by-zero guard + in the onProgress callback were ever removed or broken. + """ + logs: list[dict[str, str]] = [] + + def on_console(msg: Any) -> None: + logs.append({"type": msg.type, "text": msg.text}) + + page.on("console", on_console) + + try: + page.goto( + "http://localhost:8080/index.html", + wait_until="domcontentloaded", + timeout=DEFAULT_TIMEOUT, + ) + page.wait_for_function( + "() => window.godotInitialized === true", timeout=DEFAULT_TIMEOUT + ) + + malformed = [ + log["text"] + for log in logs + if "Telemetry - Assembly Transfer:" in log["text"] + and not re.search(r"Telemetry - Assembly Transfer:\s*\d+%$", log["text"]) + ] + + assert malformed == [], f"Malformed telemetry entries found: {malformed}" + finally: + try: + page.remove_listener("console", on_console) + except Exception: + pass From 2207cf9b0c0359bcaa0a444414eb244e6d1b57c5 Mon Sep 17 00:00:00 2001 From: "deepsource-autofix[bot]" <62050782+deepsource-autofix[bot]@users.noreply.github.com> Date: Sat, 15 Aug 2026 05:01:49 +0000 Subject: [PATCH 08/35] style: format code with Black and isort This commit fixes the style issues introduced in 08b0354 according to the output from Black and isort. Details: https://github.com/ikostan/SkyLockAssault/pull/896 --- tests/splash_transition_flow_test.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/splash_transition_flow_test.py b/tests/splash_transition_flow_test.py index 01982ea63..d8f988f1a 100644 --- a/tests/splash_transition_flow_test.py +++ b/tests/splash_transition_flow_test.py @@ -252,7 +252,9 @@ def _extract_on_progress_function_source() -> str: return f"function(current, total) {body}" -def _run_on_progress(page: Page, fn_source: str, calls: list[tuple[int, int]]) -> list[str]: +def _run_on_progress( + page: Page, fn_source: str, calls: list[tuple[int, int]] +) -> list[str]: """Evaluates the extracted onProgress function against a series of (current, total) calls and returns every console.log message it emitted. """ From ea8467fa0779a6bc0869cb60c81a987b65cddc6e Mon Sep 17 00:00:00 2001 From: "deepsource-autofix[bot]" <62050782+deepsource-autofix[bot]@users.noreply.github.com> Date: Sat, 15 Aug 2026 05:02:17 +0000 Subject: [PATCH 09/35] style: format code with Black and isort This commit fixes the style issues introduced in c3015ff according to the output from Black and isort. Details: https://github.com/ikostan/SkyLockAssault/pull/895 --- tests/splash_transition_flow_test.py | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/tests/splash_transition_flow_test.py b/tests/splash_transition_flow_test.py index f04f66379..5a1e0d375 100644 --- a/tests/splash_transition_flow_test.py +++ b/tests/splash_transition_flow_test.py @@ -110,7 +110,6 @@ def on_page_error(exc: Any) -> None: f"{progress_values}" ) - # 4. ASSIGN RENDERING CANVAS HANDSHAKE & STRUCTURAL GEOMETRY canvas_element = page.locator("#canvas") expect(canvas_element).to_be_visible(timeout=TEST_TIMEOUT) @@ -137,9 +136,7 @@ def on_page_error(exc: Any) -> None: ), "Loading container missing aria-hidden='true' post-initialization" # Invariant: engine initialization state persists after overlay teardown - assert page.evaluate( - "() => window.godotInitialized === true" - ), ( + assert page.evaluate("() => window.godotInitialized === true"), ( "window.godotInitialized lost its truthy state after splash " "transition completed" ) @@ -157,10 +154,8 @@ def on_page_error(exc: Any) -> None: assert ( len(critical_faults) == 0 - ), ( - "Critical exceptions found during web handshake:\n" - + "\n".join(critical_faults) - + ), "Critical exceptions found during web handshake:\n" + "\n".join( + critical_faults ) except Exception as e: @@ -173,10 +168,7 @@ def on_page_error(exc: Any) -> None: path=f"artifacts/test_splash_failure_screenshot_{timestamp}.png" ) - - logs_path = ( - f"artifacts/test_splash_failure_console_logs_{timestamp}.txt" - ) + logs_path = f"artifacts/test_splash_failure_console_logs_{timestamp}.txt" with open(logs_path, "w", encoding="utf-8") as f: f.write("--- CONSOLE LOGS ---\n") for log in logs: From 2e216027b90af28df376a3121b20ee2f56c24412 Mon Sep 17 00:00:00 2001 From: "deepsource-autofix[bot]" <62050782+deepsource-autofix[bot]@users.noreply.github.com> Date: Sat, 15 Aug 2026 05:08:55 +0000 Subject: [PATCH 10/35] style: format code with Black and isort This commit fixes the style issues introduced in 7d70c5b according to the output from Black and isort. Details: https://github.com/ikostan/SkyLockAssault/pull/896 --- tests/splash_transition_flow_test.py | 21 ++++++--------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/tests/splash_transition_flow_test.py b/tests/splash_transition_flow_test.py index 9837df253..f5798bd7d 100644 --- a/tests/splash_transition_flow_test.py +++ b/tests/splash_transition_flow_test.py @@ -221,9 +221,7 @@ def on_page_error(exc: Any) -> None: log["text"] for log in logs if "Telemetry - Assembly Transfer:" in log["text"] - and not re.search( - r"Telemetry - Assembly Transfer:\s*\d+%$", log["text"] - ) + and not re.search(r"Telemetry - Assembly Transfer:\s*\d+%$", log["text"]) ] assert malformed == [], f"Malformed telemetry entries: {malformed}" @@ -232,9 +230,7 @@ def on_page_error(exc: Any) -> None: expect(canvas_element).to_be_visible(timeout=TEST_TIMEOUT) canvas_box = canvas_element.bounding_box() - assert ( - canvas_box is not None - ), "Canvas element has no rendered bounding box" + assert canvas_box is not None, "Canvas element has no rendered bounding box" assert ( canvas_box["width"] > 0 ), "Canvas rendered width is zero (viewport layout failure)" @@ -270,9 +266,8 @@ def on_page_error(exc: Any) -> None: assert ( len(critical_faults) == 0 - ), ( - "Critical exceptions found during web handshake:\n" - + "\n".join(critical_faults) + ), "Critical exceptions found during web handshake:\n" + "\n".join( + critical_faults ) except Exception as e: @@ -280,14 +275,10 @@ def on_page_error(exc: Any) -> None: os.makedirs("artifacts", exist_ok=True) timestamp: int = int(time.time()) - screenshot_path = ( - f"artifacts/test_splash_failure_screenshot_{timestamp}.png" - ) + screenshot_path = f"artifacts/test_splash_failure_screenshot_{timestamp}.png" page.screenshot(path=screenshot_path) - logs_path = ( - f"artifacts/test_splash_failure_console_logs_{timestamp}.txt" - ) + logs_path = f"artifacts/test_splash_failure_console_logs_{timestamp}.txt" with open(logs_path, "w", encoding="utf-8") as f: f.write("--- CONSOLE LOGS ---\n") for log in logs: From d419aa4718e13291a8a305e9a8ad17d58aa23db6 Mon Sep 17 00:00:00 2001 From: Egor Kostan <20955183+ikostan@users.noreply.github.com> Date: Fri, 14 Aug 2026 22:13:45 -0700 Subject: [PATCH 11/35] Use test_utils for coverage and artifacts in splash test Replace manual CDP coverage setup/harvest with init_cdp_coverage/save_v8_coverage from tests.test_utils. Use ARTIFACTS_DIR for writing failure logs and HTML, remove unused json/os imports, and rely on conftest for screenshots/videos. Minor formatting and assertion cleanups and improved error artifact paths for consistent test artifact handling. --- tests/splash_transition_flow_test.py | 72 +++++++++++----------------- 1 file changed, 29 insertions(+), 43 deletions(-) diff --git a/tests/splash_transition_flow_test.py b/tests/splash_transition_flow_test.py index f5798bd7d..fec7bb0ce 100644 --- a/tests/splash_transition_flow_test.py +++ b/tests/splash_transition_flow_test.py @@ -20,15 +20,8 @@ Running ------- pytest -k splash_transition_flow -q - -Artifacts ---------- -v8_coverage_splash_transition_flow_test.json -artifacts/test_splash_failure_*.png/txt/html """ -import json -import os import re import time from pathlib import Path @@ -36,7 +29,13 @@ from playwright.sync_api import Page, expect -from tests.test_utils import DEFAULT_TIMEOUT, TEST_TIMEOUT +from tests.test_utils import ( + ARTIFACTS_DIR, + DEFAULT_TIMEOUT, + TEST_TIMEOUT, + init_cdp_coverage, + save_v8_coverage, +) _CUSTOM_SHELL_PATH = Path(__file__).resolve().parents[1] / "custom_shell.html" _ON_PROGRESS_MARKER = "onProgress: function(current, total)" @@ -153,7 +152,6 @@ def test_splash_transition_flow(page: Page) -> None: """ logs: list[dict[str, str]] = [] page_errors: list[str] = [] - cdp_session = None def on_console(msg: Any) -> None: """Capture all console logs to track runtime lifecycle telemetry.""" @@ -166,15 +164,10 @@ def on_page_error(exc: Any) -> None: page.on("console", on_console) page.on("pageerror", on_page_error) - try: - # 1. INITIALIZE V8 PRECISE COVERAGE VIA CDP - cdp_session = page.context.new_cdp_session(page) - cdp_session.send("Profiler.enable") - cdp_session.send( - "Profiler.startPreciseCoverage", - {"callCount": True, "detailed": True}, - ) + # 1. INITIALIZE V8 PRECISE COVERAGE VIA TEST_UTILS + cdp_session, _ = init_cdp_coverage(page) + try: # 2. MONITOR INITIAL BROWSER LOADING LAYER page.goto( "http://localhost:8080/index.html", @@ -221,7 +214,9 @@ def on_page_error(exc: Any) -> None: log["text"] for log in logs if "Telemetry - Assembly Transfer:" in log["text"] - and not re.search(r"Telemetry - Assembly Transfer:\s*\d+%$", log["text"]) + and not re.search( + r"Telemetry - Assembly Transfer:\s*\d+%$", log["text"] + ) ] assert malformed == [], f"Malformed telemetry entries: {malformed}" @@ -230,7 +225,9 @@ def on_page_error(exc: Any) -> None: expect(canvas_element).to_be_visible(timeout=TEST_TIMEOUT) canvas_box = canvas_element.bounding_box() - assert canvas_box is not None, "Canvas element has no rendered bounding box" + assert ( + canvas_box is not None + ), "Canvas element has no rendered bounding box" assert ( canvas_box["width"] > 0 ), "Canvas rendered width is zero (viewport layout failure)" @@ -266,19 +263,19 @@ def on_page_error(exc: Any) -> None: assert ( len(critical_faults) == 0 - ), "Critical exceptions found during web handshake:\n" + "\n".join( - critical_faults + ), ( + "Critical exceptions found during web handshake:\n" + + "\n".join(critical_faults) ) except Exception as e: print(f"Test: 'test_splash_transition_flow' failed: {e!s}") - os.makedirs("artifacts", exist_ok=True) - timestamp: int = int(time.time()) - - screenshot_path = f"artifacts/test_splash_failure_screenshot_{timestamp}.png" - page.screenshot(path=screenshot_path) + timestamp = int(time.time()) - logs_path = f"artifacts/test_splash_failure_console_logs_{timestamp}.txt" + # Save test-specific log and HTML dumps (screenshot/video handled by conftest) + logs_path = ( + ARTIFACTS_DIR / f"test_splash_failure_logs_{timestamp}.txt" + ) with open(logs_path, "w", encoding="utf-8") as f: f.write("--- CONSOLE LOGS ---\n") for log in logs: @@ -287,7 +284,9 @@ def on_page_error(exc: Any) -> None: for p_err in page_errors: f.write(f"{p_err}\n") - html_path = f"artifacts/test_splash_failure_html_{timestamp}.html" + html_path = ( + ARTIFACTS_DIR / f"test_splash_failure_html_{timestamp}.html" + ) with open(html_path, "w", encoding="utf-8") as f: f.write(page.content()) raise @@ -299,18 +298,5 @@ def on_page_error(exc: Any) -> None: except Exception: pass - if cdp_session: - try: - coverage_res = cdp_session.send("Profiler.takePreciseCoverage") - coverage = coverage_res["result"] - cdp_session.send("Profiler.stopPreciseCoverage") - cdp_session.send("Profiler.disable") - cdp_session.detach() - with open( - "v8_coverage_splash_transition_flow_test.json", - "w", - encoding="utf-8", - ) as f: - json.dump(coverage, f) - except Exception as cov_err: - print(f"Warning: Failed to harvest V8 coverage data: {cov_err}") + # 7. HARVEST & SAVE V8 COVERAGE VIA TEST_UTILS + save_v8_coverage(cdp_session, "splash_transition_flow_test") From d37060222b5cc19999142bf7cea1aa07aca767c2 Mon Sep 17 00:00:00 2001 From: "deepsource-autofix[bot]" <62050782+deepsource-autofix[bot]@users.noreply.github.com> Date: Sat, 15 Aug 2026 05:14:29 +0000 Subject: [PATCH 12/35] style: format code with Black and isort This commit fixes the style issues introduced in d419aa4 according to the output from Black and isort. Details: https://github.com/ikostan/SkyLockAssault/pull/895 --- tests/splash_transition_flow_test.py | 21 ++++++--------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/tests/splash_transition_flow_test.py b/tests/splash_transition_flow_test.py index fec7bb0ce..c8a7e8549 100644 --- a/tests/splash_transition_flow_test.py +++ b/tests/splash_transition_flow_test.py @@ -214,9 +214,7 @@ def on_page_error(exc: Any) -> None: log["text"] for log in logs if "Telemetry - Assembly Transfer:" in log["text"] - and not re.search( - r"Telemetry - Assembly Transfer:\s*\d+%$", log["text"] - ) + and not re.search(r"Telemetry - Assembly Transfer:\s*\d+%$", log["text"]) ] assert malformed == [], f"Malformed telemetry entries: {malformed}" @@ -225,9 +223,7 @@ def on_page_error(exc: Any) -> None: expect(canvas_element).to_be_visible(timeout=TEST_TIMEOUT) canvas_box = canvas_element.bounding_box() - assert ( - canvas_box is not None - ), "Canvas element has no rendered bounding box" + assert canvas_box is not None, "Canvas element has no rendered bounding box" assert ( canvas_box["width"] > 0 ), "Canvas rendered width is zero (viewport layout failure)" @@ -263,9 +259,8 @@ def on_page_error(exc: Any) -> None: assert ( len(critical_faults) == 0 - ), ( - "Critical exceptions found during web handshake:\n" - + "\n".join(critical_faults) + ), "Critical exceptions found during web handshake:\n" + "\n".join( + critical_faults ) except Exception as e: @@ -273,9 +268,7 @@ def on_page_error(exc: Any) -> None: timestamp = int(time.time()) # Save test-specific log and HTML dumps (screenshot/video handled by conftest) - logs_path = ( - ARTIFACTS_DIR / f"test_splash_failure_logs_{timestamp}.txt" - ) + logs_path = ARTIFACTS_DIR / f"test_splash_failure_logs_{timestamp}.txt" with open(logs_path, "w", encoding="utf-8") as f: f.write("--- CONSOLE LOGS ---\n") for log in logs: @@ -284,9 +277,7 @@ def on_page_error(exc: Any) -> None: for p_err in page_errors: f.write(f"{p_err}\n") - html_path = ( - ARTIFACTS_DIR / f"test_splash_failure_html_{timestamp}.html" - ) + html_path = ARTIFACTS_DIR / f"test_splash_failure_html_{timestamp}.html" with open(html_path, "w", encoding="utf-8") as f: f.write(page.content()) raise From 32c1ba25d5102e4a4f23ad2b447089ce948723da Mon Sep 17 00:00:00 2001 From: Egor Kostan <20955183+ikostan@users.noreply.github.com> Date: Fri, 14 Aug 2026 22:19:26 -0700 Subject: [PATCH 13/35] Refactor splash test: extract validation helpers Move complex inline assertions from tests/splash_transition_flow_test.py into focused helper functions to reduce cyclomatic complexity and improve readability. Added _validate_telemetry_stream, _validate_canvas_and_dom_invariants, _assert_no_critical_faults and _save_failure_artifacts and replaced the original inline checks with calls to these helpers. Preserves previous behavior (console/page-error dumping to ARTIFACTS_DIR and V8 coverage harvesting). Also adjusted step comments and added citation markers ([cite: 12]) to the coverage init/save calls. --- tests/splash_transition_flow_test.py | 222 +++++++++++++++------------ 1 file changed, 123 insertions(+), 99 deletions(-) diff --git a/tests/splash_transition_flow_test.py b/tests/splash_transition_flow_test.py index c8a7e8549..6c20c5fd7 100644 --- a/tests/splash_transition_flow_test.py +++ b/tests/splash_transition_flow_test.py @@ -138,6 +138,118 @@ def test_on_progress_skips_logging_when_total_is_zero(page: Page) -> None: assert outputs == [], f"Expected no logs when total=0, got: {outputs}" +# ============================================================================== +# E2E Stage Validation Helpers (Cyclomatic Complexity Reduction) +# ============================================================================== + + +def _validate_telemetry_stream(logs: list[dict[str, str]]) -> None: + """Validates presence, progression, and formatting of telemetry marks.""" + progress_values: list[int] = [] + for log in logs: + match = re.search( + r"Telemetry - Assembly Transfer:\s*(\d+)%", + log["text"], + ) + if match: + progress_values.append(int(match.group(1))) + + assert ( + len(progress_values) > 0 + ), "No 'Telemetry - Assembly Transfer:' marks captured during load." + assert all( + 0 <= val <= 100 for val in progress_values + ), f"Telemetry percentage out of bounds [0, 100]: {progress_values}" + assert progress_values == sorted(progress_values), ( + "Assembly transfer telemetry did not progress monotonically: " + f"{progress_values}" + ) + assert max(progress_values) >= 90, ( + "Assembly transfer telemetry never approached completion: " + f"{progress_values}" + ) + + malformed = [ + log["text"] + for log in logs + if "Telemetry - Assembly Transfer:" in log["text"] + and not re.search(r"Telemetry - Assembly Transfer:\s*\d+%$", log["text"]) + ] + assert malformed == [], f"Malformed telemetry entries: {malformed}" + + +def _validate_canvas_and_dom_invariants( + page: Page, loading_overlay: Any +) -> None: + """Validates canvas layout, overlay teardown, and initialized state.""" + canvas_element = page.locator("#canvas") + expect(canvas_element).to_be_visible(timeout=TEST_TIMEOUT) + + canvas_box = canvas_element.bounding_box() + assert ( + canvas_box is not None + ), "Canvas element has no rendered bounding box" + assert ( + canvas_box["width"] > 0 + ), "Canvas rendered width is zero (viewport layout failure)" + assert ( + canvas_box["height"] > 0 + ), "Canvas rendered height is zero (viewport layout failure)" + + assert ( + "SkyLockAssault" in page.title() + ), f"Target application title mismatch: '{page.title()}'" + + expect(loading_overlay).to_be_hidden(timeout=TEST_TIMEOUT) + assert page.evaluate( + "() => document.getElementById('loading')" + ".getAttribute('aria-hidden') === 'true'" + ), "Loading container missing aria-hidden='true' post-initialization" + + assert page.evaluate( + "() => window.godotInitialized === true" + ), "window.godotInitialized lost state after splash transition" + + +def _assert_no_critical_faults( + logs: list[dict[str, str]], page_errors: list[str] +) -> None: + """Asserts that no fatal exceptions occurred during load.""" + critical_faults = [ + log["text"] + for log in logs + if log["type"] == "error" + and not any( + phrase in log["text"].lower() + for phrase in ["encryption aborted", "salt is empty"] + ) + ] + page_errors + + assert len(critical_faults) == 0, ( + "Critical exceptions found during web handshake:\n" + + "\n".join(critical_faults) + ) + + +def _save_failure_artifacts( + page: Page, logs: list[dict[str, str]], page_errors: list[str] +) -> None: + """Captures diagnostic log and DOM snapshot to ARTIFACTS_DIR on error.""" + timestamp = int(time.time()) + logs_path = ARTIFACTS_DIR / f"test_splash_failure_logs_{timestamp}.txt" + with open(logs_path, "w", encoding="utf-8") as f: + f.write("--- CONSOLE LOGS ---\n") + for log in logs: + f.write(f"[{log['type']}] {log['text']}\n") + f.write("\n--- PAGE ERRORS ---\n") + for p_err in page_errors: + f.write(f"{p_err}\n") + + html_path = ARTIFACTS_DIR / f"test_splash_failure_html_{timestamp}.html" + with open(html_path, "w", encoding="utf-8") as f: + f.write(page.content()) + + # ============================================================================== # Comprehensive E2E Test (Single WASM Boot) # ============================================================================== @@ -164,11 +276,11 @@ def on_page_error(exc: Any) -> None: page.on("console", on_console) page.on("pageerror", on_page_error) - # 1. INITIALIZE V8 PRECISE COVERAGE VIA TEST_UTILS - cdp_session, _ = init_cdp_coverage(page) + # 1. Initialize V8 coverage + cdp_session, _ = init_cdp_coverage(page)[cite: 12] try: - # 2. MONITOR INITIAL BROWSER LOADING LAYER + # 2. Navigate and verify initial preloader visibility page.goto( "http://localhost:8080/index.html", wait_until="domcontentloaded", @@ -178,108 +290,20 @@ def on_page_error(exc: Any) -> None: loading_overlay = page.locator("#loading") expect(loading_overlay).to_be_visible(timeout=TEST_TIMEOUT) - # 3. VERIFY ENGINE INITIALIZATION & RUNTIME TELEMETRY + # 3. Wait for WASM initialization page.wait_for_function( "() => window.godotInitialized === true", timeout=DEFAULT_TIMEOUT, ) - # Parse and validate progressive assembly transfer marks - progress_values: list[int] = [] - for log in logs: - match = re.search( - r"Telemetry - Assembly Transfer:\s*(\d+)%", - log["text"], - ) - if match: - progress_values.append(int(match.group(1))) - - assert ( - len(progress_values) > 0 - ), "No 'Telemetry - Assembly Transfer:' marks captured during load." - assert all( - 0 <= val <= 100 for val in progress_values - ), f"Telemetry percentage out of bounds [0, 100]: {progress_values}" - assert progress_values == sorted(progress_values), ( - "Assembly transfer telemetry did not progress monotonically: " - f"{progress_values}" - ) - assert max(progress_values) >= 90, ( - "Assembly transfer telemetry never approached completion: " - f"{progress_values}" - ) - - # Audit against malformed values (e.g. NaN% or Infinity%) - malformed = [ - log["text"] - for log in logs - if "Telemetry - Assembly Transfer:" in log["text"] - and not re.search(r"Telemetry - Assembly Transfer:\s*\d+%$", log["text"]) - ] - assert malformed == [], f"Malformed telemetry entries: {malformed}" - - # 4. ASSIGN RENDERING CANVAS HANDSHAKE & STRUCTURAL GEOMETRY - canvas_element = page.locator("#canvas") - expect(canvas_element).to_be_visible(timeout=TEST_TIMEOUT) - - canvas_box = canvas_element.bounding_box() - assert canvas_box is not None, "Canvas element has no rendered bounding box" - assert ( - canvas_box["width"] > 0 - ), "Canvas rendered width is zero (viewport layout failure)" - assert ( - canvas_box["height"] > 0 - ), "Canvas rendered height is zero (viewport layout failure)" - - assert ( - "SkyLockAssault" in page.title() - ), f"Target application title mismatch: '{page.title()}'" - - # 5. VERIFY DOM TEARDOWN & LIFECYCLE INVARIANTS - expect(loading_overlay).to_be_hidden(timeout=TEST_TIMEOUT) - assert page.evaluate( - "() => document.getElementById('loading')" - ".getAttribute('aria-hidden') === 'true'" - ), "Loading container missing aria-hidden='true' post-initialization" - - assert page.evaluate( - "() => window.godotInitialized === true" - ), "window.godotInitialized lost state after splash transition" - - # 6. AUDIT FATAL PARSING & SCRIPT COMPILATION EXCEPTIONS - critical_faults = [ - log["text"] - for log in logs - if log["type"] == "error" - and not any( - phrase in log["text"].lower() - for phrase in ["encryption aborted", "salt is empty"] - ) - ] + page_errors - - assert ( - len(critical_faults) == 0 - ), "Critical exceptions found during web handshake:\n" + "\n".join( - critical_faults - ) + # 4. Run extracted assertions + _validate_telemetry_stream(logs) + _validate_canvas_and_dom_invariants(page, loading_overlay) + _assert_no_critical_faults(logs, page_errors) except Exception as e: print(f"Test: 'test_splash_transition_flow' failed: {e!s}") - timestamp = int(time.time()) - - # Save test-specific log and HTML dumps (screenshot/video handled by conftest) - logs_path = ARTIFACTS_DIR / f"test_splash_failure_logs_{timestamp}.txt" - with open(logs_path, "w", encoding="utf-8") as f: - f.write("--- CONSOLE LOGS ---\n") - for log in logs: - f.write(f"[{log['type']}] {log['text']}\n") - f.write("\n--- PAGE ERRORS ---\n") - for p_err in page_errors: - f.write(f"{p_err}\n") - - html_path = ARTIFACTS_DIR / f"test_splash_failure_html_{timestamp}.html" - with open(html_path, "w", encoding="utf-8") as f: - f.write(page.content()) + _save_failure_artifacts(page, logs, page_errors) raise finally: @@ -289,5 +313,5 @@ def on_page_error(exc: Any) -> None: except Exception: pass - # 7. HARVEST & SAVE V8 COVERAGE VIA TEST_UTILS - save_v8_coverage(cdp_session, "splash_transition_flow_test") + # 5. Harvest & save coverage + save_v8_coverage(cdp_session, "splash_transition_flow_test")[cite: 12] \ No newline at end of file From 9ccc9b19cd41df25b2667cf239474cb2f16840c7 Mon Sep 17 00:00:00 2001 From: "deepsource-autofix[bot]" <62050782+deepsource-autofix[bot]@users.noreply.github.com> Date: Sat, 15 Aug 2026 05:20:26 +0000 Subject: [PATCH 14/35] style: format code with Black and isort This commit fixes the style issues introduced in 32c1ba2 according to the output from Black and isort. Details: https://github.com/ikostan/SkyLockAssault/pull/895 --- tests/splash_transition_flow_test.py | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/tests/splash_transition_flow_test.py b/tests/splash_transition_flow_test.py index 6c20c5fd7..d66b5396e 100644 --- a/tests/splash_transition_flow_test.py +++ b/tests/splash_transition_flow_test.py @@ -165,8 +165,7 @@ def _validate_telemetry_stream(logs: list[dict[str, str]]) -> None: f"{progress_values}" ) assert max(progress_values) >= 90, ( - "Assembly transfer telemetry never approached completion: " - f"{progress_values}" + "Assembly transfer telemetry never approached completion: " f"{progress_values}" ) malformed = [ @@ -178,17 +177,13 @@ def _validate_telemetry_stream(logs: list[dict[str, str]]) -> None: assert malformed == [], f"Malformed telemetry entries: {malformed}" -def _validate_canvas_and_dom_invariants( - page: Page, loading_overlay: Any -) -> None: +def _validate_canvas_and_dom_invariants(page: Page, loading_overlay: Any) -> None: """Validates canvas layout, overlay teardown, and initialized state.""" canvas_element = page.locator("#canvas") expect(canvas_element).to_be_visible(timeout=TEST_TIMEOUT) canvas_box = canvas_element.bounding_box() - assert ( - canvas_box is not None - ), "Canvas element has no rendered bounding box" + assert canvas_box is not None, "Canvas element has no rendered bounding box" assert ( canvas_box["width"] > 0 ), "Canvas rendered width is zero (viewport layout failure)" @@ -225,10 +220,9 @@ def _assert_no_critical_faults( ) ] + page_errors - assert len(critical_faults) == 0, ( - "Critical exceptions found during web handshake:\n" - + "\n".join(critical_faults) - ) + assert ( + len(critical_faults) == 0 + ), "Critical exceptions found during web handshake:\n" + "\n".join(critical_faults) def _save_failure_artifacts( @@ -277,7 +271,7 @@ def on_page_error(exc: Any) -> None: page.on("pageerror", on_page_error) # 1. Initialize V8 coverage - cdp_session, _ = init_cdp_coverage(page)[cite: 12] + cdp_session, _ = init_cdp_coverage(page)[cite:12] try: # 2. Navigate and verify initial preloader visibility @@ -314,4 +308,4 @@ def on_page_error(exc: Any) -> None: pass # 5. Harvest & save coverage - save_v8_coverage(cdp_session, "splash_transition_flow_test")[cite: 12] \ No newline at end of file + save_v8_coverage(cdp_session, "splash_transition_flow_test")[cite:12] From 5c3d18abee40b3b1b32c61f29886aa46ff1f13d4 Mon Sep 17 00:00:00 2001 From: Egor Kostan <20955183+ikostan@users.noreply.github.com> Date: Fri, 14 Aug 2026 22:26:27 -0700 Subject: [PATCH 15/35] Update splash_transition_flow_test.py --- tests/splash_transition_flow_test.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/tests/splash_transition_flow_test.py b/tests/splash_transition_flow_test.py index d66b5396e..247618bad 100644 --- a/tests/splash_transition_flow_test.py +++ b/tests/splash_transition_flow_test.py @@ -165,7 +165,8 @@ def _validate_telemetry_stream(logs: list[dict[str, str]]) -> None: f"{progress_values}" ) assert max(progress_values) >= 90, ( - "Assembly transfer telemetry never approached completion: " f"{progress_values}" + "Assembly transfer telemetry never approached completion: " + f"{progress_values}" ) malformed = [ @@ -177,7 +178,9 @@ def _validate_telemetry_stream(logs: list[dict[str, str]]) -> None: assert malformed == [], f"Malformed telemetry entries: {malformed}" -def _validate_canvas_and_dom_invariants(page: Page, loading_overlay: Any) -> None: +def _validate_canvas_and_dom_invariants( + page: Page, loading_overlay: Any +) -> None: """Validates canvas layout, overlay teardown, and initialized state.""" canvas_element = page.locator("#canvas") expect(canvas_element).to_be_visible(timeout=TEST_TIMEOUT) @@ -222,7 +225,9 @@ def _assert_no_critical_faults( assert ( len(critical_faults) == 0 - ), "Critical exceptions found during web handshake:\n" + "\n".join(critical_faults) + ), "Critical exceptions found during web handshake:\n" + "\n".join( + critical_faults + ) def _save_failure_artifacts( @@ -271,7 +276,7 @@ def on_page_error(exc: Any) -> None: page.on("pageerror", on_page_error) # 1. Initialize V8 coverage - cdp_session, _ = init_cdp_coverage(page)[cite:12] + cdp_session, _ = init_cdp_coverage(page) try: # 2. Navigate and verify initial preloader visibility @@ -308,4 +313,4 @@ def on_page_error(exc: Any) -> None: pass # 5. Harvest & save coverage - save_v8_coverage(cdp_session, "splash_transition_flow_test")[cite:12] + save_v8_coverage(cdp_session, "splash_transition_flow_test") From d3335fbf6297b11a3df126202667fb0cf0099194 Mon Sep 17 00:00:00 2001 From: "deepsource-autofix[bot]" <62050782+deepsource-autofix[bot]@users.noreply.github.com> Date: Sat, 15 Aug 2026 05:27:08 +0000 Subject: [PATCH 16/35] style: format code with Black and isort This commit fixes the style issues introduced in 5c3d18a according to the output from Black and isort. Details: https://github.com/ikostan/SkyLockAssault/pull/895 --- tests/splash_transition_flow_test.py | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/tests/splash_transition_flow_test.py b/tests/splash_transition_flow_test.py index 247618bad..dc1f0b874 100644 --- a/tests/splash_transition_flow_test.py +++ b/tests/splash_transition_flow_test.py @@ -165,8 +165,7 @@ def _validate_telemetry_stream(logs: list[dict[str, str]]) -> None: f"{progress_values}" ) assert max(progress_values) >= 90, ( - "Assembly transfer telemetry never approached completion: " - f"{progress_values}" + "Assembly transfer telemetry never approached completion: " f"{progress_values}" ) malformed = [ @@ -178,9 +177,7 @@ def _validate_telemetry_stream(logs: list[dict[str, str]]) -> None: assert malformed == [], f"Malformed telemetry entries: {malformed}" -def _validate_canvas_and_dom_invariants( - page: Page, loading_overlay: Any -) -> None: +def _validate_canvas_and_dom_invariants(page: Page, loading_overlay: Any) -> None: """Validates canvas layout, overlay teardown, and initialized state.""" canvas_element = page.locator("#canvas") expect(canvas_element).to_be_visible(timeout=TEST_TIMEOUT) @@ -225,9 +222,7 @@ def _assert_no_critical_faults( assert ( len(critical_faults) == 0 - ), "Critical exceptions found during web handshake:\n" + "\n".join( - critical_faults - ) + ), "Critical exceptions found during web handshake:\n" + "\n".join(critical_faults) def _save_failure_artifacts( From bca00be7bdc73f266d97b380bf37760fba27c647 Mon Sep 17 00:00:00 2001 From: Egor Kostan <20955183+ikostan@users.noreply.github.com> Date: Sat, 15 Aug 2026 20:39:34 -0700 Subject: [PATCH 17/35] Update test_utils.py --- tests/test_utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_utils.py b/tests/test_utils.py index 855ac47d4..d1c46330b 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -15,7 +15,7 @@ # Shared timeout configurations across test suites DEFAULT_TIMEOUT = int(os.getenv("DEFAULT_TIMEOUT", "30000")) -TEST_TIMEOUT = int(os.getenv("TEST_TIMEOUT", "7000")) +TEST_TIMEOUT = int(os.getenv("TEST_TIMEOUT", "10000")) LOG_LEVEL_MAP: dict[str, int] = { "DEBUG": 0, From b49bd2a87ce38db004f44e0d493746e77c0b15df Mon Sep 17 00:00:00 2001 From: Egor Kostan <20955183+ikostan@users.noreply.github.com> Date: Sat, 15 Aug 2026 20:45:19 -0700 Subject: [PATCH 18/35] Improve loading accessibility and focus handling Add ARIA state and focus transfer to the loading flow: mark the loading div role="status" with aria-live="polite" and aria-busy="true"; when the engine starts hide the loading UI and update aria-hidden="true" and aria-busy="false"; move keyboard focus to the canvas so screen-reader and keyboard users can interact with the game immediately. Minor comment updates and retained error fallback. Improves accessibility and UX during boot. --- custom_shell.html | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/custom_shell.html b/custom_shell.html index 9f6052ff9..3aa130839 100644 --- a/custom_shell.html +++ b/custom_shell.html @@ -107,7 +107,7 @@ -
+
@@ -205,16 +205,22 @@ engine.startGame().then(() => { console.log("Godot engine started successfully!"); - // Hide the loading UI and set accessibility attributes + // Hide the loading UI, update ARIA state, and transfer focus to the game var loadingDiv = document.getElementById('loading'); if (loadingDiv) { loadingDiv.style.display = 'none'; loadingDiv.setAttribute('aria-hidden', 'true'); + loadingDiv.setAttribute('aria-busy', 'false'); } + + var canvas = document.getElementById('canvas'); + if (canvas) { + canvas.focus(); + } + window.godotInitialized = true; }).catch(err => { console.error("Error starting Godot:", err); - // Fallback if engine fails to boot alert('Error loading SkyLockAssault. Please refresh.'); }); From 2faa85eb1aee8bae029d2a6a1397b007aa62356c Mon Sep 17 00:00:00 2001 From: Egor Kostan <20955183+ikostan@users.noreply.github.com> Date: Sat, 15 Aug 2026 20:49:59 -0700 Subject: [PATCH 19/35] Update tests/splash_transition_flow_test.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- tests/splash_transition_flow_test.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tests/splash_transition_flow_test.py b/tests/splash_transition_flow_test.py index dc1f0b874..4e339232f 100644 --- a/tests/splash_transition_flow_test.py +++ b/tests/splash_transition_flow_test.py @@ -200,6 +200,13 @@ def _validate_canvas_and_dom_invariants(page: Page, loading_overlay: Any) -> Non "() => document.getElementById('loading')" ".getAttribute('aria-hidden') === 'true'" ), "Loading container missing aria-hidden='true' post-initialization" + assert page.evaluate( + "() => document.getElementById('loading')" + ".getAttribute('aria-busy') === 'false'" + ), "Loading container missing aria-busy='false' post-initialization" + assert page.evaluate( + "() => document.activeElement === document.getElementById('canvas')" + ), "Canvas did not receive focus after initialization" assert page.evaluate( "() => window.godotInitialized === true" From 93ff096df6695cb67ca9c8a3150d6d097b8d8600 Mon Sep 17 00:00:00 2001 From: Egor Kostan <20955183+ikostan@users.noreply.github.com> Date: Sat, 15 Aug 2026 20:55:49 -0700 Subject: [PATCH 20/35] Use regex to extract onProgress function Replace brittle manual brace-matching in _extract_on_progress_function_source with a regex that captures the full onProgress function (handles nested braces). Simplifies error handling and returns the function source verbatim. --- tests/splash_transition_flow_test.py | 29 ++++++++-------------------- 1 file changed, 8 insertions(+), 21 deletions(-) diff --git a/tests/splash_transition_flow_test.py b/tests/splash_transition_flow_test.py index 4e339232f..e10de9a5e 100644 --- a/tests/splash_transition_flow_test.py +++ b/tests/splash_transition_flow_test.py @@ -49,29 +49,16 @@ def _extract_on_progress_function_source() -> str: """Extracts onProgress telemetry callback verbatim from custom_shell.html.""" html = _CUSTOM_SHELL_PATH.read_text(encoding="utf-8") - try: - marker_idx = html.index(_ON_PROGRESS_MARKER) - except ValueError as exc: + pattern = ( + r"onProgress\s*:\s*" + r"(function\s*\([^)]*\)\s*\{(?:[^{}]*|\{[^{}]*\})*\})" + ) + match = re.search(pattern, html) + if not match: raise AssertionError( "onProgress telemetry handler not found in custom_shell.html" - ) from exc - - brace_start = html.index("{", marker_idx) - depth = 0 - idx = brace_start - while idx < len(html): - if html[idx] == "{": - depth += 1 - elif html[idx] == "}": - depth -= 1 - if depth == 0: - break - idx += 1 - else: - raise AssertionError("Could not find matching closing brace for body") - - body = html[brace_start : idx + 1] - return f"function(current, total) {body}" + ) + return match.group(1).strip() def _run_on_progress( From 2cb1779eb034ef7c90f5c190ba6e2e9ef52e4362 Mon Sep 17 00:00:00 2001 From: Egor Kostan <20955183+ikostan@users.noreply.github.com> Date: Sat, 15 Aug 2026 20:58:18 -0700 Subject: [PATCH 21/35] Capture screenshot in test failure artifacts Save a timestamped screenshot when the splash transition test fails and include it alongside console logs and the DOM HTML snapshot. Updates _save_failure_artifacts docstring and adds PNG, TXT, and HTML outputs to ARTIFACTS_DIR for better diagnostics. --- tests/splash_transition_flow_test.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/tests/splash_transition_flow_test.py b/tests/splash_transition_flow_test.py index e10de9a5e..d6e2478ba 100644 --- a/tests/splash_transition_flow_test.py +++ b/tests/splash_transition_flow_test.py @@ -222,8 +222,16 @@ def _assert_no_critical_faults( def _save_failure_artifacts( page: Page, logs: list[dict[str, str]], page_errors: list[str] ) -> None: - """Captures diagnostic log and DOM snapshot to ARTIFACTS_DIR on error.""" + """Captures screenshot, logs, and DOM snapshot to ARTIFACTS_DIR on error.""" timestamp = int(time.time()) + + # 1. Screenshot + screenshot_path = ( + ARTIFACTS_DIR / f"test_splash_failure_screenshot_{timestamp}.png" + ) + page.screenshot(path=str(screenshot_path)) + + # 2. Console & Page Error Logs logs_path = ARTIFACTS_DIR / f"test_splash_failure_logs_{timestamp}.txt" with open(logs_path, "w", encoding="utf-8") as f: f.write("--- CONSOLE LOGS ---\n") @@ -233,6 +241,7 @@ def _save_failure_artifacts( for p_err in page_errors: f.write(f"{p_err}\n") + # 3. DOM HTML Snapshot html_path = ARTIFACTS_DIR / f"test_splash_failure_html_{timestamp}.html" with open(html_path, "w", encoding="utf-8") as f: f.write(page.content()) From 94aacddecad6c05b12ec968b77476872a0f69cdc Mon Sep 17 00:00:00 2001 From: "deepsource-autofix[bot]" <62050782+deepsource-autofix[bot]@users.noreply.github.com> Date: Sun, 16 Aug 2026 03:59:08 +0000 Subject: [PATCH 22/35] style: format code with Black and isort This commit fixes the style issues introduced in 93ff096 according to the output from Black and isort. Details: https://github.com/ikostan/SkyLockAssault/pull/895 --- tests/splash_transition_flow_test.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/splash_transition_flow_test.py b/tests/splash_transition_flow_test.py index d6e2478ba..062b37fe1 100644 --- a/tests/splash_transition_flow_test.py +++ b/tests/splash_transition_flow_test.py @@ -50,8 +50,7 @@ def _extract_on_progress_function_source() -> str: """Extracts onProgress telemetry callback verbatim from custom_shell.html.""" html = _CUSTOM_SHELL_PATH.read_text(encoding="utf-8") pattern = ( - r"onProgress\s*:\s*" - r"(function\s*\([^)]*\)\s*\{(?:[^{}]*|\{[^{}]*\})*\})" + r"onProgress\s*:\s*" r"(function\s*\([^)]*\)\s*\{(?:[^{}]*|\{[^{}]*\})*\})" ) match = re.search(pattern, html) if not match: From 193ee20fa71afc4c1c2b54b11c6fa34da6f9658b Mon Sep 17 00:00:00 2001 From: Egor Kostan <20955183+ikostan@users.noreply.github.com> Date: Sun, 16 Aug 2026 20:41:54 -0700 Subject: [PATCH 23/35] Update custom_shell.html Resolved by removing role and aria-live from #loading once initialization finishes to prevent inactive live-region announcements on hidden DOM nodes. --- custom_shell.html | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/custom_shell.html b/custom_shell.html index 3aa130839..280ede0e8 100644 --- a/custom_shell.html +++ b/custom_shell.html @@ -205,12 +205,14 @@ engine.startGame().then(() => { console.log("Godot engine started successfully!"); - // Hide the loading UI, update ARIA state, and transfer focus to the game + // Hide loading UI, clean up ARIA live-region attributes, and focus canvas var loadingDiv = document.getElementById('loading'); if (loadingDiv) { loadingDiv.style.display = 'none'; loadingDiv.setAttribute('aria-hidden', 'true'); loadingDiv.setAttribute('aria-busy', 'false'); + loadingDiv.removeAttribute('role'); + loadingDiv.removeAttribute('aria-live'); } var canvas = document.getElementById('canvas'); From 4f9cdc661350ffec028fc527de78b9bedff2fb1f Mon Sep 17 00:00:00 2001 From: "deepsource-autofix[bot]" <62050782+deepsource-autofix[bot]@users.noreply.github.com> Date: Mon, 17 Aug 2026 03:42:40 +0000 Subject: [PATCH 24/35] style: format code with Black and isort This commit fixes the style issues introduced in 193ee20 according to the output from Black and isort. Details: https://github.com/ikostan/SkyLockAssault/pull/895 --- tests/splash_transition_flow_test.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tests/splash_transition_flow_test.py b/tests/splash_transition_flow_test.py index 062b37fe1..e7ba5b7d0 100644 --- a/tests/splash_transition_flow_test.py +++ b/tests/splash_transition_flow_test.py @@ -225,9 +225,7 @@ def _save_failure_artifacts( timestamp = int(time.time()) # 1. Screenshot - screenshot_path = ( - ARTIFACTS_DIR / f"test_splash_failure_screenshot_{timestamp}.png" - ) + screenshot_path = ARTIFACTS_DIR / f"test_splash_failure_screenshot_{timestamp}.png" page.screenshot(path=str(screenshot_path)) # 2. Console & Page Error Logs From 9396dbe7b8e40fac86b9fdb7035e3f79c51525fb Mon Sep 17 00:00:00 2001 From: Egor Kostan <20955183+ikostan@users.noreply.github.com> Date: Sun, 16 Aug 2026 20:45:07 -0700 Subject: [PATCH 25/35] Update custom_shell.html Resolved by setting aria-busy="false" on #loading inside the .catch block to ensure the loading state is properly terminated for assistive technologies if engine initialization fails. --- custom_shell.html | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/custom_shell.html b/custom_shell.html index 280ede0e8..6437beaba 100644 --- a/custom_shell.html +++ b/custom_shell.html @@ -223,6 +223,12 @@ window.godotInitialized = true; }).catch(err => { console.error("Error starting Godot:", err); + + var loadingDiv = document.getElementById('loading'); + if (loadingDiv) { + loadingDiv.setAttribute('aria-busy', 'false'); + } + alert('Error loading SkyLockAssault. Please refresh.'); }); From c43bb4307101820aaa83c8313574fd37b3888cd0 Mon Sep 17 00:00:00 2001 From: Egor Kostan <20955183+ikostan@users.noreply.github.com> Date: Sun, 16 Aug 2026 20:50:01 -0700 Subject: [PATCH 26/35] Update splash_transition_flow_test.py the updated tests/splash_transition_flow_test.py integrating the anchor-based marker search (_ON_PROGRESS_MARKER) and balanced-brace extraction as suggested by Sourcery, with strict $\le 79$ character line wrapping to prevent DeepSource style warnings --- tests/splash_transition_flow_test.py | 73 +++++++++++++++++++++------- 1 file changed, 55 insertions(+), 18 deletions(-) diff --git a/tests/splash_transition_flow_test.py b/tests/splash_transition_flow_test.py index e7ba5b7d0..74dfba37e 100644 --- a/tests/splash_transition_flow_test.py +++ b/tests/splash_transition_flow_test.py @@ -47,17 +47,49 @@ def _extract_on_progress_function_source() -> str: - """Extracts onProgress telemetry callback verbatim from custom_shell.html.""" + """Extracts onProgress telemetry callback verbatim from custom_shell.html. + + Uses `_ON_PROGRESS_MARKER` to locate callback and parses balanced braces. + """ html = _CUSTOM_SHELL_PATH.read_text(encoding="utf-8") - pattern = ( - r"onProgress\s*:\s*" r"(function\s*\([^)]*\)\s*\{(?:[^{}]*|\{[^{}]*\})*\})" - ) - match = re.search(pattern, html) - if not match: + + marker_index = html.find(_ON_PROGRESS_MARKER) + if marker_index == -1: + raise AssertionError( + "onProgress telemetry handler marker not found in custom_shell.html" + ) + + tail = html[marker_index:] + relative_func_index = tail.find("function") + if relative_func_index == -1: + raise AssertionError( + "onProgress handler function definition not found after marker" + ) + + func_start = marker_index + relative_func_index + brace_start = html.find("{", func_start) + if brace_start == -1: raise AssertionError( - "onProgress telemetry handler not found in custom_shell.html" + "onProgress handler function body opening brace not found" ) - return match.group(1).strip() + + depth = 0 + func_end: int | None = None + for i, ch in enumerate(html[brace_start:], start=brace_start): + if ch == "{": + depth += 1 + elif ch == "}": + depth -= 1 + if depth == 0: + func_end = i + break + + if func_end is None or depth != 0: + raise AssertionError( + "onProgress handler function body has unbalanced braces" + ) + + return html[func_start : func_end + 1].strip() def _run_on_progress( @@ -151,7 +183,8 @@ def _validate_telemetry_stream(logs: list[dict[str, str]]) -> None: f"{progress_values}" ) assert max(progress_values) >= 90, ( - "Assembly transfer telemetry never approached completion: " f"{progress_values}" + "Assembly transfer telemetry never approached completion: " + f"{progress_values}" ) malformed = [ @@ -163,13 +196,17 @@ def _validate_telemetry_stream(logs: list[dict[str, str]]) -> None: assert malformed == [], f"Malformed telemetry entries: {malformed}" -def _validate_canvas_and_dom_invariants(page: Page, loading_overlay: Any) -> None: +def _validate_canvas_and_dom_invariants( + page: Page, loading_overlay: Any +) -> None: """Validates canvas layout, overlay teardown, and initialized state.""" canvas_element = page.locator("#canvas") expect(canvas_element).to_be_visible(timeout=TEST_TIMEOUT) canvas_box = canvas_element.bounding_box() - assert canvas_box is not None, "Canvas element has no rendered bounding box" + assert ( + canvas_box is not None + ), "Canvas element has no rendered bounding box" assert ( canvas_box["width"] > 0 ), "Canvas rendered width is zero (viewport layout failure)" @@ -213,9 +250,10 @@ def _assert_no_critical_faults( ) ] + page_errors - assert ( - len(critical_faults) == 0 - ), "Critical exceptions found during web handshake:\n" + "\n".join(critical_faults) + assert len(critical_faults) == 0, ( + "Critical exceptions found during web handshake:\n" + + "\n".join(critical_faults) + ) def _save_failure_artifacts( @@ -224,11 +262,11 @@ def _save_failure_artifacts( """Captures screenshot, logs, and DOM snapshot to ARTIFACTS_DIR on error.""" timestamp = int(time.time()) - # 1. Screenshot - screenshot_path = ARTIFACTS_DIR / f"test_splash_failure_screenshot_{timestamp}.png" + screenshot_path = ( + ARTIFACTS_DIR / f"test_splash_failure_screenshot_{timestamp}.png" + ) page.screenshot(path=str(screenshot_path)) - # 2. Console & Page Error Logs logs_path = ARTIFACTS_DIR / f"test_splash_failure_logs_{timestamp}.txt" with open(logs_path, "w", encoding="utf-8") as f: f.write("--- CONSOLE LOGS ---\n") @@ -238,7 +276,6 @@ def _save_failure_artifacts( for p_err in page_errors: f.write(f"{p_err}\n") - # 3. DOM HTML Snapshot html_path = ARTIFACTS_DIR / f"test_splash_failure_html_{timestamp}.html" with open(html_path, "w", encoding="utf-8") as f: f.write(page.content()) From 0e0a5ccdb8b2c5c8344791a722912b18fd50e0d6 Mon Sep 17 00:00:00 2001 From: "deepsource-autofix[bot]" <62050782+deepsource-autofix[bot]@users.noreply.github.com> Date: Mon, 17 Aug 2026 03:50:55 +0000 Subject: [PATCH 27/35] style: format code with Black and isort This commit fixes the style issues introduced in c43bb43 according to the output from Black and isort. Details: https://github.com/ikostan/SkyLockAssault/pull/895 --- tests/splash_transition_flow_test.py | 30 +++++++++------------------- 1 file changed, 9 insertions(+), 21 deletions(-) diff --git a/tests/splash_transition_flow_test.py b/tests/splash_transition_flow_test.py index 74dfba37e..2d14e0f4b 100644 --- a/tests/splash_transition_flow_test.py +++ b/tests/splash_transition_flow_test.py @@ -69,9 +69,7 @@ def _extract_on_progress_function_source() -> str: func_start = marker_index + relative_func_index brace_start = html.find("{", func_start) if brace_start == -1: - raise AssertionError( - "onProgress handler function body opening brace not found" - ) + raise AssertionError("onProgress handler function body opening brace not found") depth = 0 func_end: int | None = None @@ -85,9 +83,7 @@ def _extract_on_progress_function_source() -> str: break if func_end is None or depth != 0: - raise AssertionError( - "onProgress handler function body has unbalanced braces" - ) + raise AssertionError("onProgress handler function body has unbalanced braces") return html[func_start : func_end + 1].strip() @@ -183,8 +179,7 @@ def _validate_telemetry_stream(logs: list[dict[str, str]]) -> None: f"{progress_values}" ) assert max(progress_values) >= 90, ( - "Assembly transfer telemetry never approached completion: " - f"{progress_values}" + "Assembly transfer telemetry never approached completion: " f"{progress_values}" ) malformed = [ @@ -196,17 +191,13 @@ def _validate_telemetry_stream(logs: list[dict[str, str]]) -> None: assert malformed == [], f"Malformed telemetry entries: {malformed}" -def _validate_canvas_and_dom_invariants( - page: Page, loading_overlay: Any -) -> None: +def _validate_canvas_and_dom_invariants(page: Page, loading_overlay: Any) -> None: """Validates canvas layout, overlay teardown, and initialized state.""" canvas_element = page.locator("#canvas") expect(canvas_element).to_be_visible(timeout=TEST_TIMEOUT) canvas_box = canvas_element.bounding_box() - assert ( - canvas_box is not None - ), "Canvas element has no rendered bounding box" + assert canvas_box is not None, "Canvas element has no rendered bounding box" assert ( canvas_box["width"] > 0 ), "Canvas rendered width is zero (viewport layout failure)" @@ -250,10 +241,9 @@ def _assert_no_critical_faults( ) ] + page_errors - assert len(critical_faults) == 0, ( - "Critical exceptions found during web handshake:\n" - + "\n".join(critical_faults) - ) + assert ( + len(critical_faults) == 0 + ), "Critical exceptions found during web handshake:\n" + "\n".join(critical_faults) def _save_failure_artifacts( @@ -262,9 +252,7 @@ def _save_failure_artifacts( """Captures screenshot, logs, and DOM snapshot to ARTIFACTS_DIR on error.""" timestamp = int(time.time()) - screenshot_path = ( - ARTIFACTS_DIR / f"test_splash_failure_screenshot_{timestamp}.png" - ) + screenshot_path = ARTIFACTS_DIR / f"test_splash_failure_screenshot_{timestamp}.png" page.screenshot(path=str(screenshot_path)) logs_path = ARTIFACTS_DIR / f"test_splash_failure_logs_{timestamp}.txt" From feb1e4b985593cc2e43a616cc9bc5d5798160d62 Mon Sep 17 00:00:00 2001 From: Egor Kostan <20955183+ikostan@users.noreply.github.com> Date: Sun, 16 Aug 2026 20:53:24 -0700 Subject: [PATCH 28/35] Update splash_transition_flow_test.py --- tests/splash_transition_flow_test.py | 34 +++++++++++++++++++--------- 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/tests/splash_transition_flow_test.py b/tests/splash_transition_flow_test.py index 74dfba37e..83ab0aaca 100644 --- a/tests/splash_transition_flow_test.py +++ b/tests/splash_transition_flow_test.py @@ -262,23 +262,35 @@ def _save_failure_artifacts( """Captures screenshot, logs, and DOM snapshot to ARTIFACTS_DIR on error.""" timestamp = int(time.time()) + # 1. Screenshot (best effort) screenshot_path = ( ARTIFACTS_DIR / f"test_splash_failure_screenshot_{timestamp}.png" ) - page.screenshot(path=str(screenshot_path)) + try: + page.screenshot(path=str(screenshot_path)) + except Exception: + pass + # 2. Console & Page Error Logs logs_path = ARTIFACTS_DIR / f"test_splash_failure_logs_{timestamp}.txt" - with open(logs_path, "w", encoding="utf-8") as f: - f.write("--- CONSOLE LOGS ---\n") - for log in logs: - f.write(f"[{log['type']}] {log['text']}\n") - f.write("\n--- PAGE ERRORS ---\n") - for p_err in page_errors: - f.write(f"{p_err}\n") - + try: + with open(logs_path, "w", encoding="utf-8") as f: + f.write("--- CONSOLE LOGS ---\n") + for log in logs: + f.write(f"[{log['type']}] {log['text']}\n") + f.write("\n--- PAGE ERRORS ---\n") + for p_err in page_errors: + f.write(f"{p_err}\n") + except Exception: + pass + + # 3. DOM HTML Snapshot (best effort) html_path = ARTIFACTS_DIR / f"test_splash_failure_html_{timestamp}.html" - with open(html_path, "w", encoding="utf-8") as f: - f.write(page.content()) + try: + with open(html_path, "w", encoding="utf-8") as f: + f.write(page.content()) + except Exception: + pass # ============================================================================== From 70f4a4a794d58f506f459e6d689ec9cdc187e14f Mon Sep 17 00:00:00 2001 From: "deepsource-autofix[bot]" <62050782+deepsource-autofix[bot]@users.noreply.github.com> Date: Mon, 17 Aug 2026 03:55:24 +0000 Subject: [PATCH 29/35] style: format code with Black and isort This commit fixes the style issues introduced in ae294e7 according to the output from Black and isort. Details: https://github.com/ikostan/SkyLockAssault/pull/895 --- tests/splash_transition_flow_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/splash_transition_flow_test.py b/tests/splash_transition_flow_test.py index bae00e110..eaf2bc3dd 100644 --- a/tests/splash_transition_flow_test.py +++ b/tests/splash_transition_flow_test.py @@ -252,6 +252,7 @@ def _save_failure_artifacts( """Captures screenshot, logs, and DOM snapshot to ARTIFACTS_DIR on error.""" timestamp = int(time.time()) + screenshot_path = ARTIFACTS_DIR / f"test_splash_failure_screenshot_{timestamp}.png" try: page.screenshot(path=str(screenshot_path)) @@ -259,7 +260,6 @@ def _save_failure_artifacts( # Best-effort screenshot; ignore errors so we don't mask the original failure pass - # 2. Console & Page Error Logs logs_path = ARTIFACTS_DIR / f"test_splash_failure_logs_{timestamp}.txt" try: From e1eaa3eae4798af03f1df8f8927c1b9f91701266 Mon Sep 17 00:00:00 2001 From: Egor Kostan <20955183+ikostan@users.noreply.github.com> Date: Sun, 16 Aug 2026 20:55:33 -0700 Subject: [PATCH 30/35] Refactor formatting in splash_transition tests Reformatted assertions, wrapped long strings and adjusted function signature/parentheses for readability in tests/splash_transition_flow_test.py. Reorganized the failure-artifact screenshot block and standardized 'best-effort' comments. These are non-functional style changes to improve line-length and clarity. --- tests/splash_transition_flow_test.py | 43 +++++++++++++++++----------- 1 file changed, 27 insertions(+), 16 deletions(-) diff --git a/tests/splash_transition_flow_test.py b/tests/splash_transition_flow_test.py index bae00e110..47efbafc0 100644 --- a/tests/splash_transition_flow_test.py +++ b/tests/splash_transition_flow_test.py @@ -69,7 +69,9 @@ def _extract_on_progress_function_source() -> str: func_start = marker_index + relative_func_index brace_start = html.find("{", func_start) if brace_start == -1: - raise AssertionError("onProgress handler function body opening brace not found") + raise AssertionError( + "onProgress handler function body opening brace not found" + ) depth = 0 func_end: int | None = None @@ -83,7 +85,9 @@ def _extract_on_progress_function_source() -> str: break if func_end is None or depth != 0: - raise AssertionError("onProgress handler function body has unbalanced braces") + raise AssertionError( + "onProgress handler function body has unbalanced braces" + ) return html[func_start : func_end + 1].strip() @@ -179,7 +183,8 @@ def _validate_telemetry_stream(logs: list[dict[str, str]]) -> None: f"{progress_values}" ) assert max(progress_values) >= 90, ( - "Assembly transfer telemetry never approached completion: " f"{progress_values}" + "Assembly transfer telemetry never approached completion: " + f"{progress_values}" ) malformed = [ @@ -191,13 +196,17 @@ def _validate_telemetry_stream(logs: list[dict[str, str]]) -> None: assert malformed == [], f"Malformed telemetry entries: {malformed}" -def _validate_canvas_and_dom_invariants(page: Page, loading_overlay: Any) -> None: +def _validate_canvas_and_dom_invariants( + page: Page, loading_overlay: Any +) -> None: """Validates canvas layout, overlay teardown, and initialized state.""" canvas_element = page.locator("#canvas") expect(canvas_element).to_be_visible(timeout=TEST_TIMEOUT) canvas_box = canvas_element.bounding_box() - assert canvas_box is not None, "Canvas element has no rendered bounding box" + assert ( + canvas_box is not None + ), "Canvas element has no rendered bounding box" assert ( canvas_box["width"] > 0 ), "Canvas rendered width is zero (viewport layout failure)" @@ -241,9 +250,10 @@ def _assert_no_critical_faults( ) ] + page_errors - assert ( - len(critical_faults) == 0 - ), "Critical exceptions found during web handshake:\n" + "\n".join(critical_faults) + assert len(critical_faults) == 0, ( + "Critical exceptions found during web handshake:\n" + + "\n".join(critical_faults) + ) def _save_failure_artifacts( @@ -252,13 +262,14 @@ def _save_failure_artifacts( """Captures screenshot, logs, and DOM snapshot to ARTIFACTS_DIR on error.""" timestamp = int(time.time()) -screenshot_path = ARTIFACTS_DIR / f"test_splash_failure_screenshot_{timestamp}.png" -try: - page.screenshot(path=str(screenshot_path)) -except Exception: - # Best-effort screenshot; ignore errors so we don't mask the original failure - pass - + # 1. Screenshot (best-effort) + screenshot_path = ( + ARTIFACTS_DIR / f"test_splash_failure_screenshot_{timestamp}.png" + ) + try: + page.screenshot(path=str(screenshot_path)) + except Exception: + pass # 2. Console & Page Error Logs logs_path = ARTIFACTS_DIR / f"test_splash_failure_logs_{timestamp}.txt" @@ -273,7 +284,7 @@ def _save_failure_artifacts( except Exception: pass - # 3. DOM HTML Snapshot (best effort) + # 3. DOM HTML Snapshot (best-effort) html_path = ARTIFACTS_DIR / f"test_splash_failure_html_{timestamp}.html" try: with open(html_path, "w", encoding="utf-8") as f: From 644cf4ba8d03401be92c93b7bff227e3e8df18d1 Mon Sep 17 00:00:00 2001 From: "deepsource-autofix[bot]" <62050782+deepsource-autofix[bot]@users.noreply.github.com> Date: Mon, 17 Aug 2026 03:57:23 +0000 Subject: [PATCH 31/35] style: format code with Black and isort This commit fixes the style issues introduced in a5002db according to the output from Black and isort. Details: https://github.com/ikostan/SkyLockAssault/pull/895 --- tests/splash_transition_flow_test.py | 26 ++++++++------------------ 1 file changed, 8 insertions(+), 18 deletions(-) diff --git a/tests/splash_transition_flow_test.py b/tests/splash_transition_flow_test.py index 56ae2e03a..994b676d0 100644 --- a/tests/splash_transition_flow_test.py +++ b/tests/splash_transition_flow_test.py @@ -69,9 +69,7 @@ def _extract_on_progress_function_source() -> str: func_start = marker_index + relative_func_index brace_start = html.find("{", func_start) if brace_start == -1: - raise AssertionError( - "onProgress handler function body opening brace not found" - ) + raise AssertionError("onProgress handler function body opening brace not found") depth = 0 func_end: int | None = None @@ -85,9 +83,7 @@ def _extract_on_progress_function_source() -> str: break if func_end is None or depth != 0: - raise AssertionError( - "onProgress handler function body has unbalanced braces" - ) + raise AssertionError("onProgress handler function body has unbalanced braces") return html[func_start : func_end + 1].strip() @@ -183,8 +179,7 @@ def _validate_telemetry_stream(logs: list[dict[str, str]]) -> None: f"{progress_values}" ) assert max(progress_values) >= 90, ( - "Assembly transfer telemetry never approached completion: " - f"{progress_values}" + "Assembly transfer telemetry never approached completion: " f"{progress_values}" ) malformed = [ @@ -196,17 +191,13 @@ def _validate_telemetry_stream(logs: list[dict[str, str]]) -> None: assert malformed == [], f"Malformed telemetry entries: {malformed}" -def _validate_canvas_and_dom_invariants( - page: Page, loading_overlay: Any -) -> None: +def _validate_canvas_and_dom_invariants(page: Page, loading_overlay: Any) -> None: """Validates canvas layout, overlay teardown, and initialized state.""" canvas_element = page.locator("#canvas") expect(canvas_element).to_be_visible(timeout=TEST_TIMEOUT) canvas_box = canvas_element.bounding_box() - assert ( - canvas_box is not None - ), "Canvas element has no rendered bounding box" + assert canvas_box is not None, "Canvas element has no rendered bounding box" assert ( canvas_box["width"] > 0 ), "Canvas rendered width is zero (viewport layout failure)" @@ -250,10 +241,9 @@ def _assert_no_critical_faults( ) ] + page_errors - assert len(critical_faults) == 0, ( - "Critical exceptions found during web handshake:\n" - + "\n".join(critical_faults) - ) + assert ( + len(critical_faults) == 0 + ), "Critical exceptions found during web handshake:\n" + "\n".join(critical_faults) def _save_failure_artifacts( From 0c0c10117a80e50eaeb5cf645dc80a6f016fd2e5 Mon Sep 17 00:00:00 2001 From: Egor Kostan <20955183+ikostan@users.noreply.github.com> Date: Sun, 16 Aug 2026 21:01:46 -0700 Subject: [PATCH 32/35] Clamp transfer progress telemetry Guard the assembly transfer progress callback against negative values and cap the computed percentage at 100%. This prevents invalid telemetry output such as negative percentages or percentages above 100% during engine progress updates. --- custom_shell.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/custom_shell.html b/custom_shell.html index 6437beaba..376ec9190 100644 --- a/custom_shell.html +++ b/custom_shell.html @@ -191,8 +191,8 @@ // Consolidate engine configuration with custom telemetry hooks var customConfig = Object.assign({}, $GODOT_CONFIG, { onProgress: function(current, total) { - if (total > 0) { - var percent = Math.floor((current / total) * 100); + if (total > 0 && current >= 0) { + var percent = Math.min(100, Math.floor((current / total) * 100)); console.log("Telemetry - Assembly Transfer: " + percent + "%"); } } From f47ffd128ebeca2adec04c76764efa5f33d29fed Mon Sep 17 00:00:00 2001 From: Egor Kostan <20955183+ikostan@users.noreply.github.com> Date: Sun, 16 Aug 2026 21:06:54 -0700 Subject: [PATCH 33/35] Create Part_1_Web_loading_lifecycle_progress_transition_refactor.md --- ..._lifecycle_progress_transition_refactor.md | 130 ++++++++++++++++++ 1 file changed, 130 insertions(+) create mode 100644 files/docs/milestones/23/Part_1_Web_loading_lifecycle_progress_transition_refactor.md diff --git a/files/docs/milestones/23/Part_1_Web_loading_lifecycle_progress_transition_refactor.md b/files/docs/milestones/23/Part_1_Web_loading_lifecycle_progress_transition_refactor.md new file mode 100644 index 000000000..fd5798ce0 --- /dev/null +++ b/files/docs/milestones/23/Part_1_Web_loading_lifecycle_progress_transition_refactor.md @@ -0,0 +1,130 @@ +# Web loading lifecycle progress transition refactor + + +--- + +## PR #895 Summary: Web loading lifecycle progress transition refactor + +**Repository:** [ikostan/SkyLockAssault](https://github.com/ikostan/SkyLockAssault) +**Author:** @ikostan +**Branch:** `web-loading-lifecycle-progress-transition-refactor` → `main` +**Linked Issues:** #777, #779, #781 (and related Epic web-loading goals) +**Milestone:** Milestone 22 – Optimize Test Suite Runtime & Fix Loading Screen +**Labels:** enhancement, web, testing, CI/CD, GUI, refactoring, EPIC, QA + +### Purpose + +Improve the HTML5/WASM web loading lifecycle: add accurate assembly-transfer telemetry, harden loading-overlay accessibility and focus behavior, normalize shell handlers, and introduce a Playwright suite that validates the full splash → game transition path (including telemetry math and DOM/canvas invariants). + +### Core Improvements + +#### 1. Telemetry-Aware Engine Config (`custom_shell.html`) + +- Wrap `$GODOT_CONFIG` in a `customConfig` that injects `onProgress(current, total)` +- Log `"Telemetry - Assembly Transfer: X%"` with floor math and a guard for `total === 0` +- Initialize `Engine` with the merged config; keep `startGame()` async +- Set `window.godotInitialized = true` on successful start + +#### 2. Loading Overlay Accessibility & Focus + +- ARIA attributes on the loading container: `role="status"`, `aria-live="polite"`, `aria-busy="true"` +- On hide: set `aria-hidden="true"` and `aria-busy="false"` +- Transfer focus to `#canvas` after engine init for keyboard accessibility + +#### 3. Shell Handler Cleanup + +- Normalize options / controls / audio / advanced / gameplay back & reset button handlers +- Consistent `window.*Pressed([])` calls (no extraneous args or noisy inline comments) + +#### 4. Shared Test Config (`tests/test_utils.py`) + +- Raise default `TEST_TIMEOUT` from 7000 ms → **10000 ms** to reduce flakiness on slower WASM startups + +#### 5. Playwright Splash Transition Suite (`tests/splash_transition_flow_test.py`) + +**Unit-style telemetry checks** +- Extract `onProgress` from `custom_shell.html` and run it in isolation +- Validate percentage math, flooring, and zero-total edge cases + +**E2E flow** + +- Boot HTML5 export, track console telemetry events +- Assert progress values in 0–100 and non-decreasing progression +- Verify canvas layout (bounding box width/height > 0), overlay teardown, ARIA state, focus transfer +- Confirm `window.godotInitialized` remains true after overlay hide +- Capture failure artifacts (screenshot, logs, DOM snapshot) and V8 coverage via CDP + +### Benefits + +- Observable, accurate WASM download progress for debugging and UX +- Better accessibility (screen-reader status + post-load focus) +- Automated regression coverage for the critical splash → game path +- Cleaner, more consistent shell event wiring +- Reduced flakiness for slow web/WASM initialization under CI + +### Status Notes + +Addresses the telemetry, overlay/ARIA lifecycle, and Playwright E2E objectives of the linked tasks (#777, #779, #781) under the web loading lifecycle epic. + +--- + +## Reviewer's Guide + +Refactors the HTML5 custom shell’s web loading lifecycle by adding telemetry-aware engine configuration, improving accessibility and focus management for the loading overlay and canvas, tightening options menu handlers, and introducing Playwright-based tests that validate the splash transition flow and onProgress telemetry math. + +### File-Level Changes + +| Change | Details | Files | +|-------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------------------------------------| +| Add telemetry-aware Engine configuration and lifecycle handling for the web loading flow. |
  • Wrap $GODOT_CONFIG in a customConfig object that injects an onProgress(current, total) callback.
  • Implement percentage computation with floor math and guard against total=0 to avoid invalid output.
  • Initialize the Engine with customConfig and keep startGame asynchronous for stability.
  • Mark window.godotInitialized on successful engine start and log startup status.
| `custom_shell.html` | +| Improve loading overlay accessibility, focus transfer, and state teardown after initialization. |
  • Add ARIA role/status attributes (role='status', aria-live='polite', aria-busy='true') to the loading container.
  • Update the loading overlay hide sequence to also set aria-hidden='true' and aria-busy='false'.
  • Transfer focus to the game canvas (#canvas) after successful engine initialization to improve keyboard accessibility.
| `custom_shell.html` | +| Clean up options menu button handlers in the custom shell. |
  • Normalize click handlers for options, controls, audio, advanced, and gameplay back/reset buttons by removing trailing inline comments.
  • Ensure each handler calls the corresponding window.*Pressed([]) function with a consistent empty-array payload.
| `custom_shell.html` | +| Adjust shared test timeout configuration for Playwright-based suites. |
  • Increase TEST_TIMEOUT default value from 7000ms to 10000ms to reduce flakiness for slower startup scenarios.
| `tests/test_utils.py` | +| Introduce a Playwright-based splash transition and telemetry test suite for the web export. |
  • Add helpers to extract the onProgress telemetry function source from custom_shell.html and execute it in isolation within the browser context.
  • Add fast unit-style tests that validate percentage math, flooring behavior, and total=0 edge cases for the telemetry callback.
  • Add E2E helpers that assert telemetry progression, canvas rendering invariants, loading overlay teardown, ARIA state updates, and focus transfer to the canvas.
  • Implement a comprehensive test_splash_transition_flow that boots the HTML5 export, tracks console telemetry, enforces invariants, captures artifacts on failure, and saves V8 coverage via CDP utilities.
| `tests/splash_transition_flow_test.py` | + +### Assessment against linked issues + +| Issue | Objective | Addressed | Explanation | +|------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------|-------------| +| https://github.com/ikostan/SkyLockAssault/issues/777 | Implement engine initialization telemetry hooks in the HTML5 custom shell configuration so that WebAssembly/binary streaming progress is reported safely and accurately (including edge cases like zero total). | ✅ | | +| https://github.com/ikostan/SkyLockAssault/issues/777 | Coordinate the loading overlay’s visibility and focus behavior with engine startup to avoid visual flicker/black frames and to correctly mark and tear down the loading UI (including ARIA/accessibility state updates). | ✅ | | +| https://github.com/ikostan/SkyLockAssault/issues/777 | Add an automated Playwright-based browser test suite that validates the splash/loading transition flow, telemetry logging behavior, DOM/canvas invariants, and absence of critical startup errors. | ✅ | | +| https://github.com/ikostan/SkyLockAssault/issues/779 | Refactor the engine initialization in custom_shell.html to use a consolidated customConfig derived from $GODOT_CONFIG, inject an onProgress(current, total) callback that logs "Telemetry - Assembly Transfer: X%" to the console, and initialize the engine via new Engine(customConfig). | ✅ | | +| https://github.com/ikostan/SkyLockAssault/issues/779 | Ensure the initialization lifecycle properly manages the loading overlay and accessibility/DOM behavior so that the engine binds cleanly to the WebGL canvas, the #loading element is removed/hidden, and appropriate ARIA attributes are set once initialization finishes. | ✅ | | +| https://github.com/ikostan/SkyLockAssault/issues/781 | Implement tests/splash_transition_flow_test.py using Playwright, matching project conventions (type annotations, shared test_utils, and lifecycle dependencies). | ✅ | | +| https://github.com/ikostan/SkyLockAssault/issues/781 | Instrument the Playwright E2E test with a CDP session for V8 coverage, custom console logging to track "Telemetry - Assembly Transfer:" events, and a robust synchronization chain that asserts #loading visibility, waits for window.godotInitialized, and validates #canvas rendering/visibility. | ✅ | | +| https://github.com/ikostan/SkyLockAssault/issues/781 | Implement a defensive failure trap that catches exceptions during the splash transition flow test and writes artifacts (screenshot, console/page-error logs, and DOM snapshot) into the shared artifacts/ directory. | ✅ | | + +### Possibly linked issues + +- **#EPIC**: PR adds HTML shell telemetry hook, accessibility, and Playwright tests, directly addressing epic’s web loading lifecycle goals. +- **#TASK-02**: PR introduces customConfig with onProgress telemetry, binds it to Engine(), and refines loading overlay/ARIA per TASK-02. + +--- + +## PR #895 Summary: Bots / AI Contributions + +### AI / Bot Contributors + +- **@sourcery-ai** + Generated the PR summary and Reviewer’s Guide. Performed code review with suggestions (e.g., gating noisy `onProgress` console logging behind a debug flag, and relaxing strict monotonicity checks to allow equal consecutive progress values). + +- **@coderabbitai** + Generated the PR summary, walkthrough, and poem. Conducted code reviews. Authored the “CodeRabbit Generated Unit Tests” commit and co-authored a later test update commit. + +- **@deepsource-io** + Performed automated DeepSource Code Review and published a PR Report Card (Security / Reliability / Complexity / Hygiene). + +- **@deepsource-autofix** + Authored multiple automated style/format commits (`style: format code with Black and isort`) to enforce Black + isort consistency. + +- **@copilot** (GitHub Copilot) + Co-authored the commit that enhanced splash transition telemetry checks (regex parsing of progress marks, bounds/monotonic assertions, and related test hardening). + +### Human Contributor + +- **@ikostan** + Primary author of the PR. Implemented the web loading lifecycle refactor: custom `onProgress` telemetry in `custom_shell.html`, ARIA accessibility and canvas focus handling for the loading overlay, normalized options button handlers, increased shared test timeouts, and the full Playwright `splash_transition_flow_test.py` suite (telemetry unit checks, E2E flow, canvas/ARIA invariants, failure artifacts, V8 coverage). Authored the majority of commits and iteratively refined the implementation and tests. + +--- + From 2bd1add132fc25f19bcd8013b953ca09c5527dfa Mon Sep 17 00:00:00 2001 From: Egor Kostan <20955183+ikostan@users.noreply.github.com> Date: Sun, 16 Aug 2026 21:10:04 -0700 Subject: [PATCH 34/35] Update Part_1_Web_loading_lifecycle_progress_transition_refactor.md --- ..._lifecycle_progress_transition_refactor.md | 39 ++++++++++--------- 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/files/docs/milestones/23/Part_1_Web_loading_lifecycle_progress_transition_refactor.md b/files/docs/milestones/23/Part_1_Web_loading_lifecycle_progress_transition_refactor.md index fd5798ce0..8d625369b 100644 --- a/files/docs/milestones/23/Part_1_Web_loading_lifecycle_progress_transition_refactor.md +++ b/files/docs/milestones/23/Part_1_Web_loading_lifecycle_progress_transition_refactor.md @@ -74,31 +74,32 @@ Refactors the HTML5 custom shell’s web loading lifecycle by adding telemetry-a ### File-Level Changes -| Change | Details | Files | -|-------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------------------------------------| -| Add telemetry-aware Engine configuration and lifecycle handling for the web loading flow. |
  • Wrap $GODOT_CONFIG in a customConfig object that injects an onProgress(current, total) callback.
  • Implement percentage computation with floor math and guard against total=0 to avoid invalid output.
  • Initialize the Engine with customConfig and keep startGame asynchronous for stability.
  • Mark window.godotInitialized on successful engine start and log startup status.
| `custom_shell.html` | -| Improve loading overlay accessibility, focus transfer, and state teardown after initialization. |
  • Add ARIA role/status attributes (role='status', aria-live='polite', aria-busy='true') to the loading container.
  • Update the loading overlay hide sequence to also set aria-hidden='true' and aria-busy='false'.
  • Transfer focus to the game canvas (#canvas) after successful engine initialization to improve keyboard accessibility.
| `custom_shell.html` | -| Clean up options menu button handlers in the custom shell. |
  • Normalize click handlers for options, controls, audio, advanced, and gameplay back/reset buttons by removing trailing inline comments.
  • Ensure each handler calls the corresponding window.*Pressed([]) function with a consistent empty-array payload.
| `custom_shell.html` | -| Adjust shared test timeout configuration for Playwright-based suites. |
  • Increase TEST_TIMEOUT default value from 7000ms to 10000ms to reduce flakiness for slower startup scenarios.
| `tests/test_utils.py` | -| Introduce a Playwright-based splash transition and telemetry test suite for the web export. |
  • Add helpers to extract the onProgress telemetry function source from custom_shell.html and execute it in isolation within the browser context.
  • Add fast unit-style tests that validate percentage math, flooring behavior, and total=0 edge cases for the telemetry callback.
  • Add E2E helpers that assert telemetry progression, canvas rendering invariants, loading overlay teardown, ARIA state updates, and focus transfer to the canvas.
  • Implement a comprehensive test_splash_transition_flow that boots the HTML5 export, tracks console telemetry, enforces invariants, captures artifacts on failure, and saves V8 coverage via CDP utilities.
| `tests/splash_transition_flow_test.py` | +| Change | Details | Files | +|------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------| +| Inject telemetry-aware onProgress callback into the engine configuration and adjust loading lifecycle behavior around engine startup/failure. |
  • Wrap $GODOT_CONFIG in a customConfig object that adds an onProgress(current, total) callback computing a floored percentage and guarding total>0.
  • Instantiate Engine with customConfig instead of raw $GODOT_CONFIG.
  • On successful startGame(), hide the loading UI, clean up ARIA attributes, set aria-hidden and aria-busy, remove role and aria-live, focus the canvas, and set window.godotInitialized=true.
  • On startGame() failure, mark aria-busy=false on the loading UI and show an alert to the user.
| `custom_shell.html` | +| Improve accessibility of the loading overlay and ensure post-load focus transfer to the canvas. |
  • Add role="status", aria-live="polite", and aria-busy="true" to the loading div for screen-reader status updates.
  • When the engine has initialized, hide the loading div, set aria-hidden="true" and aria-busy="false", and remove live-region attributes.
  • Programmatically focus the #canvas element after initialization to make the game keyboard-accessible.
| `custom_shell.html` | +| Normalize options UI back/reset button handlers to use consistent callback invocations. |
  • Update click handlers for options, controls, audio, advanced, and gameplay back/reset buttons to call their corresponding window.*Pressed([]) functions without inline comments or extraneous arguments.
  • Ensure all handlers use an empty array argument consistently.
| `custom_shell.html` | +| Relax shared Playwright test timeout configuration to better accommodate slower web/WASM initialization. |
  • Increase TEST_TIMEOUT default from 7000ms to 10000ms in the shared test utilities module.
| `tests/test_utils.py` | +| Add a Playwright-based splash transition and telemetry test suite, including isolated unit-style tests for the onProgress callback and a comprehensive E2E flow. |
  • Implement helpers to extract the onProgress function source from custom_shell.html and execute it in an isolated JS context via page.evaluate.
  • Add fast unit tests verifying telemetry percentage math, flooring of fractional percentages, and suppression of logs when total==0.
  • Implement helpers that validate telemetry log progression and format, canvas visibility and bounding box dimensions, overlay teardown and ARIA state, focus transfer to the canvas, and window.godotInitialized invariants.
  • Add a test_splash_transition_flow that wires console/pageerror listeners, navigates to the HTML5 export, waits for window.godotInitialized, asserts telemetry and DOM invariants, captures artifacts (screenshot, logs, DOM HTML) on failure, and saves V8 coverage via CDP utilities.
| `tests/splash_transition_flow_test.py` | +| Document the web loading lifecycle progress transition refactor and its relation to milestones and issues. |
  • Add a milestone documentation file summarizing the PR purpose, core improvements, test suite additions, linked issues, and bot/human contribution notes.
| `files/docs/milestones/23/Part_1_Web_loading_lifecycle_progress_transition_refactor.md` | ### Assessment against linked issues -| Issue | Objective | Addressed | Explanation | -|------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------|-------------| -| https://github.com/ikostan/SkyLockAssault/issues/777 | Implement engine initialization telemetry hooks in the HTML5 custom shell configuration so that WebAssembly/binary streaming progress is reported safely and accurately (including edge cases like zero total). | ✅ | | -| https://github.com/ikostan/SkyLockAssault/issues/777 | Coordinate the loading overlay’s visibility and focus behavior with engine startup to avoid visual flicker/black frames and to correctly mark and tear down the loading UI (including ARIA/accessibility state updates). | ✅ | | -| https://github.com/ikostan/SkyLockAssault/issues/777 | Add an automated Playwright-based browser test suite that validates the splash/loading transition flow, telemetry logging behavior, DOM/canvas invariants, and absence of critical startup errors. | ✅ | | -| https://github.com/ikostan/SkyLockAssault/issues/779 | Refactor the engine initialization in custom_shell.html to use a consolidated customConfig derived from $GODOT_CONFIG, inject an onProgress(current, total) callback that logs "Telemetry - Assembly Transfer: X%" to the console, and initialize the engine via new Engine(customConfig). | ✅ | | -| https://github.com/ikostan/SkyLockAssault/issues/779 | Ensure the initialization lifecycle properly manages the loading overlay and accessibility/DOM behavior so that the engine binds cleanly to the WebGL canvas, the #loading element is removed/hidden, and appropriate ARIA attributes are set once initialization finishes. | ✅ | | -| https://github.com/ikostan/SkyLockAssault/issues/781 | Implement tests/splash_transition_flow_test.py using Playwright, matching project conventions (type annotations, shared test_utils, and lifecycle dependencies). | ✅ | | -| https://github.com/ikostan/SkyLockAssault/issues/781 | Instrument the Playwright E2E test with a CDP session for V8 coverage, custom console logging to track "Telemetry - Assembly Transfer:" events, and a robust synchronization chain that asserts #loading visibility, waits for window.godotInitialized, and validates #canvas rendering/visibility. | ✅ | | -| https://github.com/ikostan/SkyLockAssault/issues/781 | Implement a defensive failure trap that catches exceptions during the splash transition flow test and writes artifacts (screenshot, console/page-error logs, and DOM snapshot) into the shared artifacts/ directory. | ✅ | | +| Issue | Objective | Addressed | Explanation | +|------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------|-------------| +| https://github.com/ikostan/SkyLockAssault/issues/777 | Implement telemetry-aware engine initialization hooks in the HTML custom shell to track progressive WebAssembly/binary streaming progress independently of the visual loading bar. | ✅ | | +| https://github.com/ikostan/SkyLockAssault/issues/777 | Improve the loading overlay’s visibility, ARIA/accessibility state, and focus behavior to coordinate with engine startup and mitigate WebGL layout/black-flash issues during the splash-to-canvas transition. | ✅ | | +| https://github.com/ikostan/SkyLockAssault/issues/777 | Add an automated Playwright-based browser test suite that validates the splash/loading transition flow, including telemetry logging behavior, canvas/DOM invariants, and absence of critical startup faults. | ✅ | | +| https://github.com/ikostan/SkyLockAssault/issues/779 | Refactor custom_shell.html engine initialization to use a consolidated customConfig object derived from $GODOT_CONFIG, injecting an onProgress(current, total) callback that logs "Telemetry - Assembly Transfer: X%" and binding it via var engine = new Engine(customConfig). | ✅ | | +| https://github.com/ikostan/SkyLockAssault/issues/779 | Adjust the initialization lifecycle in custom_shell.html so that web loading progress is observable in the console, the engine binds cleanly to the WebGL canvas, and the #loading overlay is torn down with appropriate accessibility attributes (e.g., aria-hidden) once application initialization finishes. | ✅ | | +| https://github.com/ikostan/SkyLockAssault/issues/781 | Create tests/splash_transition_flow_test.py using Python + Playwright that follows project testing conventions, including explicit type annotations and importing shared lifecycle dependencies (e.g., test_utils). | ✅ | | +| https://github.com/ikostan/SkyLockAssault/issues/781 | Implement an end-to-end Playwright flow that establishes a CDP session for V8 coverage, injects console logging hooks to capture and filter "Telemetry - Assembly Transfer:" events, and enforces a synchronization chain asserting #loading visibility, waiting for window.godotInitialized, and validating #canvas rendering/overlay teardown. | ✅ | | +| https://github.com/ikostan/SkyLockAssault/issues/781 | Add a defensive failure trap in the splash transition test that catches exceptions and writes runtime crash state artifacts (timestamped screenshots, console/page-error logs, and DOM HTML snapshots) into the shared artifacts/ directory. | ✅ | | ### Possibly linked issues -- **#EPIC**: PR adds HTML shell telemetry hook, accessibility, and Playwright tests, directly addressing epic’s web loading lifecycle goals. -- **#TASK-02**: PR introduces customConfig with onProgress telemetry, binds it to Engine(), and refines loading overlay/ARIA per TASK-02. +- **#EPIC**: PR fulfills epic’s HTML shell telemetry, accessibility, and Playwright E2E testing requirements for web loading lifecycle. +- **#TASK-02**: PR introduces customConfig with onProgress telemetry in custom_shell.html and refines loading overlay/ARIA per TASK-02. --- From 0221bf7f0124cb44264a0bde592369a9f8e05f7e Mon Sep 17 00:00:00 2001 From: Egor Kostan <20955183+ikostan@users.noreply.github.com> Date: Sun, 16 Aug 2026 21:26:33 -0700 Subject: [PATCH 35/35] Update test_utils.py --- tests/test_utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_utils.py b/tests/test_utils.py index d1c46330b..140782726 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -15,7 +15,7 @@ # Shared timeout configurations across test suites DEFAULT_TIMEOUT = int(os.getenv("DEFAULT_TIMEOUT", "30000")) -TEST_TIMEOUT = int(os.getenv("TEST_TIMEOUT", "10000")) +TEST_TIMEOUT = int(os.getenv("TEST_TIMEOUT", "15000")) LOG_LEVEL_MAP: dict[str, int] = { "DEBUG": 0,