Files
malio-layer-ui/app/components/malio/RadioButton.test.ts
kevin 88dd76a0e4 [#364 ] Création d'un composant de type radio (#6)
| Numéro du ticket | Titre du ticket |
|------------------|-----------------|
|           #364        |       Création d'un composant de type radio          |

## Description de la PR

## Modification du .env

## Check list

- [x] Pas de régression
- [x] TU/TI/TF rédigée
- [x] TU/TI/TF OK
- [x] CHANGELOG modifié

Reviewed-on: #6
Co-authored-by: kevin <kevin@yuno.malio.fr>
Co-committed-by: kevin <kevin@yuno.malio.fr>
2026-03-08 18:59:50 +00:00

157 lines
5.3 KiB
TypeScript

import {describe, expect, it} from 'vitest'
import {mount} from '@vue/test-utils'
import type {DefineComponent} from 'vue'
import RadioButton from './RadioButton.vue'
type RadioButtonProps = {
id?: string
label?: string
name?: string
modelValue?: string | number | boolean | null | undefined
value?: string | number | boolean | null | undefined
inputClass?: string
labelClass?: string
groupClass?: string
required?: boolean
disabled?: boolean
readonly?: boolean
hint?: string
error?: string
success?: string
}
const RadioButtonForTest = RadioButton as DefineComponent<RadioButtonProps>
const mountRadioButton = (props: RadioButtonProps = {}) =>
mount(RadioButtonForTest, {
props,
})
describe('MalioRadioButton', () => {
it('renders the label text', () => {
const wrapper = mountRadioButton({label: 'Option 1'})
expect(wrapper.get('.radio-text').text()).toBe('Option 1')
})
it('applies provided id to input and label', () => {
const wrapper = mountRadioButton({id: 'radio-id', label: 'Option 1'})
expect(wrapper.get('input').attributes('id')).toBe('radio-id')
expect(wrapper.get('.radio-text').attributes('for')).toBe('radio-id')
})
it('generates an id when missing and reuses it on label', () => {
const wrapper = mountRadioButton({label: 'Option 1'})
const inputId = wrapper.get('input').attributes('id')
expect(inputId?.startsWith('malio-radio-')).toBe(true)
expect(wrapper.get('.radio-text').attributes('for')).toBe(inputId)
})
it('applies the name attribute', () => {
const wrapper = mountRadioButton({name: 'choice-group'})
expect(wrapper.get('input').attributes('name')).toBe('choice-group')
})
it('sets required when true', () => {
const wrapper = mountRadioButton({required: true})
expect(wrapper.get('input').attributes('required')).toBeDefined()
})
it('sets disabled styles when true', () => {
const wrapper = mountRadioButton({disabled: true, label: 'Option 1'})
expect(wrapper.get('input').attributes('disabled')).toBeDefined()
expect(wrapper.get('.radio-control').classes()).toContain('is-disabled')
expect(wrapper.get('.radio-text').classes()).toContain('cursor-not-allowed')
})
it('checks the input when modelValue matches value', () => {
const wrapper = mountRadioButton({modelValue: 'a', value: 'a'})
expect((wrapper.get('input').element as HTMLInputElement).checked).toBe(true)
})
it('emits update:modelValue on change', async () => {
const wrapper = mountRadioButton({modelValue: 'a', value: 'b'})
await wrapper.get('input').trigger('change')
expect(wrapper.emitted('update:modelValue')?.[0]).toEqual(['b'])
})
it('prevents updates when readonly', async () => {
const wrapper = mountRadioButton({modelValue: 'a', value: 'b', readonly: true})
const input = wrapper.get('input')
;(input.element as HTMLInputElement).checked = true
await input.trigger('change')
expect(wrapper.emitted('update:modelValue')).toBeUndefined()
expect((input.element as HTMLInputElement).checked).toBe(false)
})
it('shows hint message and wires aria-describedby', () => {
const wrapper = mountRadioButton({hint: 'Helpful hint'})
const input = wrapper.get('input')
const message = wrapper.get('.radio-message')
expect(message.text()).toBe('Helpful hint')
expect(input.attributes('aria-describedby')).toBe(message.attributes('id'))
expect(input.attributes('aria-invalid')).toBe('false')
})
it('shows error state on control, label and helper text', () => {
const wrapper = mountRadioButton({
label: 'Option 1',
error: 'Selection required',
})
expect(wrapper.get('.radio-control').classes()).toContain('is-error')
expect(wrapper.get('.radio-text').classes()).toContain('text-m-error')
expect(wrapper.get('.radio-message').classes()).toContain('text-m-error')
expect(wrapper.get('input').attributes('aria-invalid')).toBe('true')
})
it('shows success state when no error is present', () => {
const wrapper = mountRadioButton({
label: 'Option 1',
success: 'Selection saved',
})
expect(wrapper.get('.radio-control').classes()).toContain('is-success')
expect(wrapper.get('.radio-text').classes()).toContain('text-m-success')
expect(wrapper.get('.radio-message').classes()).toContain('text-m-success')
})
it('prioritizes error over success', () => {
const wrapper = mountRadioButton({
error: 'Selection required',
success: 'Selection saved',
})
expect(wrapper.get('.radio-control').classes()).toContain('is-error')
expect(wrapper.get('.radio-control').classes()).not.toContain('is-success')
expect(wrapper.get('.radio-message').text()).toBe('Selection required')
expect(wrapper.get('.radio-message').classes()).toContain('text-m-error')
})
it('merges custom classes on group, input and label', () => {
const wrapper = mountRadioButton({
label: 'Option 1',
groupClass: 'mt-0 custom-group',
inputClass: 'border-red-500',
labelClass: 'font-bold',
})
expect(wrapper.get('.radio-item').classes()).toContain('custom-group')
expect(wrapper.get('.radio-item').classes()).toContain('mt-0')
expect(wrapper.get('input').classes()).toContain('border-red-500')
expect(wrapper.get('.radio-text').classes()).toContain('font-bold')
})
})