vue-typeahead-bootstrap
Version:
A typeahead/autocomplete component for Vue 2 using Bootstrap 4
360 lines (336 loc) • 11.5 kB
JavaScript
import { mount } from '@vue/test-utils'
import VueTypeaheadBootstrapList from '@/components/VueTypeaheadBootstrapList.vue'
import VueTypeaheadBootstrapListItem from '@/components/VueTypeaheadBootstrapListItem.vue'
describe('VueBootstrapTypeaheadList', () => {
let wrapper
const demoData = [
{
id: 0,
data: 'Canada',
text: 'Canada'
},
{
id: 1,
data: 'USA',
text: 'USA'
},
{
id: 2,
data: 'Mexico',
text: 'Mexico'
},
{
id: 3,
data: 'Canadiana',
text: 'Canadiana'
},
{
id: 4,
data: 'Canada (CA)',
text: 'Canada (CA)'
}
]
beforeEach(() => {
wrapper = mount(VueTypeaheadBootstrapList, {
propsData: {
data: demoData,
vbtUniqueId: 123456789
}
})
})
it('Mounts and renders a list-group div', () => {
expect(wrapper.element.tagName.toLowerCase()).toBe('div')
expect(wrapper.classes()).toContain('list-group')
})
it('Matches items when there is a query', async () => {
expect(wrapper.vm.matchedItems.length).toBe(0)
wrapper.setProps({
query: 'Can'
})
await wrapper.vm.$nextTick()
expect(wrapper.vm.matchedItems.length).toBe(3)
expect(wrapper.findAllComponents(VueTypeaheadBootstrapListItem).length).toBe(3)
wrapper.setProps({
query: 'Canada'
})
await wrapper.vm.$nextTick()
expect(wrapper.vm.matchedItems.length).toBe(2)
expect(wrapper.findAllComponents(VueTypeaheadBootstrapListItem).length).toBe(2)
})
it('Matches no items when there is no query', () => {
expect(wrapper.vm.matchedItems.length).toBe(0)
wrapper.setProps({
query: ''
})
expect(wrapper.vm.matchedItems.length).toBe(0)
expect(wrapper.findAllComponents(VueTypeaheadBootstrapListItem).length).toBe(0)
})
it('Limits the number of matches with maxMatches', () => {
wrapper.setProps({
query: 'can'
})
expect(wrapper.vm.matchedItems.length).toBe(3)
wrapper.setProps({
maxMatches: 1
})
expect(wrapper.vm.matchedItems.length).toBe(1)
})
it('Uses minMatchingChars to filter the number of matches', async () => {
wrapper.setProps({
query: 'c',
minMatchingChars: 1
})
await wrapper.vm.$nextTick()
expect(wrapper.findAllComponents(VueTypeaheadBootstrapListItem).length).toBe(4)
})
it('Highlights text matches properly by default', async () => {
wrapper.setProps({
query: 'Cana'
})
await wrapper.vm.$nextTick()
expect(wrapper.findComponent(VueTypeaheadBootstrapListItem).vm.htmlText).toBe(`<span class='vbt-matched-text'>Cana</span>da`)
})
it('Highlights text matches when query text contains regex escape characters', async () => {
wrapper.setProps({
query: 'Canada (C'
})
await wrapper.vm.$nextTick()
expect(wrapper.findComponent(VueTypeaheadBootstrapListItem).vm.htmlText).toBe(`<span class='vbt-matched-text'>Canada (C</span>A)`)
})
describe('providing accessible text for screen readers', () => {
it('renders screen reader text if provided', async () => {
wrapper.setProps({
data: [
{
id: 0,
data: 'Canada',
text: 'Canada',
screenReaderText: 'my screen reader text',
}
],
query: 'Can'
})
await wrapper.vm.$nextTick()
expect(wrapper.findComponent(VueTypeaheadBootstrapListItem).vm.screenReaderText).toBe('my screen reader text')
})
it("defaults the screen reader text to the item's text if not provided ", async () => {
wrapper.setProps({
data: [
{
id: 0,
data: 'Canada',
text: 'Canada'
},
],
query: 'Can'
})
await wrapper.vm.$nextTick()
expect(wrapper.findComponent(VueTypeaheadBootstrapListItem).vm.screenReaderText).toBe('Canada')
})
})
describe('selecting items with the keyboard', () => {
beforeEach(() => {
wrapper.setProps({
data: [
{
id: 0,
data: 'Canada',
text: 'Canada'
},
{
id: 1,
data: 'Canada1',
text: 'Canada1'
},
{
id: 2,
data: 'Canada2',
text: 'Canada2'
}
],
query: 'Cana'
})
})
describe('using the down arrow', () => {
it('cycles through all options', () => {
wrapper.vm.selectNextListItem()
expect(wrapper.vm.activeListItem).toBe(0)
wrapper.vm.selectNextListItem()
expect(wrapper.vm.activeListItem).toBe(1)
wrapper.vm.selectNextListItem()
expect(wrapper.vm.activeListItem).toBe(2)
})
it('returns the first item when nothing is disabled', () => {
wrapper.vm.selectNextListItem()
expect(wrapper.vm.activeListItem).toBe(0)
})
it('returns the second item when the first is disabled', () => {
wrapper.setProps({ disabledValues: ['Canada'] })
wrapper.vm.selectNextListItem()
expect(wrapper.vm.activeListItem).toBe(1)
})
it('returns the third item when the first and second are disabled', () => {
wrapper.setProps({ disabledValues: ['Canada', 'Canada1'] })
wrapper.vm.selectNextListItem()
expect(wrapper.vm.activeListItem).toBe(2)
})
it('returns -1 when everything is disabled', () => {
wrapper.setProps({ disabledValues: ['Canada', 'Canada1', 'Canada2'] })
wrapper.vm.selectNextListItem()
expect(wrapper.vm.activeListItem).toBe(-1)
wrapper.vm.selectNextListItem()
expect(wrapper.vm.activeListItem).toBe(-1)
})
it('wraps back to the beginning from the end', () => {
wrapper.vm.activeListItem = 1
wrapper.vm.selectNextListItem()
expect(wrapper.vm.activeListItem).toBe(2)
wrapper.vm.selectNextListItem()
expect(wrapper.vm.activeListItem).toBe(0)
})
it('wrapping accounts for disabled items', () => {
wrapper.setProps({ disabledValues: ['Canada'] })
wrapper.vm.activeListItem = 2
wrapper.vm.selectNextListItem()
expect(wrapper.vm.activeListItem).toBe(1)
})
})
describe('using the up arrow', () => {
it('returns the last item when nothing is disabled', () => {
wrapper.vm.selectPreviousListItem()
expect(wrapper.vm.activeListItem).toBe(2)
})
it('returns the second item when the last is disabled', () => {
wrapper.setProps({ disabledValues: ['Canada2'] })
wrapper.vm.selectPreviousListItem()
expect(wrapper.vm.activeListItem).toBe(1)
})
it('returns the second item when the third and fourth are disabled', () => {
wrapper.setProps({ disabledValues: ['Canada3', 'Canada2'] })
wrapper.vm.selectPreviousListItem()
expect(wrapper.vm.activeListItem).toBe(1)
})
it('returns -1 when everything is disabled', () => {
wrapper.setProps({ disabledValues: ['Canada', 'Canada1', 'Canada2', 'Canada3'] })
wrapper.vm.selectPreviousListItem()
expect(wrapper.vm.activeListItem).toBe(-1)
wrapper.vm.selectPreviousListItem()
expect(wrapper.vm.activeListItem).toBe(-1)
})
it('cycles through all options', () => {
wrapper.vm.selectPreviousListItem()
expect(wrapper.vm.activeListItem).toBe(2)
wrapper.vm.selectPreviousListItem()
expect(wrapper.vm.activeListItem).toBe(1)
wrapper.vm.selectPreviousListItem()
expect(wrapper.vm.activeListItem).toBe(0)
})
it('wraps back to the end from the beginning', () => {
wrapper.vm.activeListItem = 1
wrapper.vm.selectPreviousListItem()
expect(wrapper.vm.activeListItem).toBe(0)
wrapper.vm.selectPreviousListItem()
expect(wrapper.vm.activeListItem).toBe(2)
})
it('wrapping accounts for disabled items', () => {
wrapper.setProps({ disabledValues: ['Canada2'] })
wrapper.vm.activeListItem = 0
wrapper.vm.selectPreviousListItem()
expect(wrapper.vm.activeListItem).toBe(1)
})
})
})
describe('Selecting on Enter Key', () => {
beforeEach(() => {
wrapper.setProps({
data: [
{
id: 0,
data: 'Canada',
text: 'Canada'
},
{
id: 1,
data: 'Canada1',
text: 'Canada1'
},
{
id: 2,
data: 'Canada2',
text: 'Canada2'
}
]
})
})
it('does not return a hit with no matches', async () => {
wrapper.setProps({
query: ';lskdj'
})
await wrapper.vm.$nextTick()
wrapper.vm.handleParentInputKeyup({keyCode: 13}) // simulate enter key
await wrapper.vm.$nextTick()
expect(wrapper.emitted('hit')).toBeFalsy()
})
describe('with some matches', () => {
beforeEach(() => {
wrapper.setProps({
query: 'Cana'
})
})
it('returns the selected item when one is selected', async () => {
wrapper.vm.selectNextListItem()
wrapper.vm.selectNextListItem()
await wrapper.vm.$nextTick()
wrapper.vm.handleParentInputKeyup({keyCode: 13}) // simulate enter key
await wrapper.vm.$nextTick()
expect(wrapper.emitted().hit).toBeTruthy()
expect(wrapper.emitted().hit[0][0].data).toBe("Canada1")
})
it('returns the first item when no item is selected', async () => {
await wrapper.vm.$nextTick()
wrapper.vm.handleParentInputKeyup({keyCode: 13}) // simulate enter key
await wrapper.vm.$nextTick()
expect(wrapper.emitted().hit).toBeTruthy()
expect(wrapper.emitted().hit[0][0].data).toBe("Canada")
})
it('returns the first enabled item when no item is selected', async () => {
wrapper.setProps({
disabledValues: ['Canada']
})
wrapper.vm.handleParentInputKeyup({keyCode: 13}) // simulate enter key
await wrapper.vm.$nextTick()
expect(wrapper.emitted().hit).toBeTruthy()
expect(wrapper.emitted().hit[0][0].data).toBe("Canada1")
})
})
it('returns the only non-disabled item as a hit with only one enabled match', async () => {
wrapper.setProps({
disabledValues: ['Canada', 'Canada2'],
query: 'Cana'
})
await wrapper.vm.$nextTick()
wrapper.vm.handleParentInputKeyup({keyCode: 13}) // simulate enter key
await wrapper.vm.$nextTick()
expect(wrapper.emitted().hit).toBeTruthy()
expect(wrapper.emitted().hit[0][0].data).toBe("Canada1")
})
it('does not return a hit with only disabled matches', async () => {
wrapper.setProps({
disabledValues: ['Canada', 'Canada1', 'Canada2'],
query: 'Cana'
})
await wrapper.vm.$nextTick()
wrapper.vm.handleParentInputKeyup({keyCode: 13}) // simulate enter key
await wrapper.vm.$nextTick()
expect(wrapper.emitted('hit')).toBeFalsy()
})
})
it('Highlights text matches properly with highlightClass prop', async () => {
wrapper.setProps({
query: 'Canada',
highlightClass: 'myStyle'
})
await wrapper.vm.$nextTick()
expect(wrapper.findComponent(VueTypeaheadBootstrapListItem).vm.htmlText).toBe(`<span class='myStyle'>Canada</span>`)
})
})