diff --git a/tests/browser.js b/tests/browser.js index 0e95616..b3bd02b 100644 --- a/tests/browser.js +++ b/tests/browser.js @@ -184,7 +184,17 @@ async function launch() { // On interroge le point d'entrée HTTP de DevTools plutôt que de lire stderr : // Edge n'y annonce rien, contrairement à Chrome. - const urlWs = await attendreDevTools(port, 20000); + // + // ⚠ 60 s, et pas 20. Sur la CI Windows du 2026-08-17, Edge n'a pas répondu + // dans les 20 s : `launch()` a rendu `null`, le `before` de `ui.test.js` a + // levé, et les 46 tests d'interface sont passés en « cancelled » — 0 échec, + // mais le job rouge quand même. Le même runner les avait fait passer deux + // fois le jour même : c'est la charge de la machine, pas un refus de démarrer. + // + // Attendre plus longtemps ne coûte RIEN quand tout va bien — la boucle sort + // dès que DevTools répond, en général sous la seconde. Ça ne coûte que dans + // le cas déjà perdu, où le navigateur ne démarrera jamais. + const urlWs = await attendreDevTools(port, 60000); if (!urlWs) { try { child.kill(); } catch (e) {} try { fs.rmSync(profil, { recursive: true, force: true }); } catch (e) {} diff --git a/tests/champ3d.test.js b/tests/champ3d.test.js index 691371f..defd861 100644 --- a/tests/champ3d.test.js +++ b/tests/champ3d.test.js @@ -611,23 +611,52 @@ describe('Champ 3D', () => { { id: 'o3', p3: [2, 0, 2], dir3: [1, 0, 0], len3: 1 }, ] }); - /** Ordre d'allumage des barres, relevé sur le flux OSC. */ - const ordreVu = async () => { + /** + * Ordre d'allumage des barres, relevé sur le flux OSC. + * + * ⚠ On attend que les 4 barres se soient allumées, on ne PARIE PAS sur une + * durée. La version d'avant coupait à 560 ms pour 4 pas de 120 ms, soit + * 80 ms de marge : la CI Windows du 2026-08-17 a relevé + * ["bar1","bar2","bar3"] — le bon ordre, tronqué d'un cran, parce que le + * quatrième pas n'était pas encore arrivé sur un runner chargé. Un test qui + * mesure une grandeur qui évolue doit être long devant le bruit de charge. + * + * Attendre la CONDITION plutôt qu'une durée rend le relevé indépendant de + * la vitesse de la machine, sans allonger le test sur une machine rapide : + * il sort dès que le compte y est. Le plafond le garde borné si rien ne + * vient — et un relevé incomplet fera échouer l'assertion, comme il doit. + * + * Attendre plus longtemps ne peut RIEN fausser ici : chaque barre n'est + * retenue qu'à son PREMIER allumage, donc les cycles suivants du chase sont + * ignorés. C'est ce qui rend cet élargissement sûr, là où élargir une + * fenêtre au hasard ne l'est pas. + */ + const ordreVu = async (attendu = 4) => { await h.post('/api/blackout'); await sleep(80); h.clearOsc(); await h.post('/api/resync'); await h.post('/api/start'); - await sleep(560); // ~4 pas de 120 ms - await h.post('/api/stop'); - const vus = []; - const precedent = {}; - for (const m of h.osc()) { - const mm = /^\/fixtures\/(bar\d+)\/luminosity$/.exec(m.address); - if (!mm) continue; - if (m.args[0] > 0.5 && !(precedent[mm[1]] > 0.5) && !vus.includes(mm[1])) vus.push(mm[1]); - precedent[mm[1]] = m.args[0]; + /** Relit tout le flux depuis le dernier `clearOsc()` — idempotent. */ + const relever = () => { + const vus = []; + const precedent = {}; + for (const m of h.osc()) { + const mm = /^\/fixtures\/(bar\d+)\/luminosity$/.exec(m.address); + if (!mm) continue; + if (m.args[0] > 0.5 && !(precedent[mm[1]] > 0.5) && !vus.includes(mm[1])) vus.push(mm[1]); + precedent[mm[1]] = m.args[0]; + } + return vus; + }; + let vus = []; + // Plafond à 3 s : largement au-dessus des ~480 ms nominales, et le test + // reste borné si le chase ne démarre pas du tout. + for (let i = 0; i < 60 && vus.length < attendu; i++) { + await sleep(50); + vus = relever(); } + await h.post('/api/stop'); return vus; }; @@ -1008,8 +1037,21 @@ describe('Champ 3D', () => { await base({ engine: 'field', field: 'bruit', axAz, axEl: 0, stepMs: 10000, group: 8, speed: 0.05, width: 2 }); await h.post('/api/start'); + // ⚠ Laisser le champ s'ÉTABLIR avant de mesurer, et prendre assez de + // relevés pour que la statistique converge. Sur la CI Windows du + // 2026-08-17, ce test a rendu 0,1087 contre 0,2149 — or 0,2149 est la + // valeur nominale des DEUX azimuts. Ce n'est donc pas l'axe qui a bougé : + // c'est un écart-type écrasé par des relevés plats, pris avant le premier + // tick sur une machine chargée. Un relevé plat sur dix suffit à diviser la + // dispersion par deux. + // + // On ne touche PAS au seuil de 15 % : il a été resserré depuis 50 % sur + // mesure, précisément parce que 50 % laissait passer le défaut que ce test + // interdit. Élargir la tolérance annulerait ce travail — c'est la mesure + // qu'on fiabilise, pas l'exigence qu'on relâche. + await sleep(150); const vals = []; - for (let i = 0; i < 10; i++) { + for (let i = 0; i < 20; i++) { const st = await h.state(); for (const v of (st.levels || [])) if (typeof v === 'number') vals.push(v); await sleep(70); diff --git a/tests/ui.test.js b/tests/ui.test.js index 5e62ad4..ab09ce8 100644 --- a/tests/ui.test.js +++ b/tests/ui.test.js @@ -24,7 +24,12 @@ describe('Interface dans un vrai navigateur', { skip: AUCUN_NAVIGATEUR && h = await start(); await h.post('/api/fixtures', { fixtures: fixtures(6) }); nav = await launch(); - if (!nav) throw new Error('le navigateur n’a pas démarré'); + // ⚠ Ce message est tout ce qu'on aura pour diagnostiquer : quand ce `before` + // lève, les 46 tests d'en dessous s'annoncent « cancelled » sans dire + // pourquoi. Dire le délai attendu évite de rechercher la cause à l'aveugle, + // comme il a fallu le faire le 2026-08-17. + if (!nav) throw new Error( + 'le navigateur n’a pas démarré : DevTools n’a pas répondu en 60 s'); await nav.goto('http://127.0.0.1:' + h.port + '/'); }); after(async () => {