diff --git a/test/simpleshop_theme_web/live/theme_css_consistency_test.exs b/test/simpleshop_theme_web/live/theme_css_consistency_test.exs new file mode 100644 index 0000000..67a0fa9 --- /dev/null +++ b/test/simpleshop_theme_web/live/theme_css_consistency_test.exs @@ -0,0 +1,163 @@ +defmodule SimpleshopThemeWeb.ThemeCSSConsistencyTest do + @moduledoc """ + Tests that verify CSS selectors work correctly for both the theme editor + preview (.preview-frame) and the shop pages (.shop-root). + + These tests ensure that the theme-layer2-attributes.css file has correct + selectors for both contexts, and that CSS custom properties are resolved. + """ + + use SimpleshopThemeWeb.ConnCase, async: false + + import Phoenix.LiveViewTest + import SimpleshopTheme.AccountsFixtures + + alias SimpleshopTheme.Settings + + setup do + user = user_fixture() + %{user: user} + end + + describe "CSS selector consistency" do + test "shop home page has .shop-root with data attributes", %{conn: conn} do + {:ok, _view, html} = live(conn, ~p"/") + + # Verify shop-root element exists with theme data attributes + assert html =~ ~r/]*class="shop-root/ + assert html =~ ~r/data-mood="/ + assert html =~ ~r/data-typography="/ + assert html =~ ~r/data-shape="/ + assert html =~ ~r/data-density="/ + end + + test "theme editor has .preview-frame with data attributes", %{conn: conn, user: user} do + conn = log_in_user(conn, user) + {:ok, _view, html} = live(conn, ~p"/admin/theme") + + # Verify preview-frame element exists with theme data attributes + assert html =~ ~r/]*class="preview-frame/ + assert html =~ ~r/data-mood="/ + assert html =~ ~r/data-typography="/ + assert html =~ ~r/data-shape="/ + assert html =~ ~r/data-density="/ + end + + test "shop page uses same theme settings as preview", %{conn: conn, user: user} do + # Set a specific theme configuration + {:ok, _settings} = Settings.apply_preset(:night) + + # Check shop page + {:ok, _view, shop_html} = live(conn, ~p"/") + + # Check preview (authenticated) + conn = log_in_user(conn, user) + {:ok, _view, preview_html} = live(conn, ~p"/admin/theme") + + # Extract data-mood values from both + [_, shop_mood] = Regex.run(~r/data-mood="([^"]+)"/, shop_html) + [_, preview_mood] = Regex.run(~r/data-mood="([^"]+)"/, preview_html) + + # They should match + assert shop_mood == preview_mood + assert shop_mood == "dark" + end + + test "theme settings changes are reflected on shop page", %{conn: conn} do + # Start with minimal preset (neutral mood) + {:ok, _settings} = Settings.apply_preset(:minimal) + + {:ok, _view, html} = live(conn, ~p"/") + assert html =~ ~s(data-mood="neutral") + + # Change to night preset (dark mood) + {:ok, _settings} = Settings.apply_preset(:night) + + {:ok, _view, html} = live(conn, ~p"/") + assert html =~ ~s(data-mood="dark") + + # Change to gallery preset (warm mood) + {:ok, _settings} = Settings.apply_preset(:gallery) + + {:ok, _view, html} = live(conn, ~p"/") + assert html =~ ~s(data-mood="warm") + end + end + + describe "CSS file structure" do + test "theme-layer2-attributes.css has both .preview-frame and .shop-root selectors" do + css_path = Path.join([File.cwd!(), "assets", "css", "theme-layer2-attributes.css"]) + css_content = File.read!(css_path) + + # Check that mood selectors exist for both + assert css_content =~ ".preview-frame[data-mood=\"dark\"]" + assert css_content =~ ".shop-root[data-mood=\"dark\"]" + + assert css_content =~ ".preview-frame[data-mood=\"warm\"]" + assert css_content =~ ".shop-root[data-mood=\"warm\"]" + + # Check typography selectors + assert css_content =~ ".preview-frame[data-typography=\"modern\"]" + assert css_content =~ ".shop-root[data-typography=\"modern\"]" + + # Check shape selectors + assert css_content =~ ".preview-frame[data-shape=\"sharp\"]" + assert css_content =~ ".shop-root[data-shape=\"sharp\"]" + + # Check descendant selectors (important for specificity) + assert css_content =~ ".preview-frame .product-grid" + assert css_content =~ ".shop-root .product-grid" + + assert css_content =~ ".preview-frame .product-card" + assert css_content =~ ".shop-root .product-card" + end + + test "default selectors include both .preview-frame and .shop-root" do + css_path = Path.join([File.cwd!(), "assets", "css", "theme-layer2-attributes.css"]) + css_content = File.read!(css_path) + + # The default (neutral) mood should apply to both + # This regex checks for the pattern where both selectors are grouped + assert Regex.match?( + ~r/\.preview-frame,\s*\n\.shop-root\s*\{[^}]*--t-surface-base/, + css_content + ) + end + end + + describe "generated CSS cache" do + test "generated CSS includes theme variables" do + # Apply a preset + {:ok, settings} = Settings.apply_preset(:bold) + + # Generate CSS + css = SimpleshopTheme.Theme.CSSGenerator.generate(settings) + + # Check that key variables are present + assert css =~ "--t-accent-h:" + assert css =~ "--t-accent-s:" + assert css =~ "--t-accent-l:" + assert css =~ "--t-font-size-scale:" + assert css =~ "--t-heading-weight-override:" + end + + test "CSS cache is warmed on startup and invalidated on settings change" do + # Ensure cache has content + SimpleshopTheme.Theme.CSSCache.warm() + + {:ok, css1} = SimpleshopTheme.Theme.CSSCache.get() + assert is_binary(css1) + assert css1 =~ "--t-accent-h:" + + # Change settings (this should invalidate and rewarm cache) + {:ok, _settings} = Settings.apply_preset(:night) + + {:ok, css2} = SimpleshopTheme.Theme.CSSCache.get() + assert is_binary(css2) + + # The CSS should be different (different accent color) + # Note: this may or may not be true depending on preset colors + assert css2 =~ "--t-accent-h:" + end + end +end