All checks were successful
Release / release (push) Successful in 1m14s
| Numéro du ticket | Titre du ticket | |------------------|-----------------| | | | ## 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é Co-authored-by: kevin <kevin@yuno.malio.fr> Co-authored-by: Kevin Boudet <kevin@yuno.malio.fr> Reviewed-on: #23 Co-authored-by: tristan <tristan@yuno.malio.fr> Co-committed-by: tristan <tristan@yuno.malio.fr>
178 lines
5.1 KiB
TypeScript
178 lines
5.1 KiB
TypeScript
import {describe, expect, it} from 'vitest'
|
|
import {mount} from '@vue/test-utils'
|
|
import type {DefineComponent} from 'vue'
|
|
import Select from './Select.vue'
|
|
|
|
type Option = {
|
|
label: string
|
|
value: string | number | null
|
|
}
|
|
|
|
type SelectProps = {
|
|
modelValue?: string | number | null
|
|
options?: Option[]
|
|
emptyOptionLabel?: string
|
|
label?: string
|
|
hint?: string
|
|
error?: string
|
|
success?: string
|
|
minWidth?: string
|
|
maxWidth?: string
|
|
textField?: string
|
|
textValue?: string
|
|
textLabel?: string
|
|
rounded?: string
|
|
disabled?: boolean
|
|
}
|
|
|
|
const SelectForTest = Select as DefineComponent<SelectProps>
|
|
|
|
const options: Option[] = [
|
|
{label: 'France', value: 'fr'},
|
|
{label: 'Belgique', value: 'be'},
|
|
{label: 'Canada', value: 'ca'},
|
|
]
|
|
|
|
describe('MalioSelect', () => {
|
|
it('renders the label text', () => {
|
|
const wrapper = mount(SelectForTest, {
|
|
props: {modelValue: null, label: 'Country'},
|
|
})
|
|
|
|
expect(wrapper.get('label').text()).toBe('Country')
|
|
})
|
|
|
|
it('generates button and listbox ids and links them together', async () => {
|
|
const wrapper = mount(SelectForTest, {
|
|
props: {modelValue: null, options},
|
|
})
|
|
|
|
const button = wrapper.get('button')
|
|
expect(button.attributes('id')?.startsWith('custom-select-btn-')).toBe(true)
|
|
expect(button.attributes('aria-controls')?.startsWith('custom-select-listbox-')).toBe(true)
|
|
|
|
await button.trigger('click')
|
|
|
|
expect(wrapper.get('ul').attributes('id')).toBe(button.attributes('aria-controls'))
|
|
})
|
|
|
|
it('uses disabled styles and prevents opening when disabled', async () => {
|
|
const wrapper = mount(SelectForTest, {
|
|
props: {modelValue: null, disabled: true, options},
|
|
})
|
|
|
|
const button = wrapper.get('button')
|
|
expect(button.attributes('disabled')).toBeDefined()
|
|
expect(button.classes()).toContain('cursor-not-allowed')
|
|
|
|
await button.trigger('click')
|
|
|
|
expect(wrapper.find('ul').exists()).toBe(false)
|
|
})
|
|
|
|
it('opens the list and rotates the icon on click', async () => {
|
|
const wrapper = mount(SelectForTest, {
|
|
props: {modelValue: null, options},
|
|
})
|
|
|
|
await wrapper.get('button').trigger('click')
|
|
|
|
expect(wrapper.get('ul').exists()).toBe(true)
|
|
expect(wrapper.get('button').attributes('aria-expanded')).toBe('true')
|
|
expect(wrapper.get('svg').classes()).toContain('rotate-180')
|
|
})
|
|
|
|
it('emits update:modelValue when selecting an option', async () => {
|
|
const wrapper = mount(SelectForTest, {
|
|
props: {modelValue: null, options},
|
|
})
|
|
|
|
await wrapper.get('button').trigger('click')
|
|
await wrapper.findAll('li')[2].trigger('click')
|
|
|
|
expect(wrapper.emitted('update:modelValue')?.[0]).toEqual(['be'])
|
|
})
|
|
|
|
it('renders the empty option with muted text style', async () => {
|
|
const wrapper = mount(SelectForTest, {
|
|
props: {
|
|
modelValue: null,
|
|
options,
|
|
emptyOptionLabel: 'Aucune selection',
|
|
},
|
|
})
|
|
|
|
await wrapper.get('button').trigger('click')
|
|
|
|
const firstOption = wrapper.findAll('li')[0]
|
|
expect(firstOption.text()).toBe('Aucune selection')
|
|
expect(firstOption.classes()).toContain('text-black/40')
|
|
})
|
|
|
|
it('shows the selected value text when an option is selected', () => {
|
|
const wrapper = mount(SelectForTest, {
|
|
props: {
|
|
options,
|
|
modelValue: 'fr',
|
|
},
|
|
})
|
|
|
|
expect(wrapper.text()).toContain('France')
|
|
expect(wrapper.get('button').classes()).toContain('border-black')
|
|
})
|
|
|
|
it('shows hint message in muted color', () => {
|
|
const wrapper = mount(SelectForTest, {
|
|
props: {modelValue: null, hint: 'Select a country'},
|
|
})
|
|
|
|
expect(wrapper.get('p.text-m-muted').text()).toBe('Select a country')
|
|
})
|
|
|
|
it('shows error state on button, label and helper text', () => {
|
|
const wrapper = mount(SelectForTest, {
|
|
props: {
|
|
modelValue: null,
|
|
options,
|
|
label: 'Country',
|
|
error: 'Selection error',
|
|
},
|
|
})
|
|
|
|
expect(wrapper.get('button').classes()).toContain('border-m-danger')
|
|
expect(wrapper.get('label').classes()).toContain('text-m-danger')
|
|
expect(wrapper.get('p.text-m-danger').text()).toBe('Selection error')
|
|
expect(wrapper.get('button').attributes('aria-invalid')).toBe('true')
|
|
})
|
|
|
|
it('shows success state on button, label and helper text', () => {
|
|
const wrapper = mount(SelectForTest, {
|
|
props: {
|
|
modelValue: null,
|
|
options,
|
|
label: 'Country',
|
|
success: 'Selection success',
|
|
},
|
|
})
|
|
|
|
expect(wrapper.get('button').classes()).toContain('border-m-success')
|
|
expect(wrapper.get('label').classes()).toContain('text-m-success')
|
|
expect(wrapper.get('p.text-m-success').text()).toBe('Selection success')
|
|
})
|
|
|
|
it('prioritizes error over success', () => {
|
|
const wrapper = mount(SelectForTest, {
|
|
props: {
|
|
modelValue: null,
|
|
options,
|
|
error: 'Selection error',
|
|
success: 'Selection success',
|
|
},
|
|
})
|
|
|
|
expect(wrapper.get('button').classes()).toContain('border-m-danger')
|
|
expect(wrapper.find('p.text-m-success').exists()).toBe(false)
|
|
expect(wrapper.get('p.text-m-danger').text()).toBe('Selection error')
|
|
})
|
|
})
|