v1.6.1 : fix — les options du graphique se réinitialisaient toutes seules
Cause (divergence de portage, bug remonté « options reset sans changer de
menu ») : renderRoute() re-crée l'écran ENTIER à chaque tick minute (60 s),
mutation du store ou resize — et l'état des options était une variable
LOCALE de renderChart, retombant aux défauts à chaque re-création.
L'Android est immunisé (remember { mutableStateOf } survit aux
recompositions).
Fix (miroir Compose) :
- chart.js : état d'interaction au NIVEAU MODULE (chartUiState) ;
renderChart(container, ctx, { preserveState }) réutilise l'état quand
preserveState=true, le recrée aux défauts sinon ;
- app.js : preserveChartState = (route === 'chart' && lastRoute === 'chart')
comparé AVANT la mise à jour de lastRoute — tick/store/resize préservent
l'état, la navigation le réinitialise (miroir du reset d'un remember
Android quitté).
Épinglé par l'E2E : resize (même code path que le tick) → chip Tracé labs
+ légende restent en place ; navigation → retour aux défauts.
Docs : §4 « État d'interaction persistant », §8 scénario E2E, §11 leçon
#15 (tout état d'UI doit survivre au re-rendu global), CHANGELOG [1.6.1]
(fix web-only : parité fonctionnelle = Android 1.6.0), README.
This commit is contained in:
parent
ed623b786b
commit
524f122f15
@ -17,8 +17,10 @@
|
|||||||
> Fie-toi toujours à tes analyses de sang et aux consignes de ton
|
> Fie-toi toujours à tes analyses de sang et aux consignes de ton
|
||||||
> endocrinologue.
|
> endocrinologue.
|
||||||
|
|
||||||
- **Statut** : web v1.6.0 — portage de l'Android v1.6.0 · **140 tests verts** ·
|
- **Statut** : web v1.6.1 — parité fonctionnelle avec l'Android v1.6.0
|
||||||
E2E navigateur ✅ · conteneur testé en configuration durcie ✅ · lint/i18n ✅
|
(+ fix web-only : options du graphique préservées entre re-rendus) ·
|
||||||
|
**140 tests verts** · E2E navigateur ✅ · conteneur testé en
|
||||||
|
configuration durcie ✅ · lint/i18n ✅
|
||||||
- **Journal des versions web** : [docs/CHANGELOG.md](docs/CHANGELOG.md)
|
- **Journal des versions web** : [docs/CHANGELOG.md](docs/CHANGELOG.md)
|
||||||
- **Releases** : [gitea.cloudyfy.fr/Siphonight/HormoneTrack-web/releases](https://gitea.cloudyfy.fr/Siphonight/HormoneTrack-web/releases)
|
- **Releases** : [gitea.cloudyfy.fr/Siphonight/HormoneTrack-web/releases](https://gitea.cloudyfy.fr/Siphonight/HormoneTrack-web/releases)
|
||||||
(zip de déploiement statique vérifié par téléchargement)
|
(zip de déploiement statique vérifié par téléchargement)
|
||||||
|
|||||||
@ -5,6 +5,31 @@
|
|||||||
> section la plus récente EN PREMIER ; ce fichier est lu par le dialog
|
> section la plus récente EN PREMIER ; ce fichier est lu par le dialog
|
||||||
> « Nouveautés » de l'app web (fetch `docs/CHANGELOG.md`).
|
> « Nouveautés » de l'app web (fetch `docs/CHANGELOG.md`).
|
||||||
|
|
||||||
|
## [1.6.1] — 2026-09-13
|
||||||
|
|
||||||
|
### Corrigé — les options du graphique se réinitialisaient « toutes seules »
|
||||||
|
|
||||||
|
- **Bug remonté** : sur l'écran Graphiques, les options sélectionnées
|
||||||
|
(modèles affichés, Tracé labs, Prolonger, zoom, panoramique…) revenaient
|
||||||
|
d'elles-mêmes aux défauts « alors qu'on n'a pas changé de menu ».
|
||||||
|
- **Cause** (divergence de portage) : le shell web re-crée l'écran ENTIER
|
||||||
|
à chaque **tick minute** (60 s), **mutation du store** ou **resize** —
|
||||||
|
et l'état des options vivait dans une variable LOCALE de la fonction de
|
||||||
|
rendu, donc retombait aux défauts à chaque re-crétion. Côté Android,
|
||||||
|
l'équivalent vit dans des `remember { mutableStateOf }` qui survivent à
|
||||||
|
toutes les recompositions : le bug est structurellement impossible côté
|
||||||
|
APK — c'était un piège du portage, pas de la logique.
|
||||||
|
- **Fix** : l'état d'interaction du graphique vit au niveau MODULE et le
|
||||||
|
shell signale les re-rendus du **même** écran (`preserveState: true`)
|
||||||
|
→ options préservées pendant qu'on regarde le graphique ; à l'entrée
|
||||||
|
depuis la navigation (quitter puis revenir), retour aux défauts —
|
||||||
|
comportement identique à l'Android.
|
||||||
|
- **Épinglé par l'E2E** : re-render déclenché (resize — même code path
|
||||||
|
que le tick) → chip et légende toujours en place ; navigation → reset.
|
||||||
|
|
||||||
|
> Note de parité : fix **web-only** (pas de changement Android) — les
|
||||||
|
> fonctionnalités portées restent celles de l'Android v1.6.0.
|
||||||
|
|
||||||
## [1.6.0] — 2026-09-12
|
## [1.6.0] — 2026-09-12
|
||||||
|
|
||||||
### « Tracé labs » prolongé au-delà du dernier lab — portage de l'Android v1.6.0
|
### « Tracé labs » prolongé au-delà du dernier lab — portage de l'Android v1.6.0
|
||||||
|
|||||||
@ -272,6 +272,16 @@ HormoneTrack-web/ (dépôt séparé)
|
|||||||
- **« now » mémoïsé sur un tick minute** (fix #56 transposé) : `ctx.nowMs`
|
- **« now » mémoïsé sur un tick minute** (fix #56 transposé) : `ctx.nowMs`
|
||||||
est fourni par le shell et ne change qu'au re-rendu (tick 60 s, mutation
|
est fourni par le shell et ne change qu'au re-rendu (tick 60 s, mutation
|
||||||
du store, navigation) — jamais de dérive de fenêtre pendant les gestes.
|
du store, navigation) — jamais de dérive de fenêtre pendant les gestes.
|
||||||
|
- **État d'interaction du graphique persistant entre re-rendus** (v1.6.1,
|
||||||
|
fix du bug « options qui se reset toutes seules ») : `renderRoute()`
|
||||||
|
re-crée l'écran ENTIER à chaque tick minute (60 s), mutation du store ou
|
||||||
|
resize — or l'Android garde les options dans des `remember` qui
|
||||||
|
SURVIVENT aux recompositions. Le web fait donc vivre l'état AU NIVEAU
|
||||||
|
MODULE (`chartUiState` dans chart.js) et le shell signale les re-rendus
|
||||||
|
du même écran via `preserveState: true` (tick/store/resize → préservé ;
|
||||||
|
navigation → défauts, miroir du reset d'un `remember` quitté). Sans ça,
|
||||||
|
les options du graphique retombaient aux défauts toutes les 60 s
|
||||||
|
pendant que l'utilisateur le regarde.
|
||||||
- **Le graphique est purement déclaratif** : pan/zoom vivent dans
|
- **Le graphique est purement déclaratif** : pan/zoom vivent dans
|
||||||
`chart.js` (parent), `chart-canvas.js` ne fait que dessiner une fenêtre
|
`chart.js` (parent), `chart-canvas.js` ne fait que dessiner une fenêtre
|
||||||
donnée — même séparation que Compose (piège #62/§11 Android).
|
donnée — même séparation que Compose (piège #62/§11 Android).
|
||||||
@ -455,6 +465,13 @@ launch) — d'où le build dédié dans le cache Playwright, hors dépôt.
|
|||||||
ancrée, la légende prolongée et l'**AVERTISSEMENT simulation** (sans
|
ancrée, la légende prolongée et l'**AVERTISSEMENT simulation** (sans
|
||||||
garantie, labs potentiellement erronés) — puis désactive et vérifie
|
garantie, labs potentiellement erronés) — puis désactive et vérifie
|
||||||
qu'ils disparaissent ;
|
qu'ils disparaissent ;
|
||||||
|
- **v1.6.1 : scénario « persistance des options »** — avec `Tracé labs`
|
||||||
|
activé, déclenche un re-render via `dispatchEvent(new Event('resize'))`
|
||||||
|
(MÊME code path que le tick minute et la mutation du store : tous trois
|
||||||
|
appellent `renderRoute` — le tick de 60 s est trop lent pour un E2E) et
|
||||||
|
vérifie que le chip reste sélectionné ET la légende affichée ; puis
|
||||||
|
navigation (quitter → revenir) et vérifie le RESET aux défauts (miroir
|
||||||
|
du `remember` Android quitté).
|
||||||
- vérifie l'**absence d'erreur console/page** sur toute la session ;
|
- vérifie l'**absence d'erreur console/page** sur toute la session ;
|
||||||
- captures dans `/tmp/hrt-web-shots/` (inspection visuelle).
|
- captures dans `/tmp/hrt-web-shots/` (inspection visuelle).
|
||||||
- ⚠️ Course au screenshot évitée par le marqueur `body[data-ready="1"]`
|
- ⚠️ Course au screenshot évitée par le marqueur `body[data-ready="1"]`
|
||||||
@ -710,6 +727,17 @@ Trouvés pendant l'écriture (à ne pas réintroduire) :
|
|||||||
d'où la garde `check.sh` §3.bis : quand le dépôt Android voisin
|
d'où la garde `check.sh` §3.bis : quand le dépôt Android voisin
|
||||||
existe, les symboles clés des features partagées sont vérifiés des
|
existe, les symboles clés des features partagées sont vérifiés des
|
||||||
DEUX côtés (moteur + chip + avertissement).
|
DEUX côtés (moteur + chip + avertissement).
|
||||||
|
15. **Re-rendu global = tout état d'UI doit survivre** (v1.6.1, bug
|
||||||
|
remonté : « les options du graphique se reset alors qu'on n'a pas
|
||||||
|
changé de menu ») : le shell re-crée l'écran ENTIER sur tick minute,
|
||||||
|
mutation du store et resize (3 déclencheurs, `renderRoute`) — un
|
||||||
|
état local à une fonction de rendu retombe donc aux défauts toutes
|
||||||
|
les 60 s SANS action de l'utilisateur. Règle : tout état d'interaction
|
||||||
|
d'un écran vit au niveau MODULE du fichier UI, et `renderRoute`
|
||||||
|
transmet « même écran re-rendu » (`preserveState`) pour le préserver
|
||||||
|
— miroir de `remember` Compose (survit aux recompositions, reset à la
|
||||||
|
navigation). Côté Android ce bug est structurellement impossible
|
||||||
|
(Compose garde l'état) : c'est un piège de portage, pas de logique.
|
||||||
|
|
||||||
## 12. Limites connues & non-portés
|
## 12. Limites connues & non-portés
|
||||||
|
|
||||||
|
|||||||
13
js/ui/app.js
13
js/ui/app.js
@ -141,6 +141,17 @@ function currentRoute() {
|
|||||||
function renderRoute() {
|
function renderRoute() {
|
||||||
if (!contentEl) return;
|
if (!contentEl) return;
|
||||||
const route = currentRoute();
|
const route = currentRoute();
|
||||||
|
// (v1.6.1) Re-rendu du MÊME écran graphique (tick minute, mutation du
|
||||||
|
// store, resize — ce re-rendu ne vient PAS de la navigation) ? Le chart
|
||||||
|
// doit alors PRÉSERVER son état d'interaction (chips, zoom, pan,
|
||||||
|
// Tracé labs…) : miroir Compose où `remember` survit aux recompositions.
|
||||||
|
// Sans ça, le tick minute de 60 s réinitialisait toutes les options du
|
||||||
|
// graphique pendant que l'utilisateur le regarde (bug remonté : « les
|
||||||
|
// options se reset alors qu'on n'a pas changé de menu »). À l'ENTRÉE
|
||||||
|
// (navigation depuis un autre onglet) : preserveState = false → défauts,
|
||||||
|
// miroir du reset Android quand on quitte l'écran. ⚠️ comparé AVANT la
|
||||||
|
// mise à jour de lastRoute ci-dessous.
|
||||||
|
const preserveChartState = route === 'chart' && lastRoute === 'chart';
|
||||||
lastRoute = route;
|
lastRoute = route;
|
||||||
|
|
||||||
// Écran de chargement tant que l'asset PK n'est pas chargé (les écrans
|
// Écran de chargement tant que l'asset PK n'est pas chargé (les écrans
|
||||||
@ -184,7 +195,7 @@ function renderRoute() {
|
|||||||
renderHome(contentEl, { nowMs, openChart: () => { location.hash = '#chart'; } });
|
renderHome(contentEl, { nowMs, openChart: () => { location.hash = '#chart'; } });
|
||||||
break;
|
break;
|
||||||
case route === 'chart':
|
case route === 'chart':
|
||||||
renderChart(contentEl, { nowMs });
|
renderChart(contentEl, { nowMs }, { preserveState: preserveChartState });
|
||||||
break;
|
break;
|
||||||
case route === 'doses':
|
case route === 'doses':
|
||||||
renderDoses(contentEl);
|
renderDoses(contentEl);
|
||||||
|
|||||||
@ -19,6 +19,11 @@
|
|||||||
* - « now » mémoïsé sur un tick minute (fix #56 : boucle de recomposition
|
* - « now » mémoïsé sur un tick minute (fix #56 : boucle de recomposition
|
||||||
* côté Android — côté web, même discipline : endMs ne dérive pas à chaque
|
* côté Android — côté web, même discipline : endMs ne dérive pas à chaque
|
||||||
* frame, il ne change qu'au tick ou sur interaction) ;
|
* frame, il ne change qu'au tick ou sur interaction) ;
|
||||||
|
* - ÉTAT D'INTERACTION PERSISTANT entre re-rendus (v1.6.1) : le tick minute
|
||||||
|
* de app.js, une mutation du store ou un resize re-créent l'écran entier —
|
||||||
|
* l'état (chips, zoom, pan, Tracé labs, Prolonger…) est réutilisé quand
|
||||||
|
* on re-rend le même écran (miroir `remember` Compose) et réinitialisé
|
||||||
|
* à l'entrée depuis la navigation (miroir du reset Android) ;
|
||||||
* - PAS de scroll horizontal parent : le drag horizontal est réservé au pan
|
* - PAS de scroll horizontal parent : le drag horizontal est réservé au pan
|
||||||
* (piège Android #62/§11).
|
* (piège Android #62/§11).
|
||||||
* ─────────────────────────────────────────────────────────────────────────────
|
* ─────────────────────────────────────────────────────────────────────────────
|
||||||
@ -43,6 +48,29 @@ const HOUR_MS = 3600000;
|
|||||||
const MIN_RANGE_H = 6;
|
const MIN_RANGE_H = 6;
|
||||||
const MAX_RANGE_H = 24 * 300;
|
const MAX_RANGE_H = 24 * 300;
|
||||||
|
|
||||||
|
// ── État d'interaction du graphique (v1.6.1 — fix du bug « options qui se
|
||||||
|
// reset toutes seules ») ──────────────────────────────────────────────────────
|
||||||
|
// ⚠️ DIVERGENCE DE PORTAGE corrigée : côté Android, les options du graphique
|
||||||
|
// vivent dans des `remember { mutableStateOf }` — elles SURVIVENT à toutes
|
||||||
|
// les recompositions (tick minute, nouvelles données, resize) tant qu'on
|
||||||
|
// reste sur l'écran. Côté web, `renderRoute()` (app.js) re-crée l'écran
|
||||||
|
// ENTIER à chaque tick minute (60 s), mutation du store ou resize — et un
|
||||||
|
// `const state = {...}` local à renderChart retombait donc aux DÉFAUTS
|
||||||
|
// toutes les 60 s pendant qu'on regarde le graphique (remontée : « les
|
||||||
|
// options se réinitialisent sans qu'on change de menu »).
|
||||||
|
//
|
||||||
|
// FIX : l'état vit AU NIVEAU MODULE. `renderChart` le réutilise quand
|
||||||
|
// l'appelant signale un re-rendu DU MÊME écran (`preserveState: true` —
|
||||||
|
// miroir de `remember` qui survit aux recompositions) et le RECRÉE aux
|
||||||
|
// défauts à l'ENTRÉE sur l'écran (navigation depuis un autre onglet —
|
||||||
|
// miroir du reset d'un `remember` quitté, PAS un rememberSaveable :
|
||||||
|
// quitter Charts puis revenir réinitialise, comme l'Android).
|
||||||
|
//
|
||||||
|
// Un seul objet à la fois : le graphique est un écran unique, le DOM
|
||||||
|
// précédent est jeté à chaque re-rendu (les closures recaptent `state`,
|
||||||
|
// qui reste le MÊME objet d'un re-rendu à l'autre quand il est préservé).
|
||||||
|
let chartUiState = null;
|
||||||
|
|
||||||
/** Styles visuels des séries (miroir de la map du ChartScreen Android). */
|
/** Styles visuels des séries (miroir de la map du ChartScreen Android). */
|
||||||
function seriesStyles(model) {
|
function seriesStyles(model) {
|
||||||
if (model === 'ESE') return { e2: { color: COLORS.chartE2, dashed: false }, t: { color: COLORS.chartT, dashed: false } };
|
if (model === 'ESE') return { e2: { color: COLORS.chartE2, dashed: false }, t: { color: COLORS.chartT, dashed: false } };
|
||||||
@ -52,10 +80,19 @@ function seriesStyles(model) {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Rend l'écran Graphiques dans [container].
|
* Rend l'écran Graphiques dans [container].
|
||||||
|
*
|
||||||
* @param {HTMLElement} container
|
* @param {HTMLElement} container
|
||||||
* @param {object} ctx { nowMs }
|
* @param {object} ctx { nowMs }
|
||||||
|
* @param {object} [opts]
|
||||||
|
* @param {boolean} [opts.preserveState=false] (v1.6.1) `true` quand on
|
||||||
|
* re-rend le MÊME écran graphique (tick minute, mutation du store,
|
||||||
|
* resize — cf app.js renderRoute) : l'état d'interaction [state]
|
||||||
|
* est réutilisé au lieu d'être recréé aux défauts (miroir Compose :
|
||||||
|
* `remember` survit aux recompositions). `false` = entrée sur
|
||||||
|
* l'écran (navigation) : état neuf aux défauts (miroir du reset
|
||||||
|
* d'un `remember` Android quand on quitte l'écran).
|
||||||
*/
|
*/
|
||||||
export function renderChart(container, ctx) {
|
export function renderChart(container, ctx, { preserveState = false } = {}) {
|
||||||
const treatments = store.getTreatments(); // TOUS (actifs ET inactifs, §6.bis)
|
const treatments = store.getTreatments(); // TOUS (actifs ET inactifs, §6.bis)
|
||||||
const doseLogs = store.getDoseLogs();
|
const doseLogs = store.getDoseLogs();
|
||||||
const labResults = store.getLabResults();
|
const labResults = store.getLabResults();
|
||||||
@ -65,7 +102,11 @@ export function renderChart(container, ctx) {
|
|||||||
const chartTimeZone = settings.chartTimezone || null;
|
const chartTimeZone = settings.chartTimezone || null;
|
||||||
|
|
||||||
// ── État d'interaction (miroir des mutableStateOf Compose) ────────────────
|
// ── État d'interaction (miroir des mutableStateOf Compose) ────────────────
|
||||||
const state = {
|
// v1.6.1 : réutilisé entre les re-rendus du même écran (cf bloc
|
||||||
|
// « État d'interaction » au-dessus — sans ça, le tick minute de app.js
|
||||||
|
// réinitialisait toutes les options toutes les 60 s).
|
||||||
|
if (!preserveState || !chartUiState) {
|
||||||
|
chartUiState = {
|
||||||
rangeHours: 24,
|
rangeHours: 24,
|
||||||
panHours: 0,
|
panHours: 0,
|
||||||
showT: true,
|
showT: true,
|
||||||
@ -86,6 +127,8 @@ export function renderChart(container, ctx) {
|
|||||||
panResidualHours: 0.0, // résiduel fractionnaire du pan (fix #62)
|
panResidualHours: 0.0, // résiduel fractionnaire du pan (fix #62)
|
||||||
togglesInitialized: false,
|
togglesInitialized: false,
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
const state = chartUiState;
|
||||||
|
|
||||||
// ── Colonne racine ───────────────────────────────────────────────────────
|
// ── Colonne racine ───────────────────────────────────────────────────────
|
||||||
const col = el('div', {});
|
const col = el('div', {});
|
||||||
|
|||||||
@ -31,7 +31,7 @@ import { el, showDialog, field, switchRow, filterChip, toast } from './component
|
|||||||
* (APK + web au MÊME numéro, tags appariés `vX.Y.Z` + `vX.Y.Z-web`).
|
* (APK + web au MÊME numéro, tags appariés `vX.Y.Z` + `vX.Y.Z-web`).
|
||||||
* v1.4.10 = portage initial de l'Android v1.4.10.
|
* v1.4.10 = portage initial de l'Android v1.4.10.
|
||||||
*/
|
*/
|
||||||
export const WEB_VERSION = '1.6.0';
|
export const WEB_VERSION = '1.6.1';
|
||||||
|
|
||||||
/** Parse un champ numérique FR (virgule → point) ; null si vide/invalide. */
|
/** Parse un champ numérique FR (virgule → point) ; null si vide/invalide. */
|
||||||
function parseNumOrNull(text) {
|
function parseNumOrNull(text) {
|
||||||
|
|||||||
@ -131,7 +131,7 @@ async function main() {
|
|||||||
ok(dialog !== null, 'dialog « Nouveautés » au premier lancement (markdown rendu)');
|
ok(dialog !== null, 'dialog « Nouveautés » au premier lancement (markdown rendu)');
|
||||||
if (dialog) {
|
if (dialog) {
|
||||||
const dlgText = await dialog.textContent();
|
const dlgText = await dialog.textContent();
|
||||||
ok(dlgText.includes('Version 1.6.0'), 'dialog : section de la version courante');
|
ok(dlgText.includes('Version 1.6.1'), 'dialog : section de la version courante');
|
||||||
const hasRenderedMd = await dialog.$('.md-body h3, .md-body strong');
|
const hasRenderedMd = await dialog.$('.md-body h3, .md-body strong');
|
||||||
ok(hasRenderedMd !== null, 'dialog : markdown RENDU (titres/gras), pas de brut');
|
ok(hasRenderedMd !== null, 'dialog : markdown RENDU (titres/gras), pas de brut');
|
||||||
await page.click('.dialog .actions button');
|
await page.click('.dialog .actions button');
|
||||||
@ -218,6 +218,45 @@ async function main() {
|
|||||||
'désactivation → légende prolongée + avertissement disparaissent');
|
'désactivation → légende prolongée + avertissement disparaissent');
|
||||||
await page.screenshot({ path: join(SHOTS, 'e2e-chart-extend.png') });
|
await page.screenshot({ path: join(SHOTS, 'e2e-chart-extend.png') });
|
||||||
|
|
||||||
|
// ── 2.ter PERSISTANCE de l'état du graphique (v1.6.1) ───────────────────
|
||||||
|
// Bug remonté : les options se réinitialisaient « toutes seules » car le
|
||||||
|
// tick minute / une mutation du store / un resize re-créaient l'écran
|
||||||
|
// ENTIER (renderRoute) et le state local de renderChart retombait aux
|
||||||
|
// défauts. Fix : état au niveau module + preserveState du même écran.
|
||||||
|
// Ici on déclenche le re-render via RESIZE (même code path que le tick :
|
||||||
|
// store.subscribe et setInterval appellent tous renderRoute) — le tick
|
||||||
|
// réel de 60 s est trop lent pour un E2E.
|
||||||
|
console.log('── Persistance des options du graphique (#chart, v1.6.1) ──');
|
||||||
|
// « Tracé labs » est ON à ce stade (scénario 2.bis) — vérifions avant :
|
||||||
|
const selectedBefore = await page.evaluate(() =>
|
||||||
|
[...document.querySelectorAll('.chip')]
|
||||||
|
.some((x) => x.textContent.trim() === 'Tracé labs' && x.classList.contains('selected')));
|
||||||
|
ok(selectedBefore, 'pré-état : chip « Tracé labs » activé');
|
||||||
|
await page.evaluate(() => window.dispatchEvent(new Event('resize')));
|
||||||
|
await page.waitForTimeout(500);
|
||||||
|
const stateAfterResize = await page.evaluate(() => ({
|
||||||
|
labTrackSelected: [...document.querySelectorAll('.chip')]
|
||||||
|
.some((x) => x.textContent.trim() === 'Tracé labs' && x.classList.contains('selected')),
|
||||||
|
legend: document.querySelector('main.content').textContent.includes('E2 ancrée sur tes labs'),
|
||||||
|
}));
|
||||||
|
ok(stateAfterResize.labTrackSelected,
|
||||||
|
'resize → le chip « Tracé labs » reste sélectionné (état préservé, bug v1.6.1 corrigé)');
|
||||||
|
ok(stateAfterResize.legend,
|
||||||
|
'resize → la légende « Tracé labs » reste affichée (le re-rendu n\'a pas tout remis à zéro)');
|
||||||
|
// Reset à l'ENTRÉE (navigation) : quitter puis revenir → défauts,
|
||||||
|
// miroir du reset d'un `remember` Android quand on quitte l'écran
|
||||||
|
await page.goto(`${base}/#home`, { waitUntil: 'load' });
|
||||||
|
await page.waitForSelector('body[data-ready="1"]');
|
||||||
|
await page.goto(`${base}/#chart`, { waitUntil: 'load' });
|
||||||
|
await page.waitForSelector('body[data-ready="1"]');
|
||||||
|
await page.waitForTimeout(400);
|
||||||
|
const stateAfterNav = await page.evaluate(() => ({
|
||||||
|
labTrackSelected: [...document.querySelectorAll('.chip')]
|
||||||
|
.some((x) => x.textContent.trim() === 'Tracé labs' && x.classList.contains('selected')),
|
||||||
|
}));
|
||||||
|
ok(stateAfterNav.labTrackSelected === false,
|
||||||
|
'navigation (quitter → revenir) → options retombées aux défauts (miroir Android)');
|
||||||
|
|
||||||
// ── 3. Navigation : les 5 onglets + settings ────────────────────────────
|
// ── 3. Navigation : les 5 onglets + settings ────────────────────────────
|
||||||
console.log('── Navigation ──');
|
console.log('── Navigation ──');
|
||||||
await page.goto(`${base}/#doses`, { waitUntil: 'load' });
|
await page.goto(`${base}/#doses`, { waitUntil: 'load' });
|
||||||
@ -243,7 +282,7 @@ async function main() {
|
|||||||
await page.waitForTimeout(300);
|
await page.waitForTimeout(300);
|
||||||
text = await page.textContent('main.content');
|
text = await page.textContent('main.content');
|
||||||
ok(text.includes('Langue'), 'Paramètres : carte langue');
|
ok(text.includes('Langue'), 'Paramètres : carte langue');
|
||||||
ok(text.includes('Version 1.6.0 (web)'), 'Paramètres : version affichée');
|
ok(text.includes('Version 1.6.1 (web)'), 'Paramètres : version affichée');
|
||||||
ok(text.includes('100 % local'), 'Paramètres : note vie privée');
|
ok(text.includes('100 % local'), 'Paramètres : note vie privée');
|
||||||
await page.screenshot({ path: join(SHOTS, 'e2e-settings.png') });
|
await page.screenshot({ path: join(SHOTS, 'e2e-settings.png') });
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user