Improve backtest lazy loading and test automation

This commit is contained in:
Bu5hm4nn
2026-04-07 12:18:50 +02:00
parent ccc10923d9
commit b2bc4db41a
18 changed files with 504 additions and 300 deletions

View File

@@ -2,9 +2,11 @@ from __future__ import annotations
from pathlib import Path
import pytest
from playwright.sync_api import expect, sync_playwright
BASE_URL = "http://127.0.0.1:8100"
pytestmark = [pytest.mark.playwright, pytest.mark.e2e]
ARTIFACTS = Path("tests/artifacts")
ARTIFACTS.mkdir(parents=True, exist_ok=True)
@@ -46,18 +48,18 @@ def assert_stacked_pane_layout(page, left_testid: str, right_testid: str) -> Non
assert_no_horizontal_overflow(page)
def test_homepage_and_options_page_render() -> None:
def test_homepage_and_options_page_render(base_url: str) -> None:
with sync_playwright() as p:
browser = p.chromium.launch(headless=True)
page = browser.new_page(viewport={"width": 1440, "height": 1000})
page.goto(BASE_URL, wait_until="domcontentloaded", timeout=30000)
page.goto(base_url, wait_until="domcontentloaded", timeout=30000)
expect(page).to_have_title("NiceGUI")
expect(page.locator("text=Create a private workspace URL").first).to_be_visible(timeout=10000)
page.get_by_role("button", name="Get started").click()
page.wait_for_url(f"{BASE_URL}/*", timeout=15000)
page.wait_for_url(f"{base_url}/*", timeout=15000)
workspace_url = page.url
workspace_id = workspace_url.removeprefix(f"{BASE_URL}/")
workspace_id = workspace_url.removeprefix(f"{base_url}/")
assert workspace_id
workspace_cookie = None
for _ in range(5):
@@ -80,7 +82,7 @@ def test_homepage_and_options_page_render() -> None:
assert_stacked_pane_layout(page, "overview-left-pane", "overview-right-pane")
page.set_viewport_size({"width": 1440, "height": 1000})
page.goto(BASE_URL, wait_until="domcontentloaded", timeout=30000)
page.goto(base_url, wait_until="domcontentloaded", timeout=30000)
page.wait_for_url(workspace_url, timeout=15000)
expect(page.locator("text=Alert Status").first).to_be_visible(timeout=15000)
@@ -112,7 +114,7 @@ def test_homepage_and_options_page_render() -> None:
assert "Traceback" not in event_text
page.screenshot(path=str(ARTIFACTS / "event-comparison.png"), full_page=True)
page.goto(f"{BASE_URL}/options", wait_until="domcontentloaded", timeout=30000)
page.goto(f"{base_url}/options", wait_until="domcontentloaded", timeout=30000)
expect(page.locator("text=Options Chain").first).to_be_visible(timeout=15000)
expect(page.locator("text=Filters").first).to_be_visible(timeout=15000)
assert_two_pane_layout(page, "options-left-pane", "options-right-pane")
@@ -223,10 +225,10 @@ def test_homepage_and_options_page_render() -> None:
second_context = browser.new_context(viewport={"width": 1440, "height": 1000})
second_page = second_context.new_page()
second_page.goto(BASE_URL, wait_until="domcontentloaded", timeout=30000)
second_page.goto(base_url, wait_until="domcontentloaded", timeout=30000)
expect(second_page.locator("text=Create a private workspace URL").first).to_be_visible(timeout=10000)
second_page.get_by_role("button", name="Get started").click()
second_page.wait_for_url(f"{BASE_URL}/*", timeout=15000)
second_page.wait_for_url(f"{base_url}/*", timeout=15000)
second_workspace_url = second_page.url
assert second_workspace_url != workspace_url
second_page.goto(f"{second_workspace_url}/settings", wait_until="domcontentloaded", timeout=30000)
@@ -285,7 +287,7 @@ def test_homepage_and_options_page_render() -> None:
browser.close()
def test_backtest_page_loads_with_valid_databento_dates() -> None:
def test_backtest_page_loads_with_valid_databento_dates(base_url: str) -> None:
"""E2E test: Backtest page loads and validates Databento date range.
Regression test for CORE-003: Ensures backtest page handles Databento
@@ -296,10 +298,10 @@ def test_backtest_page_loads_with_valid_databento_dates() -> None:
page = browser.new_page(viewport={"width": 1440, "height": 1000})
# Create a workspace first (backtests page requires workspace_id)
page.goto(BASE_URL, wait_until="domcontentloaded", timeout=30000)
page.goto(base_url, wait_until="domcontentloaded", timeout=30000)
expect(page.locator("text=Create a private workspace URL").first).to_be_visible(timeout=10000)
page.get_by_role("button", name="Get started").click()
page.wait_for_url(f"{BASE_URL}/*", timeout=15000)
page.wait_for_url(f"{base_url}/*", timeout=15000)
workspace_url = page.url
# Navigate to backtests page with workspace
@@ -316,11 +318,12 @@ def test_backtest_page_loads_with_valid_databento_dates() -> None:
dataset = page.locator("[data-testid=dataset-select]")
expect(dataset).to_be_visible()
# Verify date range hint is visible (current behavior shows GLD hint on initial render)
# TODO: When Databento is selected by default, hint should show "XNAS.BASIC data available from 2024-07-01"
# Bug: update_date_range_hint() is not called on initial render for Databento
date_hint = page.locator("text=GLD data available from")
expect(date_hint).to_be_visible(timeout=5000)
# Verify dataset-specific availability hint and lazy preview copy are visible.
expect(page.locator("text=XNAS.BASIC data available from 2024-07-01")).to_be_visible(timeout=5000)
expect(
page.get_by_text("Preview not loaded yet. Heavy Databento lookups stay lazy until you request them.").first
).to_be_visible(timeout=5000)
expect(page.get_by_role("button", name="Load scenario preview")).to_be_visible(timeout=5000)
# Verify start date input has a valid date (dynamic default based on current date)
start_input = page.get_by_label("Start date")
@@ -337,7 +340,7 @@ def test_backtest_page_loads_with_valid_databento_dates() -> None:
browser.close()
def test_backtest_page_handles_invalid_dates_gracefully() -> None:
def test_backtest_page_handles_invalid_dates_gracefully(base_url: str) -> None:
"""E2E test: Backtest page shows validation error for invalid dates.
Regression test: Ensures user-friendly error instead of 500 when
@@ -348,10 +351,10 @@ def test_backtest_page_handles_invalid_dates_gracefully() -> None:
page = browser.new_page(viewport={"width": 1440, "height": 1000})
# Create a workspace first (backtests page requires workspace_id)
page.goto(BASE_URL, wait_until="domcontentloaded", timeout=30000)
page.goto(base_url, wait_until="domcontentloaded", timeout=30000)
expect(page.locator("text=Create a private workspace URL").first).to_be_visible(timeout=10000)
page.get_by_role("button", name="Get started").click()
page.wait_for_url(f"{BASE_URL}/*", timeout=15000)
page.wait_for_url(f"{base_url}/*", timeout=15000)
workspace_url = page.url
# Navigate to backtests page with workspace
@@ -373,7 +376,7 @@ def test_backtest_page_handles_invalid_dates_gracefully() -> None:
browser.close()
def test_backtest_scenario_runs_and_displays_results() -> None:
def test_backtest_scenario_runs_and_displays_results(base_url: str) -> None:
"""E2E test: Full backtest scenario execution with synthetic data.
This test verifies that:
@@ -389,13 +392,13 @@ def test_backtest_scenario_runs_and_displays_results() -> None:
page = browser.new_page(viewport={"width": 1440, "height": 1000})
# Step 1: Create a workspace
page.goto(BASE_URL, wait_until="domcontentloaded", timeout=30000)
page.goto(base_url, wait_until="domcontentloaded", timeout=30000)
expect(page).to_have_title("NiceGUI")
expect(page.locator("text=Create a private workspace URL").first).to_be_visible(timeout=10000)
page.get_by_role("button", name="Get started").click()
page.wait_for_url(f"{BASE_URL}/*", timeout=15000)
page.wait_for_url(f"{base_url}/*", timeout=15000)
workspace_url = page.url
workspace_id = workspace_url.removeprefix(f"{BASE_URL}/")
workspace_id = workspace_url.removeprefix(f"{base_url}/")
assert workspace_id, "Should have workspace ID in URL"
# Step 2: Navigate to backtests page with workspace