You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

120 lines
3.3 KiB

from __future__ import annotations
import os
import socket
import subprocess
import sys
import time
from collections.abc import Iterator
from pathlib import Path
import pytest
PROJECT_ROOT = Path(__file__).resolve().parents[2]
def _find_free_port() -> int:
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
sock.bind(("127.0.0.1", 0))
return int(sock.getsockname()[1])
def _wait_for_server_ready(base_url: str, timeout_seconds: float = 20.0) -> None:
import urllib.error
import urllib.request
health_url = f"{base_url}/health"
deadline = time.monotonic() + timeout_seconds
while time.monotonic() < deadline:
try:
with urllib.request.urlopen(health_url, timeout=1.0) as response:
if response.status == 200:
return
except (urllib.error.URLError, TimeoutError):
time.sleep(0.2)
raise RuntimeError(f"Timed out waiting for test server at {health_url}")
@pytest.fixture(scope="session")
def e2e_environment(tmp_path_factory: pytest.TempPathFactory) -> Iterator[dict[str, str]]:
workspace = tmp_path_factory.mktemp("hw-e2e")
db_path = workspace / "happywedding-e2e.db"
port = _find_free_port()
base_url = f"http://127.0.0.1:{port}"
env = os.environ.copy()
env["DATABASE_URL"] = f"sqlite:///{db_path}"
env["FLASK_APP"] = "run.py"
env["PYTHONUNBUFFERED"] = "1"
for command in (
[sys.executable, "-m", "flask", "db", "upgrade"],
[sys.executable, "-m", "flask", "seed-all"],
[sys.executable, "-m", "flask", "seed-demo"],
):
subprocess.run(command, cwd=PROJECT_ROOT, env=env, check=True)
server_process = subprocess.Popen(
[
sys.executable,
"-m",
"flask",
"run",
"--host",
"127.0.0.1",
"--port",
str(port),
"--no-debugger",
"--no-reload",
],
cwd=PROJECT_ROOT,
env=env,
stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL,
)
try:
_wait_for_server_ready(base_url)
yield {
"base_url": base_url,
"db_path": os.fspath(db_path),
}
finally:
server_process.terminate()
try:
server_process.wait(timeout=10)
except subprocess.TimeoutExpired:
server_process.kill()
server_process.wait(timeout=5)
@pytest.fixture(scope="session")
def base_url(e2e_environment: dict[str, str]) -> str:
return e2e_environment["base_url"]
@pytest.fixture(scope="function")
def browser_context_args(browser_context_args: dict[str, object]) -> dict[str, object]:
return {
**browser_context_args,
"locale": "zh-CN",
"timezone_id": "Asia/Shanghai",
"viewport": {"width": 1440, "height": 1080},
}
@pytest.fixture(scope="function")
def admin_credentials() -> dict[str, str]:
return {"username": "admin", "password": "ChangeMe123!"}
@pytest.fixture(scope="function")
def entry_credentials() -> dict[str, str]:
return {"username": "entry-demo", "password": "EntryDemo123!"}
@pytest.fixture(scope="function")
def quick_editor_credentials() -> dict[str, str]:
return {"username": "quick-editor-demo", "password": "QuickEditor123!"}