import {describe, expect, it} from 'vitest' import {mount} from '@vue/test-utils' import type {DefineComponent} from 'vue' import Checkbox from './Checkbox.vue' type CheckboxProps = { id?: string label?: string name?: string modelValue?: boolean | null inputClass?: string labelClass?: string groupClass?: string required?: boolean disabled?: boolean readonly?: boolean hint?: string error?: string success?: string } const CheckboxForTest = Checkbox as DefineComponent const mountCheckbox = (props: CheckboxProps = {}) => mount(CheckboxForTest, {props}) describe('MalioCheckbox', () => { it('renders a checkbox input', () => { const wrapper = mountCheckbox() expect(wrapper.get('input').attributes('type')).toBe('checkbox') }) it('renders the label text', () => { const wrapper = mountCheckbox({label: 'Accept terms'}) expect(wrapper.get('label').text()).toContain('Accept terms') }) it('uses a provided id on input and label', () => { const wrapper = mountCheckbox({ id: 'checkbox-id', label: 'Accept terms', }) expect(wrapper.get('input').attributes('id')).toBe('checkbox-id') expect(wrapper.get('label').attributes('for')).toBe('checkbox-id') }) it('generates an id when none is provided', () => { const wrapper = mountCheckbox({label: 'Accept terms'}) const inputId = wrapper.get('input').attributes('id') expect(inputId?.startsWith('malio-checkbox-')).toBe(true) expect(wrapper.get('label').attributes('for')).toBe(inputId) }) it('applies the name attribute', () => { const wrapper = mountCheckbox({name: 'terms'}) expect(wrapper.get('input').attributes('name')).toBe('terms') }) it('reflects the checked state from modelValue', () => { const wrapper = mountCheckbox({modelValue: true}) expect((wrapper.get('input').element as HTMLInputElement).checked).toBe(true) }) it('emits update:modelValue when toggled', async () => { const wrapper = mountCheckbox({modelValue: false}) const input = wrapper.get('input') await input.setValue(true) expect(wrapper.emitted('update:modelValue')?.[0]).toEqual([true]) }) it('does not emit when readonly', async () => { const wrapper = mountCheckbox({ modelValue: true, readonly: true, }) const input = wrapper.get('input') await input.setValue(false) expect(wrapper.emitted('update:modelValue')).toBeUndefined() expect((input.element as HTMLInputElement).checked).toBe(true) }) it('sets disabled and required attributes', () => { const wrapper = mountCheckbox({ disabled: true, required: true, }) expect(wrapper.get('input').attributes('disabled')).toBeDefined() expect(wrapper.get('input').attributes('required')).toBeDefined() }) it('shows a hint message and links it with aria-describedby', () => { const wrapper = mountCheckbox({hint: 'Required field'}) const inputId = wrapper.get('input').attributes('id') expect(wrapper.get('p').text()).toBe('Required field') expect(wrapper.get('input').attributes('aria-describedby')).toBe(`${inputId}-describedby`) }) it('shows an error state and message', () => { const wrapper = mountCheckbox({ label: 'Accept terms', error: 'You must accept', }) expect(wrapper.get('input').attributes('aria-invalid')).toBe('true') expect(wrapper.get('label').classes()).toContain('text-m-error') expect(wrapper.get('p').text()).toBe('You must accept') }) it('shows success only when there is no error', () => { const wrapper = mountCheckbox({ success: 'Valid', error: 'Invalid', }) expect(wrapper.get('p').text()).toBe('Invalid') expect(wrapper.get('p').classes()).toContain('text-m-error') }) it('shows success styles and message when there is no error', () => { const wrapper = mountCheckbox({ label: 'Accept terms', success: 'Valid', modelValue: true, }) expect(wrapper.get('label').classes()).toContain('text-m-success') expect(wrapper.get('p').text()).toBe('Valid') expect(wrapper.get('p').classes()).toContain('text-m-success') }) })