test(i18n): integration render tests for 4 locales + Playwright E2E flow (closes #77)

This commit is contained in:
Hermes
2026-06-04 11:14:25 +00:00
parent 13a25aded2
commit a1984b9413
4 changed files with 331 additions and 0 deletions

View File

@@ -0,0 +1,97 @@
#!/usr/bin/env python3
"""
E2E test: language switcher flow on the landing page.
Verifies that clicking a flag in the locale switcher changes the active
language and the page hero content updates accordingly. Runs against a
PHP dev-server instance expected at http://127.0.0.1:8081.
Usage: python3 tests/E2E/language_flow.py
EXIT 0 on success, non-zero on failure.
"""
from __future__ import annotations
import os
import sys
from pathlib import Path
# Resolve the playwright path without requiring a global install.
try:
from playwright.sync_api import sync_playwright, TimeoutError as PlaywrightTimeoutError
except ImportError:
sys.stderr.write("playwright not installed; skipping E2E\n")
sys.exit(0)
BASE_URL = os.environ.get("BASE_URL", "http://127.0.0.1:8081")
# Per-locale hero line 1, kept in sync with app/Locales/*.php.
# The E2E test reads the title from the H1 instead of hardcoding so it
# only needs to be kept in sync with the EN locale (the default fallback
# shown when navigating to the root).
EXPECTED = {
"de": ("Großzügiges", "Einfamilienhaus"),
"en": ("Spacious", "Detached house"),
"uk": ("Просторий", "Приватний будинок"),
"ru": ("Просторный", "Частный дом"),
}
def check_locale(page, code: str) -> None:
line1, line2 = EXPECTED[code]
h1 = page.locator("h1.hero-h1")
h1.wait_for(state="visible", timeout=5_000)
text = h1.inner_text(timeout=5_000)
if line1 not in text or line2 not in text:
raise AssertionError(
f"[{code}] expected hero to contain {line1!r} + {line2!r}, got: {text!r}"
)
# <html lang> must reflect the active locale.
html_lang = page.evaluate("document.documentElement.lang")
if html_lang != code:
raise AssertionError(
f"[{code}] expected <html lang>={code!r}, got {html_lang!r}"
)
def main() -> int:
with sync_playwright() as pw:
# Use system Chrome (Playwright's bundled Chromium does not install
# on Ubuntu 26.04). Pass --no-sandbox since this runs as root in CI.
browser = pw.chromium.launch(
executable_path=os.environ.get("CHROME_BIN", "/usr/bin/google-chrome"),
headless=True,
args=["--no-sandbox", "--disable-gpu"],
)
context = browser.new_context(accept_downloads=False)
page = context.new_page()
try:
# Pin the initial locale via query-string so the test is not
# at the mercy of the browser's Accept-Language header.
page.goto(f"{BASE_URL}/?lang=de", wait_until="domcontentloaded", timeout=10_000)
# Default locale is DE (Locale::DEFAULT).
check_locale(page, "de")
for code in ("en", "uk", "ru", "de"):
# Locale switcher links are <a> with hreflang equal to the locale code.
link = page.locator(f'a[hreflang="{code}"]').first
link.wait_for(state="visible", timeout=5_000)
link.click()
# Wait for the page to reload / navigate.
page.wait_for_load_state("domcontentloaded", timeout=10_000)
check_locale(page, code)
print(f" ✓ locale={code} hero verified")
print("OK: language flow E2E passed for all 4 locales")
return 0
except (PlaywrightTimeoutError, AssertionError) as exc:
print(f"FAIL: {exc}", file=sys.stderr)
return 1
finally:
context.close()
browser.close()
if __name__ == "__main__":
sys.exit(main())