Files
chicken_babies_site/tests/conftest.py
Phillip Tarrant 0306f71763 feat: phase 2 content model + cache — SQLite schema, markdown, TTL
Stand up the full SQLite content layer: all 7 tables from the authoritative
schema with WAL + foreign-keys enforced per-connection, entity dataclasses
plus row mappers, hand-rolled versioned migrations tracked in
schema_migrations, and an idempotent Python seed (system user + welcome
post + About page).

Add a Markdown->HTML service using markdown-it-py with a strict bleach
allowlist (tables intentionally omitted on both sides). Add a typed
in-process TTLCache[K,V] and wire it into real DB-backed PostService and
PageService, both exposing invalidate_all() for Phase 4 admin writes.

Rewire / and /about to read from the DB; homepage renders the seeded
welcome post, About renders page.title + sanitized body_html_cached.
Update the Phase 1 route tests accordingly.

Mark Phase 2 complete in docs/ROADMAP.md.
2026-04-21 15:40:35 -05:00

57 lines
1.8 KiB
Python

"""Shared pytest fixtures for the ``chicken_babies_site`` suite.
Key fixtures:
- ``db_engine``: a session-scoped SQLAlchemy engine pointed at a
temp-file SQLite database. Migrations + seed run once per test
session. Per the CLAUDE.md mandate, tests do NOT mock the DB —
they use a real SQLite file so behavior matches production.
- ``clean_db_engine``: a function-scoped engine with migrations
applied but seed NOT run, for tests that need to exercise the
first-boot path.
"""
from __future__ import annotations
from pathlib import Path
from typing import Iterator
import pytest
from sqlalchemy import Engine
from app.db import build_engine, run_migrations
from app.models.seed import run_seed
@pytest.fixture(scope="session")
def db_engine(tmp_path_factory: pytest.TempPathFactory) -> Iterator[Engine]:
"""Return a migrated + seeded SQLite engine shared across the session.
Uses a real on-disk file (NOT ``:memory:``) because the CLAUDE.md
project rules forbid mocking the DB in auth / magic-link tests,
and doing the same here keeps the behavior identical to
production.
"""
db_path: Path = tmp_path_factory.mktemp("db") / "test.db"
engine = build_engine(f"sqlite:///{db_path}")
run_migrations(engine)
run_seed(engine)
yield engine
engine.dispose()
@pytest.fixture
def clean_db_engine(tmp_path: Path) -> Iterator[Engine]:
"""Return a fresh engine with tables created but NO seed data.
Function-scoped so each test that uses it starts with a virgin
database — useful for asserting first-run seed behavior and
migration idempotency without contaminating the session-scoped
``db_engine``.
"""
db_path = tmp_path / "clean.db"
engine = build_engine(f"sqlite:///{db_path}")
run_migrations(engine)
yield engine
engine.dispose()