feat(marketing): base.html layout + glassmorphism header + button macro

- templates/macros/button.html: 3 variants (primary gradient/glow, secondary,
  ghost) x 3 sizes for reuse across marketing/billing/legal/auth templates
- templates/marketing/base.html: Tailwind v4-scoped layout with FlexiHub
  glassmorphism header (62px, navy/.97, backdrop-blur-xl, .045 border),
  sticky positioning, OG/Twitter meta, Inter font preload, marketing.css
  link, Alpine.js defer, 5-item main nav + Connexion/Demarrer CTAs
- templates/marketing/_footer.html: minimal Phase 2 placeholder with
  legal links + Inverness QC address + info@dictia.ca (full footer in A-2.7)
- templates/marketing/landing.html: minimal hero placeholder (replaced
  in A-2.2 with full hero + cosmic orbs)
- src/marketing/routes.py: landing() now render_template instead of inline HTML
- 7 tests verify template structure, FlexiHub markers, nav, CTAs, legal
  links, no login redirect for anonymous users
- Tailwind CSS rebuilt with new template content scope (cssnano-minified)
This commit is contained in:
Allison
2026-04-27 16:51:06 -04:00
parent 08318a946f
commit 49bf94576c
7 changed files with 216 additions and 11 deletions

View File

@@ -0,0 +1,82 @@
"""Verify the marketing landing template renders correctly."""
import os
import sys
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
os.environ.setdefault('SQLALCHEMY_DATABASE_URI', 'sqlite:///:memory:')
os.environ.setdefault('SECRET_KEY', 'test-secret-key')
from src.app import app # noqa: E402
def test_landing_renders_template_not_inline_html():
"""GET / renders templates/marketing/landing.html (not inline HTML from Phase 1)."""
client = app.test_client()
response = client.get('/', follow_redirects=False)
assert response.status_code == 200
body = response.data.decode('utf-8')
# Phase 2 template hallmarks
assert '<!DOCTYPE html>' in body, "Missing DOCTYPE — base.html not rendering"
assert 'lang="fr-CA"' in body, "Missing lang=fr-CA"
assert '/static/css/marketing.css' in body, "Missing marketing.css link"
assert '/static/fonts/Inter-Variable.woff2' in body, "Missing Inter font preload"
assert '/static/js/alpine.min.js' in body, "Missing Alpine.js script"
def test_landing_has_canonical_url():
"""OG + canonical metadata present."""
client = app.test_client()
response = client.get('/')
body = response.data.decode('utf-8')
assert 'rel="canonical"' in body
assert 'og:type' in body
assert 'og:locale' in body and 'fr_CA' in body
assert 'twitter:card' in body
def test_landing_has_glassmorphism_header():
"""FlexiHub-style header present (navy + backdrop-blur)."""
client = app.test_client()
response = client.get('/')
body = response.data.decode('utf-8')
assert 'bg-brand-navy/[0.97]' in body or 'bg-brand-navy' in body
assert 'backdrop-blur-xl' in body
assert 'border-white/[0.045]' in body, "Missing FlexiHub-style 0.045 border opacity"
def test_landing_has_main_nav():
"""Main nav has 5 links: Fonctionnalités, Conformité, Tarifs, Blog, Contact."""
client = app.test_client()
response = client.get('/')
body = response.data.decode('utf-8')
for link in ['/fonctionnalites', '/conformite', '/tarifs', '/blog', '/contact']:
assert f'href="{link}"' in body, f"Missing nav link: {link}"
def test_landing_has_login_and_signup_ctas():
"""Login + Signup CTAs present in header."""
client = app.test_client()
response = client.get('/')
body = response.data.decode('utf-8')
assert 'href="/login"' in body
assert 'href="/signup"' in body
assert 'Démarrer' in body or 'D&eacute;marrer' in body
def test_landing_footer_has_legal_links():
"""Footer placeholder includes legal links (full footer in A-2.7)."""
client = app.test_client()
response = client.get('/')
body = response.data.decode('utf-8')
assert '/legal/conditions' in body
assert '/legal/confidentialite' in body
assert 'info@dictia.ca' in body, "Missing canonical email info@dictia.ca"
assert 'Inverness' in body, "Missing Inverness QC address"
def test_landing_no_login_redirect_for_anonymous():
"""Anonymous user GET / must see template (regression check from B-1.3)."""
client = app.test_client()
response = client.get('/', follow_redirects=False)
assert response.status_code == 200, \
f"Expected 200, got {response.status_code} — possibly login_required regression"