@coreui/vue-pro
Version:
UI Components Library for Vue.js
429 lines (355 loc) • 11.9 kB
text/typescript
import { mount, flushPromises } from '@vue/test-utils'
import { nextTick } from 'vue'
import { CAutocomplete } from '../CAutocomplete'
const mockOptions = [
{ label: 'Apple', value: 1 },
{ label: 'Banana', value: 2 },
{ label: 'Cherry', value: 3 },
{ label: 'Date', value: 4 },
]
const mockOptionsWithGroups = [
{
label: 'Fruits',
options: [
{ label: 'Apple', value: 1 },
{ label: 'Banana', value: 2 },
],
},
{
label: 'Vegetables',
options: [
{ label: 'Carrot', value: 3 },
{ label: 'Spinach', value: 4 },
],
},
]
describe('CAutocomplete', () => {
test('loads and displays CAutocomplete component', async () => {
const wrapper = mount(CAutocomplete, {
props: {
options: mockOptions,
},
})
expect(wrapper.html()).toMatchSnapshot()
})
test('CAutocomplete customize', async () => {
const wrapper = mount(CAutocomplete, {
props: {
className: 'bazinga',
disabled: true,
size: 'lg',
placeholder: 'Select option',
options: mockOptions,
cleaner: true,
indicator: true,
},
})
expect(wrapper.html()).toMatchSnapshot()
expect(wrapper.find('.autocomplete').classes()).toContain('bazinga')
expect(wrapper.find('.autocomplete').classes()).toContain('autocomplete-lg')
expect(wrapper.find('.autocomplete').classes()).toContain('disabled')
})
test('CAutocomplete renders input with placeholder', async () => {
const wrapper = mount(CAutocomplete, {
props: {
options: mockOptions,
placeholder: 'Type to search...',
},
})
const input = wrapper.find('input[role="combobox"]')
expect(input.attributes('placeholder')).toBe('Type to search...')
})
test('CAutocomplete opens dropdown on input click', async () => {
const wrapper = mount(CAutocomplete, {
props: {
options: mockOptions,
},
})
const input = wrapper.find('input[role="combobox"]')
await input.trigger('click')
await flushPromises()
const listbox = wrapper.find('[role="listbox"]')
expect(listbox.exists()).toBe(true)
expect(wrapper.find('.autocomplete').classes()).toContain('show')
})
test('CAutocomplete filters options on input change', async () => {
const wrapper = mount(CAutocomplete, {
props: {
options: mockOptions,
},
})
const input = wrapper.find('input[role="combobox"]')
await input.setValue('app')
await input.trigger('input')
await flushPromises()
expect(wrapper.text()).toContain('Apple')
expect(wrapper.text()).not.toContain('Banana')
})
test('CAutocomplete selects option on click', async () => {
const wrapper = mount(CAutocomplete, {
props: {
options: mockOptions,
},
})
const input = wrapper.find('input[role="combobox"]')
await input.trigger('click')
await flushPromises()
const option = wrapper.find('.autocomplete-option')
await option.trigger('click')
await flushPromises()
expect(wrapper.emitted('change')).toBeTruthy()
expect(wrapper.emitted('change')![0]).toEqual([mockOptions[0]])
})
test('CAutocomplete selects option on Enter key', async () => {
const wrapper = mount(CAutocomplete, {
props: {
options: mockOptions,
},
})
const input = wrapper.find('input[role="combobox"]')
await input.setValue('Apple')
await input.trigger('input')
await input.trigger('keydown', { key: 'Enter' })
await flushPromises()
expect(wrapper.emitted('change')).toBeTruthy()
expect(wrapper.emitted('change')![0]).toEqual([mockOptions[0]])
})
test('CAutocomplete closes dropdown on Escape key', async () => {
const wrapper = mount(CAutocomplete, {
props: {
options: mockOptions,
},
})
const input = wrapper.find('input[role="combobox"]')
await input.trigger('click')
await flushPromises()
expect(wrapper.find('.autocomplete').classes()).toContain('show')
await input.trigger('keydown', { key: 'Escape' })
await flushPromises()
expect(input.attributes('aria-expanded')).toBe('false')
expect(wrapper.find('.autocomplete').classes()).not.toContain('show')
})
test('CAutocomplete navigates options with arrow keys', async () => {
const wrapper = mount(CAutocomplete, {
props: {
options: mockOptions,
},
attachTo: document.body,
})
const input = wrapper.find('input[role="combobox"]')
await input.trigger('click')
await flushPromises()
expect(wrapper.find('[role="listbox"]').exists()).toBe(true)
await input.trigger('keydown', { key: 'ArrowDown' })
await nextTick()
const firstOption = wrapper.find('.autocomplete-option')
expect(firstOption.exists()).toBe(true)
})
test('CAutocomplete shows cleaner button when option selected', async () => {
const wrapper = mount(CAutocomplete, {
props: {
options: mockOptions,
cleaner: true,
value: 1,
},
})
await flushPromises()
const cleanerButton = wrapper.find('.autocomplete-cleaner')
expect(cleanerButton.exists()).toBe(true)
})
test('CAutocomplete clears selection when cleaner clicked', async () => {
const wrapper = mount(CAutocomplete, {
props: {
options: mockOptions,
cleaner: true,
value: 1,
},
})
await flushPromises()
const cleanerButton = wrapper.find('.autocomplete-cleaner')
await cleanerButton.trigger('click')
await flushPromises()
expect(wrapper.emitted('change')).toBeTruthy()
expect(wrapper.emitted('change')![0]).toEqual([null])
})
test('CAutocomplete shows no results message', async () => {
const wrapper = mount(CAutocomplete, {
props: {
options: mockOptions,
searchNoResultsLabel: 'No options found',
},
})
const input = wrapper.find('input[role="combobox"]')
await input.setValue('xyz')
await input.trigger('input')
await flushPromises()
expect(wrapper.text()).toContain('No options found')
})
test('CAutocomplete renders option groups', async () => {
const wrapper = mount(CAutocomplete, {
props: {
options: mockOptionsWithGroups,
},
})
const input = wrapper.find('input[role="combobox"]')
await input.trigger('click')
await flushPromises()
expect(wrapper.text()).toContain('Fruits')
expect(wrapper.text()).toContain('Vegetables')
expect(wrapper.text()).toContain('Apple')
expect(wrapper.text()).toContain('Carrot')
})
test('CAutocomplete shows hint when enabled', async () => {
const wrapper = mount(CAutocomplete, {
props: {
options: mockOptions,
showHints: true,
},
})
const input = wrapper.find('input[role="combobox"]')
await input.setValue('ap')
await input.trigger('input')
await flushPromises()
const hintInput = wrapper.find('.autocomplete-input-hint')
expect(hintInput.exists()).toBe(true)
})
test('CAutocomplete allows custom values when allowOnlyDefinedOptions is false', async () => {
const wrapper = mount(CAutocomplete, {
props: {
options: mockOptions,
allowOnlyDefinedOptions: false,
},
})
const input = wrapper.find('input[role="combobox"]')
await input.setValue('Custom Value')
await input.trigger('input')
await input.trigger('keydown', { key: 'Enter' })
await flushPromises()
expect(wrapper.emitted('change')).toBeTruthy()
expect(wrapper.emitted('change')![0]).toEqual(['Custom Value'])
})
test('CAutocomplete prevents custom values when allowOnlyDefinedOptions is true', async () => {
const wrapper = mount(CAutocomplete, {
props: {
options: mockOptions,
allowOnlyDefinedOptions: true,
},
})
const input = wrapper.find('input[role="combobox"]')
await input.setValue('Custom Value')
await input.trigger('input')
await input.trigger('keydown', { key: 'Enter' })
await flushPromises()
expect(wrapper.emitted('change')).toBeFalsy()
})
test('CAutocomplete highlights search matches', async () => {
const wrapper = mount(CAutocomplete, {
props: {
options: mockOptions,
highlightOptionsOnSearch: true,
},
})
const input = wrapper.find('input[role="combobox"]')
await input.setValue('app')
await input.trigger('input')
await flushPromises()
const option = wrapper.find('.autocomplete-option')
expect(option.exists()).toBe(true)
})
test('CAutocomplete is disabled when disabled prop is true', async () => {
const wrapper = mount(CAutocomplete, {
props: {
options: mockOptions,
disabled: true,
},
})
const input = wrapper.find('input[role="combobox"]')
expect(input.attributes('disabled')).toBeDefined()
})
test('CAutocomplete is readonly when readOnly prop is true', async () => {
const wrapper = mount(CAutocomplete, {
props: {
options: mockOptions,
readOnly: true,
},
})
const input = wrapper.find('input[role="combobox"]')
expect(input.attributes('readonly')).toBeDefined()
})
test('CAutocomplete emits input event on search', async () => {
const wrapper = mount(CAutocomplete, {
props: {
options: mockOptions,
},
})
const input = wrapper.find('input[role="combobox"]')
await input.setValue('test')
await input.trigger('input')
await flushPromises()
expect(wrapper.emitted('input')).toBeTruthy()
expect(wrapper.emitted('input')![0]).toEqual(['test'])
})
test('CAutocomplete emits show and hide events', async () => {
const wrapper = mount(CAutocomplete, {
props: {
options: mockOptions,
},
})
const input = wrapper.find('input[role="combobox"]')
// Test show event
await input.trigger('click')
await flushPromises()
expect(wrapper.emitted('show')).toBeTruthy()
// Test hide event
await input.trigger('keydown', { key: 'Escape' })
await flushPromises()
expect(wrapper.emitted('hide')).toBeTruthy()
})
test('CAutocomplete handles string options correctly', async () => {
const stringOptions = ['Apple', 'Banana', 'Cherry']
const wrapper = mount(CAutocomplete, {
props: {
options: stringOptions,
},
})
const input = wrapper.find('input[role="combobox"]')
await input.trigger('click')
await flushPromises()
expect(wrapper.text()).toContain('Apple')
expect(wrapper.text()).toContain('Banana')
expect(wrapper.text()).toContain('Cherry')
})
test('CAutocomplete handles virtual scroller', async () => {
const wrapper = mount(CAutocomplete, {
props: {
options: mockOptions,
virtualScroller: true,
visibleItems: 2,
},
})
const input = wrapper.find('input[role="combobox"]')
await input.trigger('click')
await flushPromises()
expect(wrapper.find('[role="listbox"]').exists()).toBe(true)
})
test('CAutocomplete clears search on select when clearSearchOnSelect is true', async () => {
const wrapper = mount(CAutocomplete, {
props: {
options: mockOptions,
clearSearchOnSelect: true,
},
})
const input = wrapper.find('input[role="combobox"]')
await input.setValue('app')
await input.trigger('input')
await input.trigger('click')
await flushPromises()
const option = wrapper.find('.autocomplete-option')
await option.trigger('click')
await flushPromises()
expect(wrapper.emitted('input')).toBeTruthy()
// Should emit empty string when clearing search
const inputEvents = wrapper.emitted('input') as string[][]
expect(inputEvents[inputEvents.length - 1]).toEqual([''])
})
})