"""Tests for shared s-expression components (Phase 5).""" import pytest from shared.sx.jinja_bridge import sx, _COMPONENT_ENV from shared.sx.components import load_shared_components @pytest.fixture(autouse=True) def _load_components(): """Ensure all shared components are registered for every test.""" _COMPONENT_ENV.clear() load_shared_components() # --------------------------------------------------------------------------- # ~shared:fragments/cart-mini # --------------------------------------------------------------------------- class TestCartMini: def test_empty_cart_shows_logo(self): html = sx( '(~shared:fragments/cart-mini :cart-count cart-count :blog-url blog-url :cart-url cart-url)', **{"cart-count": 0, "blog-url": "https://blog.example.com/", "cart-url": "https://cart.example.com/"}, ) assert 'id="cart-mini"' in html assert "logo.jpg" in html assert "blog.example.com/" in html assert "fa-shopping-cart" not in html def test_nonempty_cart_shows_badge(self): html = sx( '(~shared:fragments/cart-mini :cart-count cart-count :blog-url blog-url :cart-url cart-url)', **{"cart-count": 3, "blog-url": "https://blog.example.com/", "cart-url": "https://cart.example.com/"}, ) assert 'id="cart-mini"' in html assert "fa-shopping-cart" in html assert "bg-emerald-600" in html assert ">3<" in html assert "cart.example.com/" in html def test_oob_attribute(self): html = sx( '(~shared:fragments/cart-mini :cart-count 0 :blog-url "" :cart-url "" :oob "true")', ) assert 'sx-swap-oob="true"' in html def test_no_oob_when_nil(self): html = sx( '(~shared:fragments/cart-mini :cart-count 0 :blog-url "" :cart-url "")', ) assert "sx-swap-oob" not in html # --------------------------------------------------------------------------- # ~auth-menu # --------------------------------------------------------------------------- class TestAuthMenu: def test_logged_in(self): html = sx( '(~auth-menu :user-email user-email :account-url account-url)', **{"user-email": "alice@example.com", "account-url": "https://account.example.com/"}, ) assert 'id="auth-menu-desktop"' in html assert 'id="auth-menu-mobile"' in html assert "alice@example.com" in html assert "fa-solid fa-user" in html assert "sign in or register" not in html def test_logged_out(self): html = sx( '(~auth-menu :account-url account-url)', **{"account-url": "https://account.example.com/"}, ) assert "fa-solid fa-key" in html assert "sign in or register" in html def test_desktop_has_data_close_details(self): html = sx( '(~auth-menu :user-email "x@y.com" :account-url "http://a")', ) assert "data-close-details" in html def test_two_spans_always_present(self): """Both desktop and mobile spans are always rendered.""" for email in ["user@test.com", None]: html = sx( '(~auth-menu :user-email user-email :account-url account-url)', **{"user-email": email, "account-url": "http://a"}, ) assert 'id="auth-menu-desktop"' in html assert 'id="auth-menu-mobile"' in html # --------------------------------------------------------------------------- # ~shared:fragments/account-nav-item # --------------------------------------------------------------------------- class TestAccountNavItem: def test_renders_link(self): html = sx( '(~shared:fragments/account-nav-item :href "/orders/" :label "orders")', ) assert 'href="/orders/"' in html assert ">orders<" in html assert "nav-group" in html assert "sx-disable" in html def test_custom_label(self): html = sx( '(~shared:fragments/account-nav-item :href "/cart/orders/" :label "my orders")', ) assert ">my orders<" in html # --------------------------------------------------------------------------- # ~shared:navigation/calendar-entry-nav # --------------------------------------------------------------------------- class TestCalendarEntryNav: def test_renders_entry(self): html = sx( '(~shared:navigation/calendar-entry-nav :href "/events/entry/1/" :name "Workshop" :date-str "Jan 15, 2026 at 14:00" :nav-class "btn")', **{"date-str": "Jan 15, 2026 at 14:00", "nav-class": "btn"}, ) assert 'href="/events/entry/1/"' in html assert "Workshop" in html assert "Jan 15, 2026 at 14:00" in html # --------------------------------------------------------------------------- # ~shared:navigation/calendar-link-nav # --------------------------------------------------------------------------- class TestCalendarLinkNav: def test_renders_calendar_link(self): html = sx( '(~shared:navigation/calendar-link-nav :href "/events/cal/" :name "Art Events" :nav-class "btn")', **{"nav-class": "btn"}, ) assert 'href="/events/cal/"' in html assert "fa fa-calendar" in html assert "Art Events" in html # --------------------------------------------------------------------------- # ~shared:navigation/market-link-nav # --------------------------------------------------------------------------- class TestMarketLinkNav: def test_renders_market_link(self): html = sx( '(~shared:navigation/market-link-nav :href "/market/farm/" :name "Farm Shop" :nav-class "btn")', **{"nav-class": "btn"}, ) assert 'href="/market/farm/"' in html assert "fa fa-shopping-bag" in html assert "Farm Shop" in html # --------------------------------------------------------------------------- # ~shared:cards/post-card # --------------------------------------------------------------------------- class TestPostCard: def test_basic_card(self): html = sx( '(~shared:cards/post-card :title "Hello World" :slug "hello" :href "/hello/"' ' :feature-image "/img/hello.jpg" :excerpt "A test post"' ' :status "published" :published-at "15 Jan 2026"' ' :hx-select "#main-panel")', **{ "feature-image": "/img/hello.jpg", "hx-select": "#main-panel", "published-at": "15 Jan 2026", }, ) assert "" in html assert "Test" in html assert "

Hello

" in html assert "tw.css" in html class TestErrorPage: def test_404_page(self): html = sx( '(~shared:pages/error-page :title "404 Error" :message "NOT FOUND" :image "/static/errors/404.gif" :asset-url "/static")', **{"asset-url": "/static"}, ) assert "" in html assert "NOT FOUND" in html assert "text-red-500" in html assert "/static/errors/404.gif" in html def test_error_page_no_image(self): html = sx( '(~shared:pages/error-page :title "500 Error" :message "SERVER ERROR" :asset-url "/static")', **{"asset-url": "/static"}, ) assert "SERVER ERROR" in html assert "" in html assert "MSG" in html