Ctrl K
ComunidadGuías…

test_serve_app_js_fin_mise_a_jour.py

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

Archivo original ↗Preguntar a KiBot
"""Une conclusion sans relance rend les contrôles et le libellé du bouton."""

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


class TestsFinMiseAJour(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")
        motifs = [
            r"^const I18N = \{.*?^\};",
            r"^function t\([^\n]*$",
            r"^const CONTROLES_GELES_PENDANT_MAJ = [^\n]*;$",
            *[rf"^function {nom}\(.*?^\}}" for nom in (
                "tf", "libellePhase", "montrerTravail", "montrerMaj", "gelerPendantMaj")],
            r'^\$\("update"\)\.onclick = async \(\) => \{.*?^\};',
            r'^async function etatDuTravail\(.*?^\}',
        ]
        cls.code = "\n".join(re.search(motif, source, re.DOTALL | re.MULTILINE).group(0)
                             for motif in motifs)

    def executer(self, langue, actif, retard=False, refus=False, retard_post=False,
                 reessai=False):
        script = """
const elements = {};
const $ = id => elements[id] ||= {
  disabled: false, dataset: {}, textContent: '', hidden: false,
  classList: {add() {}, remove() {}}, removeAttribute() {}
};
let _lang = LANGUE, actualisationLocale = false;
let travailVisible = false, travailEnCours = true, miseAJourAttente = null;
let generationMaj = 0, repondreTravail, repondreMaj;
let rechargements = 0;
const intervallesAnnules = [];
const delais = [];
const rechargerEnArrierePlan = () => rechargements++;
const setInterval = () => 7;
const clearInterval = id => intervallesAnnules.push(id);
const setTimeout = rappel => delais.push(rappel);
const fetch = async url => url === '/api/travail'
  ? new Promise(resolve => repondreTravail = resolve)
  : (RETARD_POST ? new Promise(resolve => repondreMaj = resolve)
    : (REFUS ? {error: 'Conclusion occupée'} : {ok: true, version: '0.99.0'}));
const lireJSON = async reponse => reponse;
const alert = () => { if (!REFUS) throw Error('alerte inattendue'); };
""".replace("LANGUE", json.dumps(langue)) + self.code + """
(async () => {
  montrerMaj({version: '0.99.0'});
  const lecture = RETARD ? etatDuTravail() : null;
  const demande = $('update').onclick();
  let postProtege = null;
  if (RETARD_POST) {
    const travail = etatDuTravail();
    if (repondreTravail) repondreTravail({travail: {
      quoi: 'Ancien échec', cle: 'phase.update_noop', fait: 1, total: 1,
      termine: '2026-10-02T00:00:00Z'}});
    await travail;
    postProtege = $('update').disabled && !!$('update').dataset.encours;
    repondreMaj({ok: true, version: '0.99.0'});
  }
  await demande;
  const geles = CONTROLES_GELES_PENDANT_MAJ.every(id => $(id).disabled);
  let ancienneIgnoree = null;
  if (RETARD) {
    repondreTravail({travail: {quoi: 'Ancien échec', cle: 'phase.update_noop',
      fait: 1, total: 1, termine: '2026-10-02T00:00:00Z'}});
    await lecture;
    ancienneIgnoree = $('update').disabled
      && CONTROLES_GELES_PENDANT_MAJ.every(id => $(id).disabled)
      && miseAJourAttente === 7 && intervallesAnnules.length === 0;
  }
  if (REFUS) {
    console.log(JSON.stringify({bouton: {disabled: $('update').disabled,
      texte: $('update').textContent, encours: !!$('update').dataset.encours}}));
    return;
  }
  montrerTravail({quoi: "Échec de l'arrêt", cle: 'phase.update_noop',
    fait: 1, total: 1, termine: '2026-10-02T00:00:00Z', actif: ACTIF});
  if (REESSAI) {
    await $('update').onclick();
    const attenteReessai = miseAJourAttente;
    const annulesAvant = intervallesAnnules.length;
    delais[0]();
    const ancienDelaiIgnore = $('update').disabled && !!$('update').dataset.encours
      && CONTROLES_GELES_PENDANT_MAJ.every(id => $(id).disabled)
      && miseAJourAttente === attenteReessai && intervallesAnnules.length === annulesAvant;
    delais[1]();
    const nouveauDelaiApplique = !$('update').disabled && !$('update').dataset.encours
      && CONTROLES_GELES_PENDANT_MAJ.every(id => !$(id).disabled)
      && miseAJourAttente === null && intervallesAnnules.length === annulesAvant + 1;
    console.log(JSON.stringify({ancienDelaiIgnore, nouveauDelaiApplique}));
    return;
  }
  console.log(JSON.stringify({geles, ancienneIgnoree, postProtege,
    controles: CONTROLES_GELES_PENDANT_MAJ.map(id => $(id).disabled),
    bouton: {disabled: $('update').disabled, texte: $('update').textContent,
             encours: !!$('update').dataset.encours},
    refresh: $('refresh').disabled, phase: $('phase').textContent,
    attente: miseAJourAttente, intervallesAnnules, rechargements}));
})().catch(erreur => {console.error(erreur); process.exitCode = 1;});
""".replace("ACTIF", json.dumps(actif))
        script = script.replace("RETARD_POST", json.dumps(retard_post))
        script = script.replace("REESSAI", json.dumps(reessai))
        script = script.replace("RETARD", json.dumps(retard)).replace("REFUS", json.dumps(refus))
        resultat = subprocess.run([self.node, "-"], input=script, capture_output=True,
                                  text=True, encoding="utf-8", timeout=15)
        self.assertEqual(resultat.returncode, 0, resultat.stderr)
        return json.loads(resultat.stdout)

    def verifier(self, actif):
        for langue, texte in (("fr", "Installer 0.99.0"), ("en", "Install 0.99.0")):
            with self.subTest(langue=langue):
                resultat = self.executer(langue, actif)
                self.assertTrue(resultat["geles"])
                self.assertEqual(resultat["controles"], [False] * 4)
                self.assertEqual(resultat["bouton"], {
                    "disabled": False, "texte": texte, "encours": False})
                self.assertEqual(resultat["refresh"], actif)
                self.assertEqual(resultat["phase"], "Échec de l'arrêt")
                self.assertIsNone(resultat["attente"])
                self.assertEqual(resultat["intervallesAnnules"], [7])
                self.assertEqual(resultat["rechargements"], int(not actif))

    def test_echec_sans_autre_travail(self):
        self.verifier(False)

    def test_echec_pendant_un_telechargement(self):
        self.verifier(True)

    def test_reponse_en_vol_avant_le_clic_ne_debloque_pas_le_reessai(self):
        resultat = self.executer("en", True, retard=True)
        self.assertTrue(resultat["ancienneIgnoree"])
        self.assertEqual(resultat["bouton"], {
            "disabled": False, "texte": "Install 0.99.0", "encours": False})
        self.assertEqual(resultat["intervallesAnnules"], [7])

    def test_reessai_refuse_retablit_le_libelle_du_bouton(self):
        resultat = self.executer("fr", True, refus=True)
        self.assertEqual(resultat["bouton"], {
            "disabled": False, "texte": "Installer 0.99.0", "encours": False})

    def test_sonde_pendant_le_post_ne_debloque_pas_le_bouton(self):
        resultat = self.executer("en", True, retard_post=True)
        self.assertTrue(resultat["postProtege"])
        self.assertTrue(resultat["geles"])

    def test_ancien_delai_ne_debloque_pas_le_reessai(self):
        resultat = self.executer("fr", True, reessai=True)
        self.assertTrue(resultat["ancienDelaiIgnore"])
        self.assertTrue(resultat["nouveauDelaiApplique"])


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