Ctrl K
ComunidadGuías…

test_serve_app_js_nouveaux_clips.py

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
"""Audit du 26/09/2026, B03 : heuresDePassage() comparait le nombre de clips
de /api/passages à data.total_known entier, devenu un objet par genre
({"clip": ..., "direct": ...}) le 2026-09-04. La soustraction donnait NaN :
les nouveaux clips n'étaient plus annoncés, ni la galerie rechargée quand la
case d'actualisation automatique était cochée.

La vraie fonction est extraite de serve_app.js et exécutée par node, avec une
API et un DOM simulés.
"""

from __future__ import annotations

import json
import re
import shutil
import subprocess
import unittest
from pathlib import Path


class TestsNouveauxClips(unittest.TestCase):
    @classmethod
    def setUpClass(cls):
        cls.node = shutil.which("node")
        if cls.node is None:
            raise unittest.SkipTest("node introuvable")
        source = (Path(__file__).parent / "serve_app.js").read_text(encoding="utf-8")
        fonction = re.search(
            r"^async function heuresDePassage\(\) \{.*?^\}", source,
            re.DOTALL | re.MULTILINE,
        )
        if fonction is None:
            raise AssertionError("heuresDePassage() introuvable dans serve_app.js")
        cls.fonction = fonction.group(0)

    def _executer(self, *, galerie: dict, clips_passages: int, auto: bool) -> dict:
        etat = {"passages": {"download": "2026-09-26T18:05:00Z"},
                "clips": clips_passages, "maj": None}
        script = f"""
let data = {json.dumps(galerie)};
let travailEnCours = false;
let rechargements = 0;
function rechargerEnArrierePlan() {{ rechargements += 1; }}
function montrerMaj() {{}}
async function lireJSON(reponse) {{ return reponse; }}
globalThis.fetch = async () => ({json.dumps(etat)});
function tf(cle, valeurs) {{ return "[" + cle + ":" + JSON.stringify(valeurs || {{}}) + "]"; }}
const elements = {{ auto: {{ checked: {json.dumps(auto)} }}, passages: {{ textContent: "" }} }};
globalThis.$ = (id) => elements[id];

{self.fonction}

heuresDePassage().then(() => process.stdout.write(JSON.stringify({{
  rechargements, texte: elements.passages.textContent,
}})));
"""
        resultat = subprocess.run(
            [self.node, "-e", script], capture_output=True, text=True,
            encoding="utf-8", timeout=60,
        )
        if resultat.returncode != 0:
            raise AssertionError(resultat.stderr)
        return json.loads(resultat.stdout)

    def test_un_clip_arrive_recharge_quand_la_case_est_cochee(self):
        sortie = self._executer(
            galerie={"clips": [], "total_known": {"clip": 10, "direct": 3}},
            clips_passages=11, auto=True)
        self.assertEqual(sortie["rechargements"], 1)

    def test_un_clip_arrive_est_annonce_sans_actualisation_automatique(self):
        sortie = self._executer(
            galerie={"clips": [], "total_known": {"clip": 10, "direct": 3}},
            clips_passages=11, auto=False)
        self.assertEqual(sortie["rechargements"], 0)
        self.assertIn('passages.new.one:{"n":1}', sortie["texte"])

    def test_rien_de_nouveau_rien_d_annonce(self):
        sortie = self._executer(
            galerie={"clips": [], "total_known": {"clip": 11, "direct": 3}},
            clips_passages=11, auto=True)
        self.assertEqual(sortie["rechargements"], 0)
        self.assertNotIn("passages.new", sortie["texte"])

    def test_galerie_pas_encore_chargee_rien_a_comparer(self):
        # État initial de serve_app.js : data sans total_known.
        sortie = self._executer(
            galerie={"clips": [], "cameras": [], "days": []},
            clips_passages=11, auto=True)
        self.assertEqual(sortie["rechargements"], 0)
        self.assertNotIn("passages.new", sortie["texte"])


if __name__ == "__main__":
    unittest.main()