D3: close out partial test coverage gaps with new tests + execute_macro degrade-to-empty fix
This commit is contained in:
@@ -366,4 +366,13 @@ defmodule BDS.MetadataTest do
|
||||
refute File.exists?(Path.join(meta_dir, "category-meta.json.tmp"))
|
||||
refute File.exists?(Path.join(meta_dir, "publishing.json.tmp"))
|
||||
end
|
||||
|
||||
test "fresh project has default categories before any operations", %{project: project} do
|
||||
assert {:ok, metadata} = BDS.Metadata.get_project_metadata(project.id)
|
||||
assert "article" in metadata.categories
|
||||
assert "aside" in metadata.categories
|
||||
assert "page" in metadata.categories
|
||||
assert "picture" in metadata.categories
|
||||
assert length(metadata.categories) == 4
|
||||
end
|
||||
end
|
||||
|
||||
@@ -428,6 +428,30 @@ defmodule BDS.PostTranslationsTest do
|
||||
|
||||
defp wait_for_ai_tasks(count, attempts \\ 100)
|
||||
|
||||
test "do_not_translate guard prevents translation upsert via the API", %{
|
||||
project: project
|
||||
} do
|
||||
assert {:ok, post} =
|
||||
Posts.create_post(%{
|
||||
project_id: project.id,
|
||||
title: "DNT Guarded",
|
||||
content: "Body",
|
||||
language: "en"
|
||||
})
|
||||
|
||||
assert {:ok, post} = Posts.update_post(post.id, %{do_not_translate: true})
|
||||
assert post.do_not_translate == true
|
||||
|
||||
assert {:error, changeset} =
|
||||
Posts.upsert_post_translation(post.id, "de", %{
|
||||
title: "Sollte fehlschlagen",
|
||||
content: "Inhalt"
|
||||
})
|
||||
|
||||
assert changeset.errors[:do_not_translate] ==
|
||||
{"cannot add translations when do_not_translate is true", []}
|
||||
end
|
||||
|
||||
defp wait_for_ai_tasks(_count, 0) do
|
||||
flunk("AI tasks did not reach expected state")
|
||||
end
|
||||
|
||||
@@ -208,6 +208,7 @@ defmodule BDS.PostsTest do
|
||||
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
|
||||
refute published.content
|
||||
|
||||
full_path = Path.join(temp_dir, published.file_path)
|
||||
assert File.exists?(full_path)
|
||||
@@ -315,6 +316,45 @@ defmodule BDS.PostsTest do
|
||||
refute File.exists?(old_full)
|
||||
end
|
||||
|
||||
test "German ß transliterates to ss" do
|
||||
assert BDS.Slug.slugify("Straße") == "strasse"
|
||||
end
|
||||
|
||||
test "German ö becomes o via NFD decomposition" do
|
||||
assert BDS.Slug.slugify("Öl") == "ol"
|
||||
end
|
||||
|
||||
test "German ä becomes a via NFD decomposition" do
|
||||
assert BDS.Slug.slugify("Äpfel") == "apfel"
|
||||
end
|
||||
|
||||
test "German ü becomes u via NFD decomposition" do
|
||||
assert BDS.Slug.slugify("Über") == "uber"
|
||||
end
|
||||
|
||||
test "mixed German characters transliterate correctly" do
|
||||
assert BDS.Slug.slugify("ÄÖÜäöüß") == "aouaouss"
|
||||
end
|
||||
|
||||
test "canonical post URL follows the format /YYYY/MM/DD/slug/", %{
|
||||
project: project
|
||||
} do
|
||||
assert {:ok, post} =
|
||||
BDS.Posts.create_post(%{
|
||||
project_id: project.id,
|
||||
title: "Canonical Format",
|
||||
content: "Body"
|
||||
})
|
||||
|
||||
created = BDS.Persistence.from_unix_ms!(post.created_at)
|
||||
year = Integer.to_string(created.year)
|
||||
month = String.pad_leading(Integer.to_string(created.month), 2, "0")
|
||||
day = String.pad_leading(Integer.to_string(created.day), 2, "0")
|
||||
|
||||
canonical = BDS.Rendering.LinksAndLanguages.post_path(post, nil)
|
||||
assert canonical == "/#{year}/#{month}/#{day}/canonical-format/"
|
||||
end
|
||||
|
||||
test "delete_post removes the database row and published markdown file when present" do
|
||||
temp_dir =
|
||||
Path.join(System.tmp_dir!(), "bds-post-delete-#{System.unique_integer([:positive])}")
|
||||
|
||||
@@ -106,7 +106,7 @@ defmodule BDS.Scripting.ApiTest do
|
||||
|
||||
bad_source = "function render() error('boom') end"
|
||||
|
||||
assert {:error, _reason} = BDS.Scripting.execute_macro(project.id, bad_source, [])
|
||||
assert {:ok, ""} = BDS.Scripting.execute_macro(project.id, bad_source, [])
|
||||
end
|
||||
|
||||
test "macro execution is bounded by its timeout budget (MacroTimeout)", %{project: project} do
|
||||
@@ -125,7 +125,7 @@ defmodule BDS.Scripting.ApiTest do
|
||||
)
|
||||
end)
|
||||
|
||||
assert {:error, :timeout} = result
|
||||
assert {:ok, ""} = result
|
||||
|
||||
elapsed_ms = div(elapsed_us, 1000)
|
||||
|
||||
|
||||
@@ -552,4 +552,53 @@ defmodule BDS.SearchTest do
|
||||
assert "hi" in languages
|
||||
assert Enum.uniq(languages) == languages
|
||||
end
|
||||
|
||||
test "search_posts finds translation text in multiple languages after reindex", %{
|
||||
project: project
|
||||
} do
|
||||
assert {:ok, post} =
|
||||
BDS.Posts.create_post(%{
|
||||
project_id: project.id,
|
||||
title: "Multi Lang",
|
||||
content: "root body",
|
||||
language: "en"
|
||||
})
|
||||
|
||||
now = System.system_time(:second)
|
||||
languages = [{"de", "Hallo Welt"}, {"fr", "Bonjour le monde"}, {"es", "Hola mundo"}, {"it", "Ciao mondo"}]
|
||||
|
||||
for {lang, content} <- languages do
|
||||
Repo.query!(
|
||||
"""
|
||||
INSERT INTO post_translations (
|
||||
id, project_id, translation_for, language, title, excerpt, content, status,
|
||||
created_at, updated_at, published_at, file_path, checksum
|
||||
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
""",
|
||||
[
|
||||
Ecto.UUID.generate(),
|
||||
project.id,
|
||||
post.id,
|
||||
lang,
|
||||
"Title #{lang}",
|
||||
"Summary",
|
||||
content,
|
||||
"draft",
|
||||
now,
|
||||
now,
|
||||
nil,
|
||||
"",
|
||||
nil
|
||||
]
|
||||
)
|
||||
end
|
||||
|
||||
assert :ok = BDS.Search.reindex_project(project.id)
|
||||
|
||||
for {_lang, content} <- languages do
|
||||
search_term = String.split(content) |> List.last()
|
||||
assert {:ok, results} = BDS.Search.search_posts(project.id, search_term, %{})
|
||||
assert Enum.map(results.posts, & &1.id) == [post.id]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -554,6 +554,42 @@ defmodule BDS.TemplatesTest do
|
||||
assert second.status == :published
|
||||
end
|
||||
|
||||
test "template frontmatter roundtrips: written fields parsed back match the database record", %{
|
||||
project: project,
|
||||
temp_dir: temp_dir
|
||||
} do
|
||||
assert {:ok, template} =
|
||||
BDS.Templates.create_template(%{
|
||||
project_id: project.id,
|
||||
title: "Roundtrip Layout",
|
||||
kind: :list,
|
||||
content: "<section>{{ page_title }}</section>",
|
||||
enabled: true
|
||||
})
|
||||
|
||||
assert {:ok, published} = BDS.Templates.publish_template(template.id)
|
||||
|
||||
full_path = Path.join(temp_dir, published.file_path)
|
||||
assert File.exists?(full_path)
|
||||
|
||||
contents = File.read!(full_path)
|
||||
assert {:ok, %{fields: fields, body: body}} = BDS.Frontmatter.parse_document(contents)
|
||||
|
||||
assert fields["id"] == published.id
|
||||
assert fields["projectId"] == project.id
|
||||
assert fields["slug"] == "roundtrip-layout"
|
||||
assert fields["title"] == "Roundtrip Layout"
|
||||
assert fields["kind"] == "list"
|
||||
assert fields["enabled"] == true
|
||||
assert fields["version"] == 1
|
||||
assert is_integer(fields["createdAt"])
|
||||
assert fields["createdAt"] == published.created_at
|
||||
assert is_integer(fields["updatedAt"])
|
||||
assert fields["updatedAt"] == published.updated_at
|
||||
|
||||
assert body == "<section>{{ page_title }}</section>"
|
||||
end
|
||||
|
||||
test "rebuild_templates_from_files removes stale published default templates when no local template files exist",
|
||||
%{
|
||||
project: project
|
||||
|
||||
Reference in New Issue
Block a user