be3d88ed45
## Problème Sur la famille Date editable, le masque maska n'imposait que la *forme* (`##/##/####`). Une valeur structurellement absurde comme `99/99/9999` était donc **saisissable**, puis rejetée *a posteriori* par la validation. Le métier veut que ce soit **impossible à taper**. ## Solution (masque borné + validation en filet) - `composables/maskTemplate.ts` — `buildBoundedMask(template)` : borne le **premier chiffre de chaque champ** (jour `0-3`, mois `0-1`, heure `0-2`, minute `0-5`). Distingue le mois des minutes (même lettre `M`) selon la présence d'heures dans le gabarit, pour ne pas brider la saisie des minutes du DateTime. - `internal/CalendarField.vue` — branche le builder dans `maskaOptions` (remplace le `replace(/[A-Za-z]/g, '#')`). Les impossibilités plus fines (`31/02`, 29/02 non bissextile, hors `min`/`max`) restent captées par la **validation** (`invalidMessage` + `update:valid=false`). ## Tests - `maskTemplate.test.ts` (5) — bornes par champ, structure du masque, non-confusion mois/minutes. - `Date.test.ts` — test `invalidMessage` adapté (`32/13/2026`, typable→invalide) + garde de non-régression : `99/99/9999` ne s'inscrit jamais et n'émet aucune date. - Suite complète : **1004/1004 verte** (DateTime 36 incluse → saisie d'heure intacte). Doc : `COMPONENTS.md` (MalioDate) + `CHANGELOG.md` (Fixed) à jour. Reviewed-on: #79 Co-authored-by: tristan <tristan@yuno.malio.fr> Co-committed-by: tristan <tristan@yuno.malio.fr>
44 lines
1.9 KiB
TypeScript
44 lines
1.9 KiB
TypeScript
import {describe, it, expect} from 'vitest'
|
||
import {computeVisibleCount} from './tabFit'
|
||
|
||
const base = {gap: 60, chevronReserve: 110}
|
||
const widths = (n: number, w = 180) => Array.from({length: n}, () => w)
|
||
|
||
describe('computeVisibleCount', () => {
|
||
it('sans layout : respecte maxVisibleTabs', () => {
|
||
expect(computeVisibleCount({...base, count: 5, containerWidth: 0, tabWidths: [], maxVisibleTabs: 3})).toBe(3)
|
||
})
|
||
|
||
it('sans layout ni maxVisibleTabs : tous les onglets', () => {
|
||
expect(computeVisibleCount({...base, count: 5, containerWidth: 0, tabWidths: []})).toBe(5)
|
||
})
|
||
|
||
it('tout tient : retourne le total (pas de chevrons)', () => {
|
||
// 4×180 + 3×60 = 900 <= 1000
|
||
expect(computeVisibleCount({...base, count: 4, containerWidth: 1000, tabWidths: widths(4)})).toBe(4)
|
||
})
|
||
|
||
it('trop large : additionne les vraies largeurs (pas la pire) — pas d\'effondrement à 1', () => {
|
||
// total 7×180+6×60=1620 > 1400 ; avail=1400-110=1290 ; 180,420,660,900,1140,(1380>1290) → 5
|
||
expect(computeVisibleCount({...base, count: 7, containerWidth: 1400, tabWidths: widths(7)})).toBe(5)
|
||
})
|
||
|
||
it('largeur étroite : montre ce qui tient (≥ 2 ici, pas 1)', () => {
|
||
// avail=570-110=460 ; 180,(420),(660>460) → 2
|
||
expect(computeVisibleCount({...base, count: 7, containerWidth: 570, tabWidths: widths(7)})).toBe(2)
|
||
})
|
||
|
||
it('maxVisibleTabs plafonne le résultat', () => {
|
||
expect(computeVisibleCount({...base, count: 7, containerWidth: 1400, tabWidths: widths(7), maxVisibleTabs: 3})).toBe(3)
|
||
})
|
||
|
||
it('au moins 1 onglet si rien ne tient', () => {
|
||
expect(computeVisibleCount({...base, count: 5, containerWidth: 150, tabWidths: widths(5, 300)})).toBe(1)
|
||
})
|
||
|
||
it('gère des largeurs hétérogènes', () => {
|
||
// total 1080 > 1000 → fenêtré ; avail=1000-110=890 ; 300,560,820,(1080>890) → 3
|
||
expect(computeVisibleCount({...base, count: 4, containerWidth: 1000, tabWidths: [300, 200, 200, 200]})).toBe(3)
|
||
})
|
||
})
|