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:
@@ -308,7 +308,7 @@ describe('MalioDate', () => {
|
||||
it('efface l\'erreur de saisie quand modelValue change de l\'extérieur', async () => {
|
||||
const wrapper = mountDate({editable: true})
|
||||
const input = wrapper.get('[data-test="date-input"]')
|
||||
await input.setValue('32/13/2026')
|
||||
await input.setValue('31/02/2026')
|
||||
await input.trigger('blur')
|
||||
expect(wrapper.text()).toContain('Date invalide')
|
||||
await wrapper.setProps({modelValue: '2026-05-19'})
|
||||
@@ -338,10 +338,10 @@ describe('MalioDate', () => {
|
||||
it('garde le texte et affiche « Date invalide » sur saisie invalide au blur', async () => {
|
||||
const wrapper = mountDate({editable: true})
|
||||
const input = wrapper.get('[data-test="date-input"]')
|
||||
await input.setValue('32/13/2026')
|
||||
await input.setValue('31/02/2026')
|
||||
await input.trigger('blur')
|
||||
expect(wrapper.emitted('update:modelValue')).toBeUndefined()
|
||||
expect((input.element as HTMLInputElement).value).toBe('32/13/2026')
|
||||
expect((input.element as HTMLInputElement).value).toBe('31/02/2026')
|
||||
expect(input.attributes('aria-invalid')).toBe('true')
|
||||
expect(wrapper.text()).toContain('Date invalide')
|
||||
})
|
||||
@@ -366,7 +366,7 @@ describe('MalioDate', () => {
|
||||
it('efface l\'erreur de saisie quand on sélectionne une date au calendrier', async () => {
|
||||
const wrapper = mountDate({editable: true})
|
||||
const input = wrapper.get('[data-test="date-input"]')
|
||||
await input.setValue('32/13/2026')
|
||||
await input.setValue('31/02/2026')
|
||||
await input.trigger('blur')
|
||||
expect(wrapper.text()).toContain('Date invalide')
|
||||
await input.trigger('focus')
|
||||
@@ -391,8 +391,8 @@ describe('MalioDate', () => {
|
||||
it('utilise le message invalidMessage personnalisé', async () => {
|
||||
const wrapper = mountDate({editable: true, invalidMessage: 'Format incorrect'})
|
||||
const input = wrapper.get('[data-test="date-input"]')
|
||||
// 32/13/2026 : structurellement saisissable (3 ≤ 3, 1 ≤ 1) mais date inexistante.
|
||||
await input.setValue('32/13/2026')
|
||||
// 31/02/2026 : champs valides (jour ≤ 31, mois ≤ 12) mais le 31 février n'existe pas.
|
||||
await input.setValue('31/02/2026')
|
||||
await input.trigger('blur')
|
||||
expect(wrapper.text()).toContain('Format incorrect')
|
||||
})
|
||||
@@ -402,12 +402,23 @@ describe('MalioDate', () => {
|
||||
const input = wrapper.get('[data-test="date-input"]')
|
||||
await input.setValue('99/99/9999')
|
||||
await input.trigger('blur')
|
||||
// Le masque borne le 1er chiffre (jour 0-3, mois 0-1) : « 9 » est rejeté,
|
||||
// la saisie absurde ne s'inscrit jamais et aucune date réelle n'est émise.
|
||||
// Le bornage refuse « 9 » dès le 1er chiffre du jour/mois : la saisie absurde
|
||||
// ne s'inscrit jamais et aucune date réelle n'est émise.
|
||||
expect((input.element as HTMLInputElement).value).not.toContain('99')
|
||||
const emitted = wrapper.emitted('update:modelValue') ?? []
|
||||
expect(emitted.every(([value]) => value === null)).toBe(true)
|
||||
})
|
||||
|
||||
it('empêche un jour > 31 ou un mois > 12 (exemple métier 33/19, 2e chiffre borné)', async () => {
|
||||
const wrapper = mountDate({editable: true})
|
||||
const input = wrapper.get('[data-test="date-input"]')
|
||||
// 33 (jour) : le 2e « 3 » est refusé → seul « 3 » subsiste.
|
||||
await input.setValue('33')
|
||||
expect((input.element as HTMLInputElement).value).toBe('3')
|
||||
// 19 en mois : après un jour valide, le 2e chiffre du mois (« 9 ») est refusé.
|
||||
await input.setValue('15/19')
|
||||
expect((input.element as HTMLInputElement).value).not.toContain('19')
|
||||
})
|
||||
})
|
||||
|
||||
describe('gabarit de saisie (editable)', () => {
|
||||
@@ -451,9 +462,9 @@ describe('MalioDate', () => {
|
||||
it('vide le champ au clic sur la croix même après une saisie invalide (modelValue déjà null)', async () => {
|
||||
const wrapper = mountDate({editable: true})
|
||||
const input = wrapper.get('[data-test="date-input"]')
|
||||
await input.setValue('32/13/2026')
|
||||
await input.setValue('31/02/2026')
|
||||
await input.trigger('blur')
|
||||
expect((input.element as HTMLInputElement).value).toBe('32/13/2026')
|
||||
expect((input.element as HTMLInputElement).value).toBe('31/02/2026')
|
||||
await wrapper.get('[data-test="clear"]').trigger('click')
|
||||
expect((input.element as HTMLInputElement).value).toBe('')
|
||||
})
|
||||
@@ -481,7 +492,7 @@ describe('MalioDate', () => {
|
||||
it('émet valid=false sur saisie malformée sans émettre modelValue', async () => {
|
||||
const wrapper = mountDate({editable: true})
|
||||
const input = wrapper.get('[data-test="date-input"]')
|
||||
await input.setValue('32/13/2026')
|
||||
await input.setValue('31/02/2026')
|
||||
await input.trigger('blur')
|
||||
expect(wrapper.emitted('update:valid')?.at(-1)).toEqual([false])
|
||||
expect(wrapper.emitted('update:modelValue')).toBeUndefined()
|
||||
@@ -520,7 +531,7 @@ describe('MalioDate', () => {
|
||||
it('repasse valid=true quand modelValue change de l\'extérieur après une saisie invalide', async () => {
|
||||
const wrapper = mountDate({editable: true})
|
||||
const input = wrapper.get('[data-test="date-input"]')
|
||||
await input.setValue('32/13/2026')
|
||||
await input.setValue('31/02/2026')
|
||||
await input.trigger('blur')
|
||||
expect(wrapper.emitted('update:valid')?.at(-1)).toEqual([false])
|
||||
await wrapper.setProps({modelValue: '2026-05-19'})
|
||||
@@ -532,9 +543,9 @@ describe('MalioDate', () => {
|
||||
it('émet le texte brut trimmé sur saisie malformée, sans émettre modelValue', async () => {
|
||||
const wrapper = mountDate({editable: true})
|
||||
const input = wrapper.get('[data-test="date-input"]')
|
||||
await input.setValue('32/13/2026')
|
||||
await input.setValue('31/02/2026')
|
||||
await input.trigger('blur')
|
||||
expect(wrapper.emitted('update:rawValue')?.at(-1)).toEqual(['32/13/2026'])
|
||||
expect(wrapper.emitted('update:rawValue')?.at(-1)).toEqual(['31/02/2026'])
|
||||
expect(wrapper.emitted('update:modelValue')).toBeUndefined()
|
||||
})
|
||||
|
||||
@@ -573,9 +584,9 @@ describe('MalioDate', () => {
|
||||
it('émet rawValue vide quand on sélectionne une date au calendrier', async () => {
|
||||
const wrapper = mountDate({editable: true})
|
||||
const input = wrapper.get('[data-test="date-input"]')
|
||||
await input.setValue('32/13/2026')
|
||||
await input.setValue('31/02/2026')
|
||||
await input.trigger('blur')
|
||||
expect(wrapper.emitted('update:rawValue')?.at(-1)).toEqual(['32/13/2026'])
|
||||
expect(wrapper.emitted('update:rawValue')?.at(-1)).toEqual(['31/02/2026'])
|
||||
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([''])
|
||||
|
||||
Reference in New Issue
Block a user