diff --git a/test/controllers/published_projects_controller_test.rb b/test/controllers/published_projects_controller_test.rb
index 657681a..1280275 100644
--- a/test/controllers/published_projects_controller_test.rb
+++ b/test/controllers/published_projects_controller_test.rb
@@ -86,6 +86,54 @@ def sign_in(user)
assert_select "a[href=?]", edit_project_publication_path(@published), count: 0
end
+ test "show wraps the process summary in trix-content without a redundant prose wrapper" do
+ get published_project_url(slug: @published.slug)
+ assert_response :success
+
+ # ActionText emits the body inside
. The published
+ # page should rely on .trix-content styling rather than wrap it again in
+ # `prose`, which has no rules for the
-as-paragraph markup that Trix
+ # produces and only adds noise.
+ assert_select ".trix-content"
+ assert_select ".prose .trix-content", count: 0
+ end
+
+ test "show renders the challenge as a full card linking to the challenges page" do
+ challenge = Challenge.create!(
+ code: "C6",
+ category: "material",
+ question_translations: { "en" => "How might we replace plastics?" },
+ description_translations: { "en" => "Framing description for C6." }
+ )
+ @published.update!(challenge: challenge)
+
+ get published_project_url(slug: @published.slug)
+ assert_response :success
+
+ assert_select "article[data-challenge=?]", "C6" do
+ assert_select "h3 a[href=?]", challenges_path
+ assert_select "a[data-turbo-frame=preview]", count: 0
+ end
+ end
+
+ test "show hides the challenge bookmark toggle even when logged in" do
+ challenge = Challenge.create!(
+ code: "C7",
+ category: "design",
+ question_translations: { "en" => "How might we ..." },
+ description_translations: { "en" => "..." }
+ )
+ @published.update!(challenge: challenge)
+ sign_in(@member)
+
+ get published_project_url(slug: @published.slug)
+ assert_response :success
+
+ assert_select "article[data-challenge=?]", "C7" do
+ assert_select ".bookmark-toggle", count: 0
+ end
+ end
+
test "show returns 404 for a disabled published project" do
admin = User.create!(name: "Admin", email: "admin-pp@example.com",
password: @password, role: :admin)
diff --git a/test/helpers/materials_helper_test.rb b/test/helpers/materials_helper_test.rb
index 842a2f4..ae8748a 100644
--- a/test/helpers/materials_helper_test.rb
+++ b/test/helpers/materials_helper_test.rb
@@ -1,6 +1,8 @@
require "test_helper"
class MaterialsHelperTest < ActionView::TestCase
+ include GlossaryHighlightHelper
+
# --- materials_chip_toggle_url --------------------------------------------
test "adds the slug to an empty facet" do
@@ -70,4 +72,55 @@ class MaterialsHelperTest < ActionView::TestCase
assert_not materials_chip_active?("origin_type", "plants",
selected_by_facet: {})
end
+
+ # --- material_prose fallback ----------------------------------------------
+
+ test "material_prose falls back to English when the current-locale slot is missing" do
+ material = Material.new(description_translations: { "en" => "A natural fiber." })
+
+ rendered = I18n.with_locale(:es) { material_prose(material, :description) }
+
+ assert_not_nil rendered
+ assert_includes rendered.to_s, "A natural fiber."
+ end
+
+ test "material_prose falls back to English when the current-locale slot is an empty string" do
+ material = Material.new(
+ description_translations: { "en" => "A natural fiber.", "es" => "" }
+ )
+
+ rendered = I18n.with_locale(:es) { material_prose(material, :description) }
+
+ assert_not_nil rendered
+ assert_includes rendered.to_s, "A natural fiber."
+ end
+
+ test "material_prose falls back to English when the current-locale slot is whitespace only" do
+ material = Material.new(
+ description_translations: { "en" => "A natural fiber.", "es" => " \n " }
+ )
+
+ rendered = I18n.with_locale(:es) { material_prose(material, :description) }
+
+ assert_not_nil rendered
+ assert_includes rendered.to_s, "A natural fiber."
+ end
+
+ test "material_prose returns nil when the attribute is blank in every locale" do
+ material = Material.new(description_translations: { "en" => "", "es" => "" })
+
+ assert_nil I18n.with_locale(:es) { material_prose(material, :description) }
+ end
+
+ # --- material_meta_description fallback -----------------------------------
+
+ test "material_meta_description falls back to English when the current-locale slot is empty" do
+ material = Material.new(
+ description_translations: { "en" => "Soft heavy rib knit.", "es" => "" }
+ )
+
+ meta = I18n.with_locale(:es) { material_meta_description(material) }
+
+ assert_equal "Soft heavy rib knit.", meta
+ end
end
diff --git a/test/models/material_test.rb b/test/models/material_test.rb
index a2f6229..c68f2d1 100644
--- a/test/models/material_test.rb
+++ b/test/models/material_test.rb
@@ -28,6 +28,29 @@ def valid_attributes(overrides = {})
assert_equal "A fiber", I18n.with_locale(:it) { record.description }
end
+ # --- Translatable: blank locale slots --------------------------------------
+
+ test "blank locale slots are dropped from translation columns on save" do
+ record = Material.create!(valid_attributes(
+ description_translations: { "en" => "A fiber", "es" => "", "it" => " " },
+ sensorial_qualities_translations: { "en" => "Soft", "es" => "" },
+ what_problem_it_solves_translations: { "en" => "Replaces nylon", "el" => "\n" }
+ ))
+
+ record.reload
+ assert_equal({ "en" => "A fiber" }, record.description_translations)
+ assert_equal({ "en" => "Soft" }, record.sensorial_qualities_translations)
+ assert_equal({ "en" => "Replaces nylon" }, record.what_problem_it_solves_translations)
+ end
+
+ test "blank locale slots are dropped on update too" do
+ record = Material.create!(valid_attributes)
+ record.update!(description_translations: { "en" => "Updated", "es" => "", "it" => "" })
+
+ record.reload
+ assert_equal({ "en" => "Updated" }, record.description_translations)
+ end
+
test "translatable narrative fields are all declared" do
record = Material.new(
interesting_properties_translations: { "en" => "Breathable" },