left4me/l4d2web/tests/e2e/conftest.py
mwiegand f030395a57
fix(e2e): force SESSION_COOKIE_SECURE=0 + document init_db duplication
Two follow-ups from the Task 11 code review.

Important — without SESSION_COOKIE_SECURE=0, Task 12's Playwright
login would silently fail. app.py:57 sets SESSION_COOKIE_SECURE = not
TESTING, so with our TESTING=False conftest the cookie is marked
Secure; the browser drops it over http://127.0.0.1 and the
session never establishes. The env-var override (app.py:53-55) is the
least invasive fix and preserves the SECRET_KEY guard.

Minor — the second init_db() looked redundant but is actually load-
bearing: create_app's init_db runs inside the app context (binds to
the in-app engine), while the seed work uses session_scope() outside
the app context (binds to an env-derived engine). The second
init_db() creates tables on THAT engine. Added a clarifying comment
so a future reader doesn't drop the line and silently break the seed.

Addresses Important #1 + Minor #1 from the Task 11 code review.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-16 21:07:15 +02:00

77 lines
2.5 KiB
Python

"""Pytest fixtures for end-to-end browser tests.
Boots the Flask app in a background thread on an ephemeral port and
yields the base URL. The app uses a temp SQLite DB so e2e runs don't
contaminate the dev database.
"""
import socket
import threading
import pytest
from werkzeug.serving import make_server
from l4d2web.app import create_app
from l4d2web.auth import hash_password
from l4d2web.db import init_db, session_scope
from l4d2web.models import Blueprint, User
def _free_port() -> int:
s = socket.socket()
s.bind(("127.0.0.1", 0))
port = s.getsockname()[1]
s.close()
return port
@pytest.fixture(scope="function")
def live_server(tmp_path, monkeypatch):
db_path = tmp_path / "e2e.db"
db_url = f"sqlite:///{db_path}"
monkeypatch.setenv("DATABASE_URL", db_url)
# app.py:57 sets SESSION_COOKIE_SECURE = not TESTING, which would
# mark the session cookie Secure. The browser then drops it over
# http://127.0.0.1 in e2e tests and the login flow silently fails
# with a redirect back to /login. Force it off explicitly via the
# env-var override (app.py:53-55) rather than flipping TESTING,
# which would skip the SECRET_KEY guard and other production paths.
monkeypatch.setenv("SESSION_COOKIE_SECURE", "0")
app = create_app({"TESTING": False, "DATABASE_URL": db_url, "SECRET_KEY": "e2e"})
# create_app() already calls init_db() inside an app context, which
# binds tables to the in-app engine. The seed work below uses
# session_scope() OUTSIDE any app context, which reads DATABASE_URL
# from the environment and binds its own engine. This second init_db()
# call creates the tables on that env-derived engine so the seed
# inserts have somewhere to land.
init_db()
with session_scope() as session:
user = User(
username="alice",
password_digest=hash_password("secret"),
admin=False,
)
session.add(user)
session.flush()
bp = Blueprint(
user_id=user.id, name="bp", arguments="[]", config="[]"
)
session.add(bp)
session.flush()
blueprint_id = bp.id
user_id = user.id
port = _free_port()
server = make_server("127.0.0.1", port, app)
thread = threading.Thread(target=server.serve_forever, daemon=True)
thread.start()
try:
yield {
"base_url": f"http://127.0.0.1:{port}",
"user_id": user_id,
"blueprint_id": blueprint_id,
}
finally:
server.shutdown()
thread.join(timeout=2)