Files
annu-kute-ced/tests/e2e/test_csp_dons.py
T

90 lines
4.0 KiB
Python
Raw Normal View History

"""Tests E2E de conformité CSP : page de dons, anti-flash de thème et bouton PWA.
Couvre les corrections COR-4/COR-7 de l'audit : scripts inline noncés,
remplacement des `onclick` par des addEventListener, et de
`style="display: none;"` par la classe utilitaire `.is-hidden`.
"""
import pytest
from playwright.sync_api import expect
def _aller_page_dons(page, base_url):
"""Charge dons.php ; saute le test si les dons sont désactivés sur l'instance."""
reponse = page.goto(base_url + "/dons.php", wait_until="domcontentloaded")
if reponse is None or reponse.status != 200:
pytest.skip(f"dons.php indisponible (HTTP {reponse.status if reponse else '?'})")
def _collecter_erreurs_console(page):
"""Installe la collecte des erreurs console/JS ; retourne la liste à vérifier."""
erreurs = []
page.on("console", lambda msg: erreurs.append(msg.text) if msg.type == "error" else None)
page.on("pageerror", lambda exc: erreurs.append(str(exc)))
return erreurs
def test_dons_scripts_inline_ont_un_nonce(page, base_url):
"""Tous les scripts inline de dons.php portent le nonce CSP (COR-7)."""
_aller_page_dons(page, base_url)
sans_nonce = page.locator("script:not([src]):not([nonce])").evaluate_all(
"(els) => els.map(e => e.outerHTML.slice(0, 80))"
)
assert sans_nonce == [], f"Scripts inline sans nonce : {sans_nonce}"
onclick = page.locator("[onclick]").count()
assert onclick == 0, f"{onclick} élément(s) avec un attribut onclick (bloqué par la CSP)"
def test_dons_anti_flash_theme_sans_erreur(page, base_url):
"""Le script anti-flash noncé s'exécute : thème sombre appliqué dès le chargement."""
page.add_init_script("localStorage.setItem('theme', 'dark');")
erreurs = _collecter_erreurs_console(page)
_aller_page_dons(page, base_url)
assert page.locator("html").get_attribute("data-theme") == "dark", (
"data-theme absent : le script anti-flash a été bloqué par la CSP"
)
assert erreurs == [], f"Erreurs console sur dons.php : {erreurs}"
def test_dons_onglets_stripe(page, base_url):
"""Les onglets Don ponctuel / Don mensuel fonctionnent via addEventListener."""
_aller_page_dons(page, base_url)
onglets = page.locator(".donation-tabs .tab-btn")
if onglets.count() == 0:
pytest.skip("Stripe désactivé sur cette instance (STRIPE_ENABLED=false)")
onglet_mensuel = page.locator('.tab-btn[data-tab="monthly"]')
onglet_ponctuel = page.locator('.tab-btn[data-tab="onetime"]')
# État initial : don ponctuel actif
expect(page.locator("#onetime-tab")).to_have_class("tab-content active")
expect(page.locator("#monthly-tab")).to_have_class("tab-content")
# dispatch_event plutôt que click : les polices chargées depuis cdnjs décalent
# la mise en page et rendent le clic aux coordonnées intermittent. Le but est
# de vérifier le câblage addEventListener (bloqué avant la correction CSP).
onglet_mensuel.dispatch_event("click")
expect(page.locator("#monthly-tab")).to_have_class("tab-content active")
expect(page.locator("#onetime-tab")).to_have_class("tab-content")
expect(onglet_mensuel).to_have_class("tab-btn active")
# Retour au don ponctuel
onglet_ponctuel.dispatch_event("click")
expect(page.locator("#onetime-tab")).to_have_class("tab-content active")
expect(page.locator("#monthly-tab")).to_have_class("tab-content")
def test_bouton_install_pwa_utilise_is_hidden(page, base_url):
"""Le bouton d'installation PWA est masqué par .is-hidden, sans style inline (COR-4)."""
_aller_page_dons(page, base_url)
bouton = page.locator("#install-pwa")
assert bouton.count() == 1, "Bouton #install-pwa absent du header"
assert bouton.get_attribute("style") is None, "Attribut style résiduel (bloqué par la CSP)"
assert bouton.get_attribute("nonce") is None, "Attribut nonce résiduel sur un non-script"
assert bouton.evaluate("(e) => e.classList.contains('is-hidden')")
assert not bouton.is_visible(), "Le bouton PWA devrait être masqué sans beforeinstallprompt"