107 lines
4.0 KiB
Python
107 lines
4.0 KiB
Python
"""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
|