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

107 lines
4.0 KiB
Python
Raw Normal View History

"""Tests E2E de l'endpoint AJAX ajax/load-more-videos.php.
L'endpoint exige trois protections cumulées (dans l'ordre) :
1. l'en-tête X-Requested-With: XMLHttpRequest ;
2. une origine (Origin, ou Referer à défaut) strictement identique au site ;
3. un token CSRF stateless valide (champ POST csrf_token).
"""
import pytest
ENDPOINT = "/ajax/load-more-videos.php"
@pytest.fixture()
def csrf_token(page, base_url):
"""Récupère un token CSRF frais depuis la balise meta de l'accueil."""
page.goto(base_url + "/index.php", wait_until="domcontentloaded")
token = page.locator('meta[name="csrf-token"]').get_attribute("content")
assert token, "La balise meta csrf-token est absente de l'accueil"
return token
def _post(page, base_url, query="", token=None, ajax=True, origin=None):
"""POST sur l'endpoint avec les protections activables une à une."""
headers = {}
if ajax:
headers["X-Requested-With"] = "XMLHttpRequest"
if origin is not None:
headers["Origin"] = origin
form = {}
if token is not None:
form["csrf_token"] = token
return page.request.post(
base_url + ENDPOINT + query, form=form, headers=headers
)
def test_load_more_rejects_non_ajax(page, base_url, csrf_token):
"""Sans X-Requested-With, la requête est refusée (403)."""
rep = _post(page, base_url, "?type=recent&page=1",
token=csrf_token, ajax=False, origin=base_url)
assert rep.status == 403
assert rep.json() == {"error": "Accès non autorisé"}
def test_load_more_rejects_bad_origin(page, base_url, csrf_token):
"""Une origine étrangère est refusée (403)."""
rep = _post(page, base_url, "?type=recent&page=1",
token=csrf_token, origin="https://example.com")
assert rep.status == 403
assert rep.json() == {"error": "Origine non autorisée"}
def test_load_more_rejects_bad_csrf(page, base_url):
"""Un token CSRF forgé est refusé (403)."""
rep = _post(page, base_url, "?type=recent&page=1",
token="1234567890:tokenforge", origin=base_url)
assert rep.status == 403
assert rep.json() == {"error": "Token CSRF invalide"}
def test_load_more_rejects_invalid_type(page, base_url, csrf_token):
"""Un type de vidéos inconnu est refusé (400)."""
rep = _post(page, base_url, "?type=inconnu&page=1",
token=csrf_token, origin=base_url)
assert rep.status == 400
assert rep.json() == {"error": "Type de vidéos non valide"}
def test_load_more_category_requires_id(page, base_url, csrf_token):
"""Le type 'category' sans ID de catégorie est refusé (400)."""
rep = _post(page, base_url, "?type=category&page=1",
token=csrf_token, origin=base_url)
assert rep.status == 400
assert rep.json() == {"error": "ID de catégorie manquant ou invalide"}
def test_load_more_recent_structure(page, base_url, csrf_token):
"""Une requête valide renvoie la structure JSON attendue."""
rep = _post(page, base_url, "?type=recent&page=1",
token=csrf_token, origin=base_url)
assert rep.status == 200
payload = rep.json()
assert payload["success"] is True
assert payload["page"] == 1
assert isinstance(payload["hasMore"], bool)
assert isinstance(payload["html"], str)
def test_load_more_recent_returns_videos(page, base_url, csrf_token):
"""Le HTML retourné contient des cartes vidéo (nécessite le réseau)."""
rep = _post(page, base_url, "?type=recent&page=1",
token=csrf_token, origin=base_url)
assert rep.status == 200
payload = rep.json()
if not payload["html"]:
pytest.skip("Aucune vidéo reçue de l'API PeerTube (réseau indisponible ?)")
assert 'class="video-card"' in payload["html"]
assert "data-video-id=" in payload["html"]
# L'endpoint n'a plus rien à servir bien au-delà du catalogue
rep_fin = _post(page, base_url, "?type=recent&page=10000",
token=csrf_token, origin=base_url)
assert rep_fin.status == 200
assert rep_fin.json()["hasMore"] is False