berrypod/test/berrypod/legal_pages_test.exs
jamey 93ff66debc
Some checks failed
deploy / deploy (push) Has been cancelled
add legal page editor integration and media library polish
Legal pages (privacy, delivery, terms) now auto-populate content from
shop settings on mount, show auto-generated vs customised badges, and
have a regenerate button. Theme editor gains alt text fields for logo,
header, and icon images. Image picker in page builder now has an upload
button and alt text warning badges. Clearing unused image references
shows an orphan info flash.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-28 17:55:02 +00:00

348 lines
11 KiB
Elixir

defmodule Berrypod.LegalPagesTest do
use Berrypod.DataCase, async: true
alias Berrypod.LegalPages
alias Berrypod.Settings
# ---------------------------------------------------------------------------
# Helpers
# ---------------------------------------------------------------------------
defp has_heading?(blocks, text) do
Enum.any?(blocks, &(&1.type == :heading and &1.text == text))
end
defp has_text_containing?(blocks, fragment) do
Enum.any?(blocks, fn block ->
case block do
%{text: text} when is_binary(text) -> String.contains?(text, fragment)
%{items: items} -> Enum.any?(items, &String.contains?(&1, fragment))
_ -> false
end
end)
end
# ---------------------------------------------------------------------------
# privacy_content/0
# ---------------------------------------------------------------------------
describe "privacy_content/0" do
test "returns a list of blocks with :lead as the first" do
blocks = LegalPages.privacy_content()
assert is_list(blocks)
assert hd(blocks).type == :lead
end
test "last block is a :closing disclaimer" do
blocks = LegalPages.privacy_content()
assert List.last(blocks).type == :closing
assert String.contains?(List.last(blocks).text, "legal advice")
end
test "always includes core sections" do
blocks = LegalPages.privacy_content()
assert has_heading?(blocks, "What we collect")
assert has_heading?(blocks, "Payment")
assert has_heading?(blocks, "Cookies")
assert has_heading?(blocks, "Third parties")
assert has_heading?(blocks, "Your rights")
assert has_heading?(blocks, "Contact")
end
test "includes PECR cart recovery wording for GB shop" do
Settings.put_setting("shop_country", "GB")
Settings.set_abandoned_cart_recovery(true)
blocks = LegalPages.privacy_content()
assert has_heading?(blocks, "Cart recovery")
assert has_text_containing?(blocks, "PECR")
assert has_text_containing?(blocks, "Regulation 22")
end
test "includes GDPR legitimate interests wording for EU shop" do
Settings.put_setting("shop_country", "DE")
Settings.set_abandoned_cart_recovery(true)
blocks = LegalPages.privacy_content()
assert has_heading?(blocks, "Cart recovery")
assert has_text_containing?(blocks, "Article 6(1)(f)")
refute has_text_containing?(blocks, "PECR")
end
test "includes generic cart recovery wording for non-UK/EU shop" do
Settings.put_setting("shop_country", "US")
Settings.set_abandoned_cart_recovery(true)
blocks = LegalPages.privacy_content()
assert has_heading?(blocks, "Cart recovery")
refute has_text_containing?(blocks, "PECR")
refute has_text_containing?(blocks, "Article 6(1)(f)")
end
test "omits cart recovery section when feature is disabled" do
Settings.set_abandoned_cart_recovery(false)
blocks = LegalPages.privacy_content()
refute has_heading?(blocks, "Cart recovery")
end
test "includes newsletter section when enabled" do
Settings.put_setting("newsletter_enabled", true, "boolean")
blocks = LegalPages.privacy_content()
assert has_heading?(blocks, "Newsletter")
end
test "omits newsletter section when disabled" do
Settings.put_setting("newsletter_enabled", false, "boolean")
blocks = LegalPages.privacy_content()
refute has_heading?(blocks, "Newsletter")
end
test "includes jurisdiction language in lead for GB" do
Settings.put_setting("shop_country", "GB")
blocks = LegalPages.privacy_content()
assert has_text_containing?(blocks, "UK GDPR")
assert has_text_containing?(blocks, "PECR")
end
test "includes GDPR jurisdiction language for EU country" do
Settings.put_setting("shop_country", "FR")
blocks = LegalPages.privacy_content()
assert has_text_containing?(blocks, "EU General Data Protection Regulation")
end
test "includes contact email when set" do
Settings.put_setting("contact_email", "hello@example.com")
blocks = LegalPages.privacy_content()
assert has_text_containing?(blocks, "hello@example.com")
end
end
# ---------------------------------------------------------------------------
# delivery_content/0
# ---------------------------------------------------------------------------
describe "delivery_content/0" do
test "returns a list of blocks with :lead as the first" do
blocks = LegalPages.delivery_content()
assert is_list(blocks)
assert hd(blocks).type == :lead
end
test "always includes returns, cancellations, and production sections" do
blocks = LegalPages.delivery_content()
assert has_heading?(blocks, "Production time")
assert has_heading?(blocks, "Returns & exchanges")
assert has_heading?(blocks, "Cancellations")
end
test "cites Consumer Contracts Regulations in returns section" do
blocks = LegalPages.delivery_content()
assert has_text_containing?(blocks, "Consumer Contracts")
assert has_text_containing?(blocks, "Regulation 28(1)(b)")
end
test "cites Consumer Rights Act for defective goods" do
blocks = LegalPages.delivery_content()
assert has_text_containing?(blocks, "Consumer Rights Act 2015")
end
test "handles empty shipping countries gracefully" do
# No shipping rates seeded — list will be empty in test
blocks = LegalPages.delivery_content()
# Should not crash and should include a fallback paragraph
assert is_list(blocks)
assert has_text_containing?(blocks, "worldwide")
end
test "last block is a :closing disclaimer" do
blocks = LegalPages.delivery_content()
assert List.last(blocks).type == :closing
end
end
# ---------------------------------------------------------------------------
# terms_content/0
# ---------------------------------------------------------------------------
describe "terms_content/0" do
test "returns a list of blocks with :lead as the first" do
blocks = LegalPages.terms_content()
assert is_list(blocks)
assert hd(blocks).type == :lead
end
test "always includes core sections" do
blocks = LegalPages.terms_content()
assert has_heading?(blocks, "Products")
assert has_heading?(blocks, "Payment")
assert has_heading?(blocks, "Returns")
assert has_heading?(blocks, "Governing law")
assert has_heading?(blocks, "Changes")
end
test "governing law is English law for GB shop" do
Settings.put_setting("shop_country", "GB")
blocks = LegalPages.terms_content()
assert has_text_containing?(blocks, "English law")
end
test "governing law references EU regulations for EU shop" do
Settings.put_setting("shop_country", "DE")
blocks = LegalPages.terms_content()
assert has_text_containing?(blocks, "EU regulations")
end
test "includes VAT clause when vat_enabled is true" do
Settings.put_setting("vat_enabled", true, "boolean")
blocks = LegalPages.terms_content()
assert has_text_containing?(blocks, "VAT")
end
test "omits VAT clause when vat_enabled is false" do
Settings.put_setting("vat_enabled", false, "boolean")
blocks = LegalPages.terms_content()
refute has_text_containing?(blocks, "VAT")
end
test "includes shop name in lead" do
Settings.put_setting("shop_name", "Petal & Ink")
blocks = LegalPages.terms_content()
assert has_text_containing?(blocks, "Petal & Ink")
end
test "last block is a :closing disclaimer" do
blocks = LegalPages.terms_content()
assert List.last(blocks).type == :closing
end
end
# ---------------------------------------------------------------------------
# regenerate_legal_content/1
# ---------------------------------------------------------------------------
describe "regenerate_legal_content/1" do
test "returns a non-empty string for privacy" do
result = LegalPages.regenerate_legal_content("privacy")
assert is_binary(result)
assert String.length(result) > 100
end
test "returns a non-empty string for delivery" do
result = LegalPages.regenerate_legal_content("delivery")
assert is_binary(result)
assert String.length(result) > 100
end
test "returns a non-empty string for terms" do
result = LegalPages.regenerate_legal_content("terms")
assert is_binary(result)
assert String.length(result) > 100
end
end
# ---------------------------------------------------------------------------
# rich_text_to_plain/1
# ---------------------------------------------------------------------------
describe "rich_text_to_plain/1" do
test "converts headings to markdown-style" do
blocks = [%{type: :heading, text: "Hello"}]
assert LegalPages.rich_text_to_plain(blocks) == "## Hello"
end
test "converts paragraphs as-is" do
blocks = [%{type: :paragraph, text: "Some text here."}]
assert LegalPages.rich_text_to_plain(blocks) == "Some text here."
end
test "converts lists to bullet points" do
blocks = [%{type: :list, items: ["One", "Two", "Three"]}]
assert LegalPages.rich_text_to_plain(blocks) == "• One\n• Two\n• Three"
end
test "converts lead blocks" do
blocks = [%{type: :lead, text: "Important intro"}]
assert LegalPages.rich_text_to_plain(blocks) == "Important intro"
end
test "converts updated_at blocks" do
blocks = [%{type: :updated_at, date: "28 February 2026"}]
assert LegalPages.rich_text_to_plain(blocks) == "Last updated: 28 February 2026"
end
test "joins multiple blocks with double newlines" do
blocks = [
%{type: :heading, text: "Title"},
%{type: :paragraph, text: "Body text."}
]
assert LegalPages.rich_text_to_plain(blocks) == "## Title\n\nBody text."
end
test "skips unknown block types" do
blocks = [
%{type: :heading, text: "Title"},
%{type: :unknown_thing, data: "whatever"},
%{type: :paragraph, text: "Body."}
]
assert LegalPages.rich_text_to_plain(blocks) == "## Title\n\nBody."
end
end
# ---------------------------------------------------------------------------
# legal_slug?/1
# ---------------------------------------------------------------------------
describe "legal_slug?/1" do
test "returns true for legal page slugs" do
assert LegalPages.legal_slug?("privacy")
assert LegalPages.legal_slug?("delivery")
assert LegalPages.legal_slug?("terms")
end
test "returns false for non-legal slugs" do
refute LegalPages.legal_slug?("home")
refute LegalPages.legal_slug?("about")
refute LegalPages.legal_slug?("contact")
end
end
end