diff --git a/SPECGAPS.md b/SPECGAPS.md index 685b12d..98b38ca 100644 --- a/SPECGAPS.md +++ b/SPECGAPS.md @@ -142,7 +142,7 @@ All reconciled to follow code. Specs must be self-consistent and match code. | ~~D2-2~~ | ~~CreateAndPublishTemplate rule~~ | template.allium:105 | **Resolved:** added `create_and_publish_template/1` (validates Liquid, creates published template + writs file), 3 tests added (happy path file assertions, invalid liquid rejection, slug dedup on title conflict) | | ~~D2-3~~ | ~~CreateAndPublishScript rule~~ | ~~script.allium:160~~ | **Resolved:** `create_and_publish_script/1` implemented in scripts.ex, 4 tests added (happy path with file assertions + macro entrypoint default + invalid Lua rejection + slug dedup on title conflict) | | ~~D2-4~~ | ~~UniqueScriptSlug dedup~~ | ~~script.allium:115~~ | **Resolved:** test added asserting two scripts with same title produce unique slugs (`dup-slug` → `dup-slug-2`) | -| D2-5 | FrontmatterRoundtrip invariant | post.allium:223 | Write test: write file, read back, assert all DB fields match | +| D2-5 | ~~FrontmatterRoundtrip invariant~~ | post.allium:223 | **Resolved:** test added — creates post with all fields, publishes, parses file back via `Frontmatter.parse_document`, asserts every field (id, title, slug, excerpt, status, author, language, doNotTranslate, templateSlug, tags, categories, createdAt, updatedAt, publishedAt, body) matches the published DB record | | D2-6 | SidecarRoundtrip invariant | media.allium:198 | Write test: write sidecar, read back, assert all fields match | | D2-7 | ConditionalPostFields: nil fields absent from frontmatter | frontmatter.allium:398 | Write test: post with nil excerpt/author/language → fields not in file | | D2-8 | ConditionalMediaFields: nil fields absent from sidecar | frontmatter.allium:417 | Write test: media with nil title/alt → fields not in sidecar | diff --git a/test/bds/posts_test.exs b/test/bds/posts_test.exs index 2e2f58b..8c110ec 100644 --- a/test/bds/posts_test.exs +++ b/test/bds/posts_test.exs @@ -188,6 +188,54 @@ defmodule BDS.PostsTest do refute File.exists?(full_path <> ".tmp") end + test "post frontmatter roundtrips: written fields parsed back match the database record", %{ + project: project, + temp_dir: temp_dir + } do + assert {:ok, post} = + BDS.Posts.create_post(%{ + project_id: project.id, + title: "Full Roundtrip", + excerpt: "Testing full roundtrip", + content: "Body content survives roundtrip", + tags: ["elixir", "testing"], + categories: ["notes"], + author: "Test Author", + language: "de", + template_slug: "article" + }) + + assert {:ok, post} = BDS.Posts.update_post(post.id, %{do_not_translate: true}) + assert {:ok, published} = BDS.Posts.publish_post(post.id) + assert published.status == :published + + full_path = Path.join(temp_dir, published.file_path) + assert File.exists?(full_path) + + file_contents = File.read!(full_path) + assert {:ok, %{fields: fields, body: body}} = BDS.Frontmatter.parse_document(file_contents) + + assert fields["id"] == published.id + assert fields["title"] == "Full Roundtrip" + assert fields["slug"] == "full-roundtrip" + assert fields["excerpt"] == "Testing full roundtrip" + assert fields["status"] == "published" + assert fields["author"] == "Test Author" + assert fields["language"] == "de" + assert fields["doNotTranslate"] == true + assert fields["templateSlug"] == "article" + assert fields["tags"] == ["elixir", "testing"] + assert fields["categories"] == ["notes"] + assert is_integer(fields["createdAt"]) + assert fields["createdAt"] == published.created_at + assert is_integer(fields["updatedAt"]) + assert fields["updatedAt"] == published.updated_at + assert is_integer(fields["publishedAt"]) + assert fields["publishedAt"] == published.published_at + + assert body == "Body content survives roundtrip" + end + test "publish_post omits doNotTranslate from frontmatter when false", %{ project: project, temp_dir: temp_dir