fix(date) : borne le 2e chiffre par champ (jour 1-31, mois 1-12, heure 0-23, minute 0-59)

Le bornage par tokens ne contraignait que le 1er chiffre (positionnel, sans
mémoire du chiffre précédent) : 33 (jour) ou 19 (mois) restaient tapables.

Remplacé par un preProcess maska qui valide chaque champ progressivement : un
chiffre n'est accepté que s'il existe encore une complétion dans [min, max].
Borne donc le 1er ET le 2e chiffre ; les impossibilités calendaires fines
(31/02, 29/02 non bissextile, hors min/max) restent captées par la validation.

Tests d'intégration : 32/13 (désormais non tapable) remplacé par 31/02 comme
date « champs valides mais inexistante » ; garde sur l'exemple métier 33/19.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-18 16:35:25 +02:00
parent 428f30aabe
commit 4a933da19e
7 changed files with 159 additions and 113 deletions
+11 -10
View File
@@ -145,10 +145,10 @@ describe('MalioDateTime', () => {
it('garde le texte et affiche « Date invalide » sur saisie invalide au blur', async () => {
const wrapper = mountDateTime({editable: true})
const input = wrapper.get('[data-test="date-input"]')
await input.setValue('32/13/2026 14:30')
await input.setValue('31/02/2026 14:30')
await input.trigger('blur')
expect(wrapper.emitted('update:modelValue')).toBeUndefined()
expect((input.element as HTMLInputElement).value).toBe('32/13/2026 14:30')
expect((input.element as HTMLInputElement).value).toBe('31/02/2026 14:30')
expect(input.attributes('aria-invalid')).toBe('true')
expect(wrapper.text()).toContain('Date invalide')
})
@@ -197,7 +197,8 @@ describe('MalioDateTime', () => {
it('utilise le message invalidMessage personnalisé', async () => {
const wrapper = mountDateTime({editable: true, invalidMessage: 'Format incorrect'})
const input = wrapper.get('[data-test="date-input"]')
await input.setValue('99/99/9999 10:00')
// 31/02 : champs valides mais date inexistante (le masque la laisse passer, la validation la rejette).
await input.setValue('31/02/2026 10:00')
await input.trigger('blur')
expect(wrapper.text()).toContain('Format incorrect')
})
@@ -205,7 +206,7 @@ describe('MalioDateTime', () => {
it('efface l\'erreur de saisie quand modelValue change de l\'extérieur', async () => {
const wrapper = mountDateTime({editable: true})
const input = wrapper.get('[data-test="date-input"]')
await input.setValue('32/13/2026 14:30')
await input.setValue('31/02/2026 14:30')
await input.trigger('blur')
expect(wrapper.text()).toContain('Date invalide')
await wrapper.setProps({modelValue: '2026-05-20T14:30:00'})
@@ -259,7 +260,7 @@ describe('MalioDateTime', () => {
it('émet valid=false sur saisie malformée sans émettre modelValue', async () => {
const wrapper = mountDateTime({editable: true})
const input = wrapper.get('[data-test="date-input"]')
await input.setValue('32/13/2026 14:30')
await input.setValue('31/02/2026 14:30')
await input.trigger('blur')
expect(wrapper.emitted('update:valid')?.at(-1)).toEqual([false])
expect(wrapper.emitted('update:modelValue')).toBeUndefined()
@@ -289,7 +290,7 @@ describe('MalioDateTime', () => {
it('repasse valid=true quand modelValue change de l\'extérieur après une saisie invalide', async () => {
const wrapper = mountDateTime({editable: true})
const input = wrapper.get('[data-test="date-input"]')
await input.setValue('32/13/2026 14:30')
await input.setValue('31/02/2026 14:30')
await input.trigger('blur')
expect(wrapper.emitted('update:valid')?.at(-1)).toEqual([false])
await wrapper.setProps({modelValue: '2026-05-20T14:30:00'})
@@ -301,9 +302,9 @@ describe('MalioDateTime', () => {
it('émet le texte brut trimmé sur saisie malformée, sans émettre modelValue', async () => {
const wrapper = mountDateTime({editable: true})
const input = wrapper.get('[data-test="date-input"]')
await input.setValue('32/13/2026 14:30')
await input.setValue('31/02/2026 14:30')
await input.trigger('blur')
expect(wrapper.emitted('update:rawValue')?.at(-1)).toEqual(['32/13/2026 14:30'])
expect(wrapper.emitted('update:rawValue')?.at(-1)).toEqual(['31/02/2026 14:30'])
expect(wrapper.emitted('update:modelValue')).toBeUndefined()
})
@@ -342,9 +343,9 @@ describe('MalioDateTime', () => {
it('émet rawValue vide quand on sélectionne une date au calendrier', async () => {
const wrapper = mountDateTime({editable: true})
const input = wrapper.get('[data-test="date-input"]')
await input.setValue('32/13/2026 14:30')
await input.setValue('31/02/2026 14:30')
await input.trigger('blur')
expect(wrapper.emitted('update:rawValue')?.at(-1)).toEqual(['32/13/2026 14:30'])
expect(wrapper.emitted('update:rawValue')?.at(-1)).toEqual(['31/02/2026 14:30'])
await input.trigger('focus')
await wrapper.get('[data-test="day"][data-iso="2026-05-19"]').trigger('click')
expect(wrapper.emitted('update:rawValue')?.at(-1)).toEqual([''])