test(i18n): integration render tests for 4 locales + Playwright E2E flow (closes #77)
This commit is contained in:
97
tests/E2E/language_flow.py
Normal file
97
tests/E2E/language_flow.py
Normal 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())
|
||||
Reference in New Issue
Block a user