v1.9.4 (web) : presets ESE étendus à 6 esters + éditeur dynamique + portage v1.9.0 complété
- presets.js : EC huile (5 mg IM), EB (1 mg IM), EUCS suspension cristalline (10 mg SC) — 25 entrées, champs Bateman informatifs - pk-engine.js : Esters.EUCS manquant (portage v1.9.0 incomplet — le preset référençait undefined) - models.js : choicesForModel ESE = 6 esters (parité Android v1.9.0 ; était resté sur la couverture des tables ODS à 3) + KDoc à jour - treatment-editor.js : liste des esters = choicesForModel(model) — rebascule sur EV si l'ester sort de la couverture au changement de modèle (garde anti 0 pg/mL) + re-render du formulaire - tests/presets.test.js (nouveau, 6) : couverture 6 esters ESE, unicité, i18n EN/FR, TFS 7 / WHSAH 6 inchangés, choicesForModel aligné dispatchs - versions 1.9.4 (settings + e2e) + CHANGELOG/§4/§8/README
This commit is contained in:
parent
624e047f39
commit
9af2587110
@ -17,11 +17,12 @@
|
|||||||
> 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.9.2 — parité fonctionnelle avec l'Android v1.9.2
|
- **Statut** : web v1.9.4 — parité fonctionnelle avec l'Android v1.9.4
|
||||||
(modèle Estrannaise analytique + nuage d'incertitude MCMC exclusif ESE ;
|
(modèle Estrannaise analytique + nuage d'incertitude MCMC exclusif ESE ;
|
||||||
l'auto-backup journalier Android reste structurellement non porté, cf
|
presets des 6 esters injectables ESE ; l'auto-backup journalier Android
|
||||||
§12 — l'export manuel couvre la donnée) ·
|
reste structurellement non porté, cf §12 — l'export manuel couvre la
|
||||||
**169 tests verts** · E2E navigateur ✅ · conteneur testé en
|
donnée) ·
|
||||||
|
**175 tests verts** · E2E navigateur ✅ · conteneur testé en
|
||||||
configuration durcie ✅ · lint/i18n ✅
|
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)
|
||||||
|
|||||||
@ -5,6 +5,30 @@
|
|||||||
> 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.9.4] — 2026-09-19
|
||||||
|
|
||||||
|
### Ajouté — les presets du modèle ESE couvrent ses 6 esters injectables
|
||||||
|
|
||||||
|
- **Remontée** : depuis l'ajout du modèle source Estrannaise (v1.9.0), les
|
||||||
|
presets de création n'offraient toujours que EV/EU/EEn — « les presets
|
||||||
|
n'ont pas été mis à jour lors de l'ajout du modèle source pour ESE ».
|
||||||
|
- **Presets** : 3 presets ESE ajoutés (25 entrées, miroir de
|
||||||
|
`PKPresets.kt`) — EC huile (5 mg IM), EB (1 mg IM), EUCS undécylate
|
||||||
|
suspension cristalline (10 mg SC, ester exclusif à ce fit). Champs
|
||||||
|
Bateman informatifs = t½ terminales des fits (pas utilisés au calcul).
|
||||||
|
- **Éditeur** : la liste des esters suit la couverture RÉELLE du modèle
|
||||||
|
choisi (`choicesForModel`, parité Android v1.9.0) — ESE liste ses 6
|
||||||
|
esters injectables ; au changement de modèle, si l'ester courant sort de
|
||||||
|
la couverture (ex. EUCS + TFS), il rebascule sur EV (garde anti
|
||||||
|
« 0 pg/mL ») et le formulaire se re-rend.
|
||||||
|
- **Corrigé (portage v1.9.0 incomplet)** : `Esters.EUCS` manquait dans
|
||||||
|
`pk-engine.js` (le preset référençait `undefined`) et `choicesForModel`
|
||||||
|
(`js/data/models.js`) était resté sur la couverture des tables ODS
|
||||||
|
(3 esters) avec sa KDoc obsolète « produirait 0 pg/mL ».
|
||||||
|
- **Tests** : `tests/presets.test.js` (nouveau, 6 tests) — couverture des
|
||||||
|
6 esters ESE, unicité, clés i18n EN/FR, TFS (7) / WHSAH (6) inchangés,
|
||||||
|
`choicesForModel` aligné sur les dispatchs. Suite web : 175 tests.
|
||||||
|
|
||||||
## [1.9.3] — 2026-09-19
|
## [1.9.3] — 2026-09-19
|
||||||
|
|
||||||
### Corrigé — le numéro de version annoncé
|
### Corrigé — le numéro de version annoncé
|
||||||
|
|||||||
@ -170,7 +170,8 @@ HormoneTrack-web/ (dépôt séparé)
|
|||||||
│ │ ρ log-linéaire, fenêtre labs)
|
│ │ ρ log-linéaire, fenêtre labs)
|
||||||
│ ├── alerts.js Alerts.kt : seuils opt-in, codec d'état,
|
│ ├── alerts.js Alerts.kt : seuils opt-in, codec d'état,
|
||||||
│ │ │ shouldNotify (anti-spam)
|
│ │ │ shouldNotify (anti-spam)
|
||||||
│ │ ├── presets.js PKPresets.kt (22 presets, clés i18n)
|
│ │ ├── presets.js PKPresets.kt (25 presets — v1.9.4 :
|
||||||
|
│ │ │ les 6 esters injectables ESE)
|
||||||
│ │ ├── chart-helpers.kt fonctions pures de CurveChart.kt :
|
│ │ ├── chart-helpers.kt fonctions pures de CurveChart.kt :
|
||||||
│ │ │ panDeltaHours (#62), xLabelTicks (#55),
|
│ │ │ panDeltaHours (#62), xLabelTicks (#55),
|
||||||
│ │ │ pointHoursBefore (#53), clampPanHours (#54),
|
│ │ │ pointHoursBefore (#53), clampPanHours (#54),
|
||||||
@ -251,6 +252,9 @@ HormoneTrack-web/ (dépôt séparé)
|
|||||||
│ ├── rounding.test.js ← round2/round3 arrondis (v1.9.2 :
|
│ ├── rounding.test.js ← round2/round3 arrondis (v1.9.2 :
|
||||||
│ │ harmonisation Android, fin de la
|
│ │ harmonisation Android, fin de la
|
||||||
│ │ troncature historique)
|
│ │ troncature historique)
|
||||||
|
│ ├── presets.test.js ← PKPresetsTest.kt (v1.9.4 : presets des
|
||||||
|
│ │ 6 esters ESE, unicité, i18n EN/FR,
|
||||||
|
│ │ choicesForModel aligné dispatchs)
|
||||||
│ ├── lab-timing.test.js ← LabTimingTest.kt (v1.8.0 : prochaine
|
│ ├── lab-timing.test.js ← LabTimingTest.kt (v1.8.0 : prochaine
|
||||||
│ │ prise de sang recommandée — creux avant
|
│ │ prise de sang recommandée — creux avant
|
||||||
│ │ créneau, saut de stabilisation, gardes)
|
│ │ créneau, saut de stabilisation, gardes)
|
||||||
@ -456,6 +460,12 @@ launch) — d'où le build dédié dans le cache Playwright, hors dépôt.
|
|||||||
exclusivité ESE — TFS/oral hors nuage, gardes vides) + **round2/round3
|
exclusivité ESE — TFS/oral hors nuage, gardes vides) + **round2/round3
|
||||||
ARRONDIS** (v1.9.2 : fin de la troncature historique — harmonisation des
|
ARRONDIS** (v1.9.2 : fin de la troncature historique — harmonisation des
|
||||||
niveaux web/Android, cf CHANGELOG Android 1.8.2) ;
|
niveaux web/Android, cf CHANGELOG Android 1.8.2) ;
|
||||||
|
- **presets** : v1.9.4 (miroir `PKPresetsTest.kt`) — les presets ESE
|
||||||
|
couvrent les 6 esters du fit analytique (unicité, clés i18n EN/FR),
|
||||||
|
TFS (7) / WHSAH (6) inchangés, et **`choicesForModel` aligné sur les
|
||||||
|
dispatchs** (ESE 6 / TFS 7 explicite sans EUCS / WHS 6) — l'éditeur et
|
||||||
|
le dialog de dose ne peuvent proposer un ester que le moteur sait
|
||||||
|
tracer ;
|
||||||
- **backup** : round-trip v2, rétrocompat v1, écrasement + IDs conservés,
|
- **backup** : round-trip v2, rétrocompat v1, écrasement + IDs conservés,
|
||||||
**imports des exports Android réels** (data-driven, hors dépôt).
|
**imports des exports Android réels** (data-driven, hors dépôt).
|
||||||
- **chart-helpers** : cumul fractionnaire du pan (#62), minuit local (#55),
|
- **chart-helpers** : cumul fractionnaire du pan (#62), minuit local (#55),
|
||||||
|
|||||||
@ -40,10 +40,10 @@ export const AdministrationRoute = {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Esters proposables dans l'override par dose pour un MODÈLE PK donné
|
* Esters proposables dans l'override par dose pour un MODÈLE PK donné
|
||||||
* (miroir de `Esters.choicesForModel`, v1.4.6 — la liste suit la couverture
|
* (miroir de `Esters.choicesForModel` — la liste suit la couverture RÉELLE
|
||||||
* du modèle : TFS = 7 esters ; WHSAH = 6 (PEP non couvert) ; Estrannaise
|
* du modèle : TFS = 7 esters ; WHSAH = 6 (PEP non couvert) ; Estrannaise
|
||||||
* (tables ODS) = EV/EU/EEn seulement — un traitement ESE + EB produirait
|
* ANALYTIQUE (v1.9.0) = 6 esters injectables, dont EUCS exclusif à ce fit —
|
||||||
* 0 pg/mL).
|
* un ester hors liste produirait 0 pg/mL : aucun fallback silencieux).
|
||||||
*
|
*
|
||||||
* @param {string} pkModel
|
* @param {string} pkModel
|
||||||
* @returns {string[]}
|
* @returns {string[]}
|
||||||
@ -51,6 +51,7 @@ export const AdministrationRoute = {
|
|||||||
export function choicesForModel(pkModel) {
|
export function choicesForModel(pkModel) {
|
||||||
if (pkModel === 'TFS') return ['EV', 'EU', 'EEN', 'EB', 'EC', 'ECS', 'PEP'];
|
if (pkModel === 'TFS') return ['EV', 'EU', 'EEN', 'EB', 'EC', 'ECS', 'PEP'];
|
||||||
if (pkModel === 'WHS') return ['EV', 'EU', 'EEN', 'EB', 'EC', 'ECS'];
|
if (pkModel === 'WHS') return ['EV', 'EU', 'EEN', 'EB', 'EC', 'ECS'];
|
||||||
|
if (pkModel === 'ESE') return ['EV', 'EU', 'EEN', 'EC', 'EB', 'EUCS']; // v1.9.4 : analytique (parité Android v1.9.0)
|
||||||
return ['EV', 'EU', 'EEN'];
|
return ['EV', 'EU', 'EEN'];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -55,6 +55,7 @@ export class TConfig {
|
|||||||
export const Esters = {
|
export const Esters = {
|
||||||
NONE: 'NONE', EV: 'EV', EU: 'EU', EEN: 'EEN',
|
NONE: 'NONE', EV: 'EV', EU: 'EU', EEN: 'EEN',
|
||||||
EB: 'EB', EC: 'EC', ECS: 'ECS', PEP: 'PEP',
|
EB: 'EB', EC: 'EC', ECS: 'ECS', PEP: 'PEP',
|
||||||
|
EUCS: 'EUCS', // v1.9.4 : undécylate suspension cristalline (fit Estrannaise seulement)
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Constantes de modèles PK (miroir de `PKModels.kt`). */
|
/** Constantes de modèles PK (miroir de `PKModels.kt`). */
|
||||||
|
|||||||
@ -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.9.3';
|
export const WEB_VERSION = '1.9.4';
|
||||||
|
|
||||||
/** 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) {
|
||||||
|
|||||||
@ -2,8 +2,13 @@
|
|||||||
* ─────────────────────────────────────────────────────────────────────────────
|
* ─────────────────────────────────────────────────────────────────────────────
|
||||||
* Éditeur de traitement (portage de `ui/screens/TreatmentEditorScreen.kt`).
|
* Éditeur de traitement (portage de `ui/screens/TreatmentEditorScreen.kt`).
|
||||||
*
|
*
|
||||||
* - presets (PKPresets, 22 entrées) pré-remplissent tout (création) ;
|
* - presets (PKPresets, 25 entrées) pré-remplissent tout (création) —
|
||||||
* - champs conditionnels : ester + modèle PK si injection, Bateman sinon ;
|
* v1.9.4 : le modèle ESE offre ses 6 esters injectables (EV/EU/EEn/EC/
|
||||||
|
* EB/EUCS), au même niveau que les presets TFS (7) et WHSAH (6) ;
|
||||||
|
* - champs conditionnels : ester + modèle PK si injection, Bateman sinon —
|
||||||
|
* v1.9.4 : la liste des esters suit la couverture RÉELLE du modèle
|
||||||
|
* choisi (choicesForModel) et rebascule sur EV si l'ester courant
|
||||||
|
* n'y est plus (garde anti « 0 pg/mL ») ;
|
||||||
* - carte Calibration : facteur manuel + bouton « Calibrer avec les
|
* - carte Calibration : facteur manuel + bouton « Calibrer avec les
|
||||||
* analyses » (computeScaleFactor — médiane lab ÷ prédiction, garde #61) ;
|
* analyses » (computeScaleFactor — médiane lab ÷ prédiction, garde #61) ;
|
||||||
* hint quand l'auto-calibration écrase le facteur à l'affichage (v1.4.9) ;
|
* hint quand l'auto-calibration écrase le facteur à l'affichage (v1.4.9) ;
|
||||||
@ -22,7 +27,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { store } from '../data/store.js';
|
import { store } from '../data/store.js';
|
||||||
import { newTreatment, isInjectionRoute, typeLabelKey, routeLabelKey, modelLabelKey } from '../data/models.js';
|
import { newTreatment, isInjectionRoute, typeLabelKey, routeLabelKey, modelLabelKey, choicesForModel } from '../data/models.js';
|
||||||
import { all as allPresets } from '../pk/presets.js';
|
import { all as allPresets } from '../pk/presets.js';
|
||||||
import { computeScaleFactor } from '../pk/pk-calibration.js';
|
import { computeScaleFactor } from '../pk/pk-calibration.js';
|
||||||
import { t } from '../util/i18n.js';
|
import { t } from '../util/i18n.js';
|
||||||
@ -124,14 +129,25 @@ export function renderTreatmentEditor(container, ctx) {
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
if (isInjectionRoute(st.route)) {
|
if (isInjectionRoute(st.route)) {
|
||||||
// Ester : liste simple (miroir Android — EV/EU/EEn dans l'éditeur ;
|
// Ester : liste = couverture RÉELLE du modèle choisi (v1.9.4 —
|
||||||
// les 7 esters sont proposables dans l'OVERRIDE par dose du DoseDialog)
|
// miroir Android Esters.choicesForModel) : ESE offre ses 6 esters
|
||||||
const esterOptions = ['EV', 'EU', 'EEN'].map((x) => ({ value: x, label: x }));
|
// injectables depuis l'éditeur, au lieu des seuls EV/EU/EEn de
|
||||||
|
// l'époque des tables ODS. L'override par dose du dialog garde le
|
||||||
|
// même helper (pas de divergence des deux listes).
|
||||||
|
const esterOptions = choicesForModel(st.model).map((x) => ({ value: x, label: x }));
|
||||||
form.appendChild(dropdown(t('ester'), st.ester, esterOptions, (v) => { st.ester = v; }));
|
form.appendChild(dropdown(t('ester'), st.ester, esterOptions, (v) => { st.ester = v; }));
|
||||||
|
|
||||||
// Modèle PK : 3 choix (v1.4.6 — WHSAH ajouté)
|
// Modèle PK : 3 choix (v1.4.6 — WHSAH ajouté). Au changement de
|
||||||
|
// modèle, l'ester courant peut sortir de la couverture (ex. EUCS +
|
||||||
|
// TFS : le V3C n'a pas de paramètres EUCS → 0 pg/mL) : on rebascule
|
||||||
|
// sur le premier ester couvert (EV partout) puis on re-rend le
|
||||||
|
// formulaire pour reconstruire la liste des esters (v1.9.4).
|
||||||
const modelOptions = ['ESE', 'TFS', 'WHS'].map((x) => ({ value: x, label: t(modelLabelKey(x)) }));
|
const modelOptions = ['ESE', 'TFS', 'WHS'].map((x) => ({ value: x, label: t(modelLabelKey(x)) }));
|
||||||
form.appendChild(dropdown(t('pk_model'), st.model, modelOptions, (v) => { st.model = v; }));
|
form.appendChild(dropdown(t('pk_model'), st.model, modelOptions, (v) => {
|
||||||
|
st.model = v;
|
||||||
|
if (!choicesForModel(v).includes(st.ester)) st.ester = choicesForModel(v)[0];
|
||||||
|
rerenderForm();
|
||||||
|
}));
|
||||||
} else {
|
} else {
|
||||||
const row1 = el('div', { class: 'row' });
|
const row1 = el('div', { class: 'row' });
|
||||||
row1.appendChild(field({ label: t('pk_absorption'), type: 'number', value: st.tmaxText, onInput: (v) => { st.tmaxText = v; }, attrs: { step: 'any' } }));
|
row1.appendChild(field({ label: t('pk_absorption'), type: 'number', value: st.tmaxText, onInput: (v) => { st.tmaxText = v; }, attrs: { step: 'any' } }));
|
||||||
|
|||||||
@ -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.9.3'), 'dialog : section de la version courante');
|
ok(dlgText.includes('Version 1.9.4'), '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');
|
||||||
@ -334,7 +334,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.9.3 (web)'), 'Paramètres : version affichée');
|
ok(text.includes('Version 1.9.4 (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') });
|
||||||
|
|
||||||
|
|||||||
70
tests/presets.test.js
Normal file
70
tests/presets.test.js
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
/**
|
||||||
|
* Tests des PRESETS de traitements (v1.9.4 — miroir de `PKPresets.kt`) :
|
||||||
|
* le modèle ESE ANALYTIQUE couvre 6 esters injectables — les presets de
|
||||||
|
* création doivent offrir les 6 (comme TFS offre les 7 du V3C et WHSAH
|
||||||
|
* les 6 du fit Mona). Avant v1.9.4, les presets ESE n'offraient que
|
||||||
|
* EV/EU/EEn (l'héritage des tables ODS) — remontée : « les presets n'ont
|
||||||
|
* pas été mis à jour lors de l'ajout du modèle source ESE ».
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { test, describe } from 'node:test';
|
||||||
|
import assert from 'node:assert/strict';
|
||||||
|
import { all } from '../js/pk/presets.js';
|
||||||
|
|
||||||
|
describe('PKPresets web (presets ESE étendus — v1.9.4)', () => {
|
||||||
|
test('les presets ESE couvrent les 6 esters du fit analytique', () => {
|
||||||
|
const eseInjectable = all.filter((p) => p.pkModel === 'ESE' && p.esterType !== 'NONE');
|
||||||
|
const esters = eseInjectable.map((p) => p.esterType).sort();
|
||||||
|
assert.deepEqual(esters, ['EB', 'EC', 'EEN', 'EU', 'EUCS', 'EV']);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('chaque ester couvert a EXACTEMENT un preset ESE (pas de doublon)', () => {
|
||||||
|
const eseInjectable = all.filter((p) => p.pkModel === 'ESE' && p.esterType !== 'NONE');
|
||||||
|
const names = eseInjectable.map((p) => p.nameKey);
|
||||||
|
assert.equal(new Set(names).size, names.length);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('chaque preset a une clé i18n présente dans EN et FR', async () => {
|
||||||
|
const { store } = await import('../js/data/store.js');
|
||||||
|
store.setBackend(new Map()); // Node : pas de localStorage
|
||||||
|
const i18n = await import('../js/util/i18n.js');
|
||||||
|
// t() lit la langue du store (pas de setLanguage exporté) : on force
|
||||||
|
// successivement 'en' puis 'fr' via les settings (miroir de l'app).
|
||||||
|
for (const lang of ['en', 'fr']) {
|
||||||
|
store.setSettings({ language: lang });
|
||||||
|
for (const p of all) {
|
||||||
|
// t() retombe sur la clé brute si absente : un libellé égal à la
|
||||||
|
// clé = clé manquante (leçon §12 web : une string manquante
|
||||||
|
// s'affiche brute dans l'UI)
|
||||||
|
assert.notEqual(i18n.t(p.nameKey), p.nameKey, `clé i18n manquante (${lang}) : ${p.nameKey}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
test('les presets TFS (7) et WHSAH (6) restent inchangés', () => {
|
||||||
|
const injectables = (model) => all.filter((p) => p.pkModel === model && p.esterType !== 'NONE');
|
||||||
|
assert.equal(injectables('TFS').length, 7);
|
||||||
|
assert.equal(injectables('WHS').length, 6);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('choicesForModel (éditeur + dialog de dose) suit la couverture du fit ESE', async () => {
|
||||||
|
// v1.9.4 : l'éditeur liste choicesForModel(model) — si ce helper restait
|
||||||
|
// sur la couverture des tables ODS (3 esters), l'éditeur n'offrirait pas
|
||||||
|
// EC/EB/EUCS même avec les presets à jour (parité Android v1.9.0).
|
||||||
|
const { choicesForModel } = await import('../js/data/models.js');
|
||||||
|
assert.deepEqual(choicesForModel('ESE').sort(), ['EB', 'EC', 'EEN', 'EU', 'EUCS', 'EV']);
|
||||||
|
// TFS reste EXPLICITE à 7 (pas d'EUCS dans le V3C — sinon 0 pg/mL) et
|
||||||
|
// WHSAH à 6 (PEP non couvert).
|
||||||
|
assert.deepEqual(choicesForModel('TFS').sort(), ['EB', 'EC', 'ECS', 'EEN', 'EU', 'EV', 'PEP']);
|
||||||
|
assert.deepEqual(choicesForModel('WHS').sort(), ['EB', 'EC', 'ECS', 'EEN', 'EU', 'EV']);
|
||||||
|
assert.equal(choicesForModel('TFS').includes('EUCS'), false);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('les presets ESE non-injectables (gel/patch/oral) restent en Bateman', () => {
|
||||||
|
const eseNonInjectable = all.filter(
|
||||||
|
(p) => p.pkModel === 'ESE' && (p.esterType === 'NONE' || p.esterType == null),
|
||||||
|
);
|
||||||
|
assert.ok(eseNonInjectable.length >= 3, 'gel/patch/oral toujours présents');
|
||||||
|
assert.ok(eseNonInjectable.every((p) => p.esterType === 'NONE'));
|
||||||
|
});
|
||||||
|
});
|
||||||
Loading…
x
Reference in New Issue
Block a user