import pytest from sqlalchemy import text from web.app import app from web.db import ( db_init, create_or_update_user, list_email_templates, update_email_template, _ensure_session, ensure_default_email_template, ) from web.email_templates import render_job_alert_email @pytest.fixture(scope="function", autouse=True) def setup_database(): app.config.update(TESTING=True, WTF_CSRF_ENABLED=False) with app.app_context(): db_init() create_or_update_user("admin", password="secret", is_admin=True, is_active=True) with _ensure_session() as session: session.execute(text("DELETE FROM email_templates")) session.commit() ensure_default_email_template() yield with _ensure_session() as session: session.execute(text("DELETE FROM email_templates")) session.commit() ensure_default_email_template() @pytest.fixture def client(): with app.test_client() as test_client: with test_client.session_transaction() as sess: sess["username"] = "admin" yield test_client @pytest.fixture def anon_client(): with app.test_client() as test_client: with test_client.session_transaction() as sess: sess.pop("username", None) yield test_client def test_email_templates_requires_admin(anon_client): response = anon_client.get("/admin/email-templates") assert response.status_code == 302 assert "/login" in response.headers.get("Location", "") def test_email_templates_lists_default(client): response = client.get("/admin/email-templates") assert response.status_code == 200 assert b"job-alert" in response.data def test_email_templates_create_update_delete(client): # Create response = client.post( "/admin/email-templates", data={ "action": "create", "name": "Daily Summary", "slug": "daily-summary", "subject": "Summary: {count_label}", "body": "Jobs:{jobs_section}", "is_active": "on", }, follow_redirects=False, ) assert response.status_code == 302 templates = list_email_templates() assert any(t["slug"] == "daily-summary" for t in templates) # Update template_row = next(t for t in templates if t["slug"] == "daily-summary") response = client.post( "/admin/email-templates", data={ "action": "update", "template_id": template_row["template_id"], "name": "Daily Summary", "slug": "daily-summary", "subject": "Updated: {count_label}", "body": "Updated body {jobs_section}", }, follow_redirects=False, ) assert response.status_code == 302 updated = list_email_templates() updated_row = next(t for t in updated if t["slug"] == "daily-summary") assert "Updated:" in updated_row["subject"] # Delete response = client.post( "/admin/email-templates", data={ "action": "delete", "template_id": updated_row["template_id"], }, follow_redirects=False, ) assert response.status_code == 302 slugs = [t["slug"] for t in list_email_templates()] assert "daily-summary" not in slugs def test_email_templates_preview(client): templates = list_email_templates() job_alert = next(t for t in templates if t["slug"] == "job-alert") response = client.get(f"/admin/email-templates?preview_id={job_alert['template_id']}") assert response.status_code == 200 assert b"Preview" in response.data assert b"Subject" in response.data def test_render_job_alert_email_uses_template_override(client): templates = list_email_templates() job_alert = next(t for t in templates if t["slug"] == "job-alert") update_email_template( job_alert["template_id"], subject="Custom Subject {count}", body="Body {jobs_message}", ) rendered = render_job_alert_email([ { "title": "Python Developer", "company": "Acme", "location": "Remote", "url": "https://example.com", } ]) assert rendered["subject"].startswith("Custom Subject") assert "Python Developer" in rendered["body"]