130 lines
5.3 KiB
TypeScript
130 lines
5.3 KiB
TypeScript
import { mount } from '@vue/test-utils';
|
|
import VRadio from './VRadio.vue';
|
|
import { describe, it, expect } from 'vitest';
|
|
|
|
describe('VRadio.vue', () => {
|
|
it('binds modelValue, reflects checked state, and emits update:modelValue', async () => {
|
|
const wrapper = mount(VRadio, {
|
|
props: {
|
|
modelValue: 'initialGroupValue', // This radio is not selected initially
|
|
value: 'thisRadioValue',
|
|
name: 'testGroup',
|
|
id: 'test-radio1',
|
|
},
|
|
});
|
|
const inputElement = wrapper.find('input[type="radio"]');
|
|
|
|
// Initial state (not checked)
|
|
expect(inputElement.element.checked).toBe(false);
|
|
|
|
// Simulate parent selecting this radio button
|
|
await wrapper.setProps({ modelValue: 'thisRadioValue' });
|
|
expect(inputElement.element.checked).toBe(true);
|
|
|
|
// Simulate user clicking this radio (which is already selected by parent)
|
|
// No change event if already checked and clicked again (browser behavior)
|
|
// So, let's test selection from an unselected state by changing modelValue first
|
|
await wrapper.setProps({ modelValue: 'anotherValue' });
|
|
expect(inputElement.element.checked).toBe(false); // Ensure it's unselected
|
|
|
|
// Simulate user clicking this radio button to select it
|
|
// Note: setChecked() on a radio in a group might not trigger change as expected in JSDOM
|
|
// A direct .trigger('change') is more reliable for unit testing radio logic.
|
|
// Or, if the radio is part of a group, only one can be checked.
|
|
// The component's logic is that if it's clicked, it emits its value.
|
|
|
|
// Manually trigger change as if user clicked THIS radio specifically
|
|
await inputElement.trigger('change');
|
|
|
|
expect(wrapper.emitted()['update:modelValue']).toBeTruthy();
|
|
// The last emission (or first if only one) should be its own value
|
|
const emissions = wrapper.emitted()['update:modelValue'];
|
|
expect(emissions[emissions.length -1]).toEqual(['thisRadioValue']);
|
|
|
|
// After emitting, if the parent updates modelValue, it should reflect
|
|
await wrapper.setProps({ modelValue: 'thisRadioValue' });
|
|
expect(inputElement.element.checked).toBe(true);
|
|
});
|
|
|
|
it('is checked when modelValue matches its value', () => {
|
|
const wrapper = mount(VRadio, {
|
|
props: { modelValue: 'selectedVal', value: 'selectedVal', name: 'group' },
|
|
});
|
|
expect(wrapper.find('input[type="radio"]').element.checked).toBe(true);
|
|
});
|
|
|
|
it('is not checked when modelValue does not match its value', () => {
|
|
const wrapper = mount(VRadio, {
|
|
props: { modelValue: 'otherVal', value: 'thisVal', name: 'group' },
|
|
});
|
|
expect(wrapper.find('input[type="radio"]').element.checked).toBe(false);
|
|
});
|
|
|
|
it('renders label when label prop is provided', () => {
|
|
const labelText = 'Select this radio';
|
|
const wrapper = mount(VRadio, {
|
|
props: { modelValue: '', value: 'any', name: 'group', label: labelText },
|
|
});
|
|
const labelElement = wrapper.find('.radio-text-label');
|
|
expect(labelElement.exists()).toBe(true);
|
|
expect(labelElement.text()).toBe(labelText);
|
|
});
|
|
|
|
it('is disabled when disabled prop is true', () => {
|
|
const wrapper = mount(VRadio, {
|
|
props: { modelValue: '', value: 'any', name: 'group', disabled: true },
|
|
});
|
|
expect(wrapper.find('input[type="radio"]').attributes('disabled')).toBeDefined();
|
|
expect(wrapper.find('.radio-label').classes()).toContain('disabled');
|
|
});
|
|
|
|
it('applies name and value attributes correctly', () => {
|
|
const nameVal = 'contactPreference';
|
|
const valueVal = 'email';
|
|
const wrapper = mount(VRadio, {
|
|
props: { modelValue: '', value: valueVal, name: nameVal },
|
|
});
|
|
const input = wrapper.find('input[type="radio"]');
|
|
expect(input.attributes('name')).toBe(nameVal);
|
|
expect(input.attributes('value')).toBe(valueVal);
|
|
});
|
|
|
|
it('passes id prop to input and label for attribute if provided', () => {
|
|
const radioId = 'my-custom-radio-id';
|
|
const wrapper = mount(VRadio, {
|
|
props: { modelValue: '', value: 'any', name: 'group', id: radioId },
|
|
});
|
|
expect(wrapper.find('input[type="radio"]').attributes('id')).toBe(radioId);
|
|
expect(wrapper.find('.radio-label').attributes('for')).toBe(radioId);
|
|
});
|
|
|
|
it('generates an effectiveId if id prop is not provided', () => {
|
|
const wrapper = mount(VRadio, {
|
|
props: { modelValue: '', value: 'valX', name: 'groupY' },
|
|
});
|
|
const expectedId = 'vradio-groupY-valX';
|
|
expect(wrapper.find('input[type="radio"]').attributes('id')).toBe(expectedId);
|
|
expect(wrapper.find('.radio-label').attributes('for')).toBe(expectedId);
|
|
});
|
|
|
|
|
|
it('contains a .checkmark.radio-mark span', () => {
|
|
const wrapper = mount(VRadio, { props: { modelValue: '', value: 'any', name: 'group' } });
|
|
expect(wrapper.find('.checkmark.radio-mark').exists()).toBe(true);
|
|
});
|
|
|
|
it('adds "checked" class to label when radio is checked', () => {
|
|
const wrapper = mount(VRadio, {
|
|
props: { modelValue: 'thisValue', value: 'thisValue', name: 'group' },
|
|
});
|
|
expect(wrapper.find('.radio-label').classes()).toContain('checked');
|
|
});
|
|
|
|
it('does not add "checked" class to label when radio is not checked', () => {
|
|
const wrapper = mount(VRadio, {
|
|
props: { modelValue: 'otherValue', value: 'thisValue', name: 'group' },
|
|
});
|
|
expect(wrapper.find('.radio-label').classes()).not.toContain('checked');
|
|
});
|
|
});
|