o2o-site-AEO/solution/backend/tests/test_mockup_blog.py
Mina Choi db7c9254f5 [feat] solution/backend: 목업(stay·stay2) 사업장 글이 게재되면 index.html 의 미니블로그만 갈아 끼움
stay 는 굽기 보호 주소라 그 사업장 글을 승인하면 발행이 거절되고 글은 승인 상태로 남았다.
목업 화면의 미니블로그는 파일에 박힌 글이라 승인해도 바뀌지 않았다.

- services/mockup_blog.py: window.__SITE_PAYLOAD__.posts 만 교체 — 기존 글 유지 · 새 글 추가 · 최신순, 직전 파일은 index.html.bak-blog
- build_service: 발행 주소가 stay·stay2 면 굽지 않고 글만 갱신 후 승인분을 게재로(버전·Teams 실패 알림 없음)

테스트 3건 추가(test_mockup_blog). 빌드·블로그·롤백·썸네일 105 passed

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 11:26:54 +09:00

81 lines
3.5 KiB
Python

import json
import uuid
from sqlalchemy import text
from common.enums import PostStatus
from crud.job_crud import JobQueue
from services import mockup_blog
from worker.handlers import build_handler
from worker.runner import Worker
MOCKUP_HTML = (
'<html><head></head><body><div id="root">옛 마크업</div>'
'<script>window.__SITE_PAYLOAD__ = {"site":{"slug":"stay"},"posts":[{"postId":"old","body":"옛 글","publishedAt":"2026-09-01T00:00:00+00:00"}]};</script>'
'</body></html>'
)
def _write_mockup(tmp_path, monkeypatch, slug="stay"):
monkeypatch.setenv("SITE_OUTPUT_DIR", str(tmp_path))
page = tmp_path / "s" / slug
page.mkdir(parents=True)
(page / "index.html").write_text(MOCKUP_HTML, encoding="utf-8")
return page / "index.html"
def _posts(html: str) -> list[dict]:
start = html.index("{", html.index(mockup_blog.PAYLOAD_MARKER))
return json.JSONDecoder().raw_decode(html, start)[0]["posts"]
def test_목업만_대상이다():
assert mockup_blog.is_mockup("stay")
assert mockup_blog.is_mockup("stay2")
assert not mockup_blog.is_mockup("stay3")
assert not mockup_blog.is_mockup("euro")
def test_새_글을_더하고_옛_글은_남기고_최신순이다(tmp_path, monkeypatch):
path = _write_mockup(tmp_path, monkeypatch)
count = mockup_blog.refresh_posts("stay", [
{"post_id": "new", "body": "새 글 </script> 포함", "published_at": "2026-10-01T00:00:00+00:00"},
{"post_id": "empty", "body": " ", "published_at": "2026-10-02T00:00:00+00:00"},
])
html = path.read_text(encoding="utf-8")
assert count == 2
assert [p["postId"] for p in _posts(html)] == ["new", "old"]
assert "</script> 포함" not in html
assert '<div id="root">옛 마크업</div>' in html
assert (path.parent / mockup_blog.BACKUP_NAME).read_text(encoding="utf-8") == MOCKUP_HTML
async def test_목업_사업장_발행은_굽지_않고_글만_바꾸고_게재로_넘긴다(auth_headers, client, db_engine, tmp_path, monkeypatch):
path = _write_mockup(tmp_path, monkeypatch)
h = await auth_headers("mockup-owner")
pid = (await client.post("/v1/place", headers=h, json={"name": "목업펜션", "category": 1})).json()["place"]["place_id"]
post_id = uuid.uuid4()
async with db_engine.begin() as c:
owner = (await c.execute(text("SELECT owner_user_id FROM places WHERE place_id = :p"), {"p": pid})).scalar()
await c.execute(
text("INSERT INTO sites (site_id, place_id, status, domain) VALUES (:s, :p, 1, 'stay')"),
{"s": uuid.uuid4(), "p": pid},
)
await c.execute(
text("INSERT INTO place_posts (post_id, place_id, body, topic_kind, topic_key, status, approved_at) "
"VALUES (:id, :p, '승인된 새 글입니다', 1, 'fog', :st, now())"),
{"id": post_id, "p": pid, "st": PostStatus.APPROVED.value},
)
await JobQueue().enqueue(4, {"place_id": pid, "owner_user_id": str(owner), "publish": True})
assert await Worker("w", JobQueue(), build_handler(), job_deadline_sec=60).process_one() is True
assert [p["postId"] for p in _posts(path.read_text(encoding="utf-8"))][0] == str(post_id)
async with db_engine.begin() as c:
status = (await c.execute(text("SELECT status FROM place_posts WHERE post_id = :id"), {"id": post_id})).scalar()
versions = (await c.execute(text("SELECT count(*) FROM site_versions"))).scalar()
assert status == PostStatus.PUBLISHED.value
assert versions == 0