Files
AlphaMaster/scripts/e2e_frontend_train_io.py
2026-07-10 18:14:59 +08:00

119 lines
4.1 KiB
Python

"""Real frontend E2E: click Export/Import training in browser.
This drives the actual web UI (buttons + file chooser) using Playwright.
It verifies:
- Export training triggers a .zip download
- Import training accepts that zip and returns to enabled state
Run:
python scripts/e2e_frontend_train_io.py
"""
from __future__ import annotations
import json
import time
from pathlib import Path
from playwright.sync_api import expect, sync_playwright
ROOT = Path(__file__).resolve().parents[1]
URL = "http://127.0.0.1:8765"
def main() -> None:
# Ensure there is a valid selected file (so buttons can enable)
# Use web_settings.json (already set to MT5_K线数据 ADAUSD_H1).
settings_path = ROOT / "web_settings.json"
if settings_path.exists():
data = json.loads(settings_path.read_text(encoding="utf-8"))
print("web_settings.json last_data_file:", data.get("last_data_file"))
downloads_dir = ROOT / "tmp_downloads"
downloads_dir.mkdir(exist_ok=True)
with sync_playwright() as p:
browser = p.chromium.launch(headless=True)
context = browser.new_context(accept_downloads=True)
page = context.new_page()
page.on("console", lambda m: print(f"[console:{m.type}] {m.text}"))
page.on("pageerror", lambda e: print(f"[pageerror] {e}"))
page.goto(URL, wait_until="networkidle")
# Wait for app.js to initialize state (loadConfig + refreshOverview)
for _ in range(20):
page.wait_for_timeout(500)
try:
# Force a refresh tick in case timers are throttled.
page.evaluate("window.refreshOverview && window.refreshOverview()")
except Exception:
pass
sym = page.evaluate("window.selectedSymbol")
df = page.evaluate("window.selectedDataFile")
if sym and df:
break
export_btn = page.locator("#exportTrainingBtn")
import_btn = page.locator("#importTrainingBtn")
file_input = page.locator("#importTrainingFile")
print("frontend selectedSymbol:", page.evaluate("window.selectedSymbol"))
print("frontend selectedDataFile:", page.evaluate("window.selectedDataFile"))
# Also check backend says checkpoint exists (helps debug why disabled).
backend_state = page.evaluate(
"""() => fetch('/api/overview').then(r=>r.json()).then(j=>({
symbol: j?.progress?.symbol,
has_checkpoint: j?.progress?.has_checkpoint,
active: j?.training?.active,
valid: j?.data_file?.valid
})).catch(e=>({error:String(e)}))"""
)
print("backend overview:", backend_state)
# Make sure we're not in training
stop_btn = page.locator("#stopBtn")
if not stop_btn.is_disabled():
stop_btn.click()
page.wait_for_timeout(1200)
# Export training: should be enabled when checkpoint exists and not active
expect(export_btn).to_be_enabled(timeout=30000)
with page.expect_download(timeout=30000) as dl_info:
export_btn.click()
download = dl_info.value
suggested = download.suggested_filename
out_path = downloads_dir / suggested
download.save_as(str(out_path))
if not out_path.exists() or out_path.stat().st_size < 1024:
raise SystemExit(f"export download failed: {out_path}")
print("exported:", out_path.name, out_path.stat().st_size, "bytes")
# Import training: enabled when symbol selected and not active.
expect(import_btn).to_be_enabled(timeout=15000)
import_btn.click()
file_input.set_input_files(str(out_path))
# Import triggers refreshOverview; wait for a client log info line or buttons state stable
page.wait_for_timeout(2500)
# After import, export should still be enabled.
expect(export_btn).to_be_enabled(timeout=15000)
# Sanity: chart canvas exists
expect(page.locator("#mainChart")).to_be_visible()
context.close()
browser.close()
print("E2E PASS: export/import via frontend works.")
if __name__ == "__main__":
main()