feat: real API-driven search pagination
This commit is contained in:
@@ -0,0 +1,125 @@
|
||||
"""Tests E2E de la pagination de la recherche (recherche.php).
|
||||
|
||||
La pagination est déléguée à l'API PeerTube (paramètre start) et le total
|
||||
affiché est le total réel renvoyé par l'API — et non le nombre de vidéos
|
||||
réellement présentes sur la page.
|
||||
"""
|
||||
import json
|
||||
import math
|
||||
import re
|
||||
import urllib.parse
|
||||
import urllib.request
|
||||
|
||||
import pytest
|
||||
|
||||
VIDEOS_PAR_PAGE = 12 # VIDEOS_PER_PAGE (includes/config.default.php)
|
||||
TERMES_CANDIDATS = ["a", "e", "video", "les"]
|
||||
|
||||
|
||||
def _total_api(peertube_url, terme):
|
||||
"""Total d'une recherche plein texte côté API PeerTube."""
|
||||
params = urllib.parse.urlencode({
|
||||
"search": terme,
|
||||
"isLocal": "true",
|
||||
"count": 1,
|
||||
})
|
||||
url = f"{peertube_url}/api/v1/search/videos?{params}"
|
||||
with urllib.request.urlopen(url, timeout=30) as rep:
|
||||
return int(json.load(rep).get("total", 0))
|
||||
|
||||
|
||||
def _nombre_resultats(page):
|
||||
"""Extrait le total affiché dans le bandeau des résultats."""
|
||||
texte = page.locator(".search-results-count p").inner_text()
|
||||
m = re.search(r"(\d+)", texte)
|
||||
assert m, f"Total introuvable dans le bandeau : {texte!r}"
|
||||
return int(m.group(1))
|
||||
|
||||
|
||||
def _ids_cartes(page):
|
||||
"""Identifiants des vidéos affichées dans la grille de résultats."""
|
||||
cartes = page.locator(".video-grid .video-card")
|
||||
return {
|
||||
cartes.nth(i).get_attribute("data-video-id")
|
||||
for i in range(cartes.count())
|
||||
}
|
||||
|
||||
|
||||
@pytest.fixture(scope="session")
|
||||
def terme_paginable(peertube_url):
|
||||
"""Un terme de recherche couvrant au moins deux pages de résultats."""
|
||||
for terme in TERMES_CANDIDATS:
|
||||
try:
|
||||
if _total_api(peertube_url, terme) > VIDEOS_PAR_PAGE:
|
||||
return terme
|
||||
except Exception:
|
||||
continue
|
||||
pytest.skip("Aucun terme avec plus d'une page de résultats (réseau ?)")
|
||||
|
||||
|
||||
def test_recherche_affiche_total_reel(page, base_url, peertube_url, terme_paginable):
|
||||
"""Le total affiché est le total réel de l'API, pas le contenu de la page."""
|
||||
total_api = _total_api(peertube_url, terme_paginable)
|
||||
page.goto(
|
||||
f"{base_url}/recherche.php?q={urllib.parse.quote(terme_paginable)}",
|
||||
wait_until="domcontentloaded",
|
||||
)
|
||||
|
||||
cartes = page.locator(".video-grid .video-card")
|
||||
if cartes.count() == 0:
|
||||
pytest.skip("Aucune vidéo reçue de l'API PeerTube (réseau indisponible ?)")
|
||||
|
||||
total_affiche = _nombre_resultats(page)
|
||||
assert total_affiche == total_api
|
||||
# La première page ne contient qu'une page de résultats, pas le total
|
||||
assert total_affiche > cartes.count()
|
||||
assert cartes.count() == min(VIDEOS_PAR_PAGE, total_affiche)
|
||||
|
||||
# La barre de pagination reflète le total réel
|
||||
assert page.locator(".pagination").count() == 1
|
||||
assert page.locator(".page-number.current").inner_text() == "1"
|
||||
numeros = [
|
||||
int(page.locator(".page-number").nth(i).inner_text())
|
||||
for i in range(page.locator(".page-number").count())
|
||||
]
|
||||
assert max(numeros) == math.ceil(total_affiche / VIDEOS_PAR_PAGE)
|
||||
|
||||
|
||||
def test_recherche_navigation_page_2(page, base_url, terme_paginable):
|
||||
"""Le lien « Suivant » mène à la page 2, avec des vidéos différentes."""
|
||||
page.goto(
|
||||
f"{base_url}/recherche.php?q={urllib.parse.quote(terme_paginable)}",
|
||||
wait_until="domcontentloaded",
|
||||
)
|
||||
ids_page1 = _ids_cartes(page)
|
||||
if not ids_page1:
|
||||
pytest.skip("Aucune vidéo reçue de l'API PeerTube (réseau indisponible ?)")
|
||||
|
||||
page.locator(".page-link.next").click()
|
||||
page.wait_for_url(re.compile(r"[?&]page=2(&|$)"))
|
||||
|
||||
assert page.locator(".page-number.current").inner_text() == "2"
|
||||
assert page.locator(".page-link.prev").count() == 1
|
||||
|
||||
ids_page2 = _ids_cartes(page)
|
||||
assert ids_page2, "La page 2 ne contient aucune vidéo"
|
||||
assert ids_page2.isdisjoint(ids_page1), "Les pages 1 et 2 partagent des vidéos"
|
||||
|
||||
|
||||
def test_recherche_page_hors_limites(page, base_url, terme_paginable):
|
||||
"""Une page au-delà de la dernière retombe sur une page valide."""
|
||||
page.goto(
|
||||
f"{base_url}/recherche.php?q={urllib.parse.quote(terme_paginable)}&page=99999999",
|
||||
wait_until="domcontentloaded",
|
||||
)
|
||||
|
||||
cartes = page.locator(".video-grid .video-card")
|
||||
if cartes.count() == 0:
|
||||
pytest.skip("Aucune vidéo reçue de l'API PeerTube (réseau indisponible ?)")
|
||||
|
||||
# La page se rabat sur une page valide (jamais de grille vide ni d'erreur)
|
||||
total_affiche = _nombre_resultats(page)
|
||||
assert total_affiche > 0
|
||||
assert page.locator(".page-number.current").count() == 1
|
||||
page_courante = int(page.locator(".page-number.current").inner_text())
|
||||
assert 1 <= page_courante <= math.ceil(total_affiche / VIDEOS_PAR_PAGE)
|
||||
Reference in New Issue
Block a user