import {describe, expect, it} from 'vitest' import {mount} from '@vue/test-utils' import type {DefineComponent} from 'vue' import Time from './Time.vue' type TimeProps = { id?: string label?: string name?: string modelValue?: string | null inputClass?: string labelClass?: string groupClass?: string required?: boolean disabled?: boolean readonly?: boolean hint?: string error?: string success?: string reserveMessageSpace?: boolean } const TimeForTest = Time as DefineComponent const mountTime = (props: TimeProps = {}) => mount(TimeForTest, {props}) describe('MalioTime', () => { it('renders two text inputs and a separator', () => { const wrapper = mountTime() expect(wrapper.findAll('input')).toHaveLength(2) expect(wrapper.text()).toContain(':') }) it('uses separate ids for hours and minutes inputs', () => { const wrapper = mountTime({label: 'Horaire'}) const inputs = wrapper.findAll('input') expect(inputs[0].attributes('id')).toContain('-hours') expect(inputs[1].attributes('id')).toContain('-minutes') expect(wrapper.get('label').attributes('for')).toBe(inputs[0].attributes('id')) }) it('clamps values to 24 hours and 59 minutes', async () => { const wrapper = mountTime({modelValue: ''}) const inputs = wrapper.findAll('input') await inputs[0].setValue('99') await inputs[1].setValue('88') expect(wrapper.emitted('update:modelValue')?.at(-1)).toEqual(['23:59']) expect((inputs[0].element as HTMLInputElement).value).toBe('23') expect((inputs[1].element as HTMLInputElement).value).toBe('59') }) it('pads single digits on blur', async () => { const wrapper = mountTime({modelValue: ''}) const inputs = wrapper.findAll('input') await inputs[0].setValue('7') await inputs[0].trigger('blur') await inputs[1].setValue('5') await inputs[1].trigger('blur') expect(wrapper.emitted('update:modelValue')?.at(-1)).toEqual(['07:05']) expect((inputs[0].element as HTMLInputElement).value).toBe('07') expect((inputs[1].element as HTMLInputElement).value).toBe('05') }) it('applies the primary border to the focused field', async () => { const wrapper = mountTime() const inputs = wrapper.findAll('input') await inputs[0].trigger('focus') expect(inputs[0].classes()).toContain('border-m-primary') expect(inputs[1].classes()).not.toContain('border-m-primary') }) it('affiche l\'astérisque quand required est vrai', () => { const wrapper = mountTime({label: 'Champ', required: true}) expect(wrapper.find('[data-test="required-mark"]').exists()).toBe(true) }) it('n\'affiche pas l\'astérisque par défaut', () => { const wrapper = mountTime({label: 'Champ'}) expect(wrapper.find('[data-test="required-mark"]').exists()).toBe(false) }) it('réserve l’espace message par défaut même sans message', () => { const wrapper = mountTime({label: 'Champ'}) const msg = wrapper.find('[id$="-describedby"]') expect(msg.exists()).toBe(true) expect(msg.classes()).toContain('min-h-[1rem]') }) it('reserveMessageSpace=false sans message : pas de ligne réservée', () => { const wrapper = mountTime({label: 'Champ', reserveMessageSpace: false}) expect(wrapper.find('[id$="-describedby"]').exists()).toBe(false) }) it('reserveMessageSpace=false avec message : ligne rendue sans min-h', () => { const wrapper = mountTime({label: 'Champ', reserveMessageSpace: false, error: 'Erreur'}) const msg = wrapper.find('[id$="-describedby"]') expect(msg.exists()).toBe(true) expect(msg.classes()).not.toContain('min-h-[1rem]') }) })