bootstrap-vue
Version:
With more than 85 components, over 45 available plugins, several directives, and 1000+ icons, BootstrapVue provides one of the most comprehensive implementations of the Bootstrap v4 component and grid system available for Vue.js v2.6, complete with extens
643 lines (516 loc) • 20 kB
JavaScript
import { mount } from '@vue/test-utils'
import { waitNT } from '../../../tests/utils'
import { BFormCheckboxGroup } from './form-checkbox-group'
import { BFormCheckbox } from './form-checkbox'
describe('form-checkbox-group', () => {
// --- Structure, class and attributes tests ---
it('default has structure <div></div>', async () => {
const wrapper = mount(BFormCheckboxGroup)
expect(wrapper).toBeDefined()
expect(wrapper.element.tagName).toBe('DIV')
const $children = wrapper.element.children
expect($children.length).toEqual(0)
wrapper.destroy()
})
it('default has no classes on wrapper other than focus ring', async () => {
const wrapper = mount(BFormCheckboxGroup)
expect(wrapper.classes()).toContain('bv-no-focus-ring')
expect(wrapper.classes().length).toEqual(1)
wrapper.destroy()
})
it('default has auto ID set', async () => {
const wrapper = mount(BFormCheckboxGroup, {
attachTo: document.body
})
await waitNT(wrapper.vm)
// Auto ID not generated until after mount
expect(wrapper.attributes('id')).toBeDefined()
wrapper.destroy()
})
it('default has tabindex set to -1', async () => {
const wrapper = mount(BFormCheckboxGroup)
expect(wrapper.attributes('tabindex')).toBeDefined()
expect(wrapper.attributes('tabindex')).toBe('-1')
wrapper.destroy()
})
it('default does not have aria-required set', async () => {
const wrapper = mount(BFormCheckboxGroup)
expect(wrapper.attributes('aria-required')).toBeUndefined()
wrapper.destroy()
})
it('default does not have aria-invalid set', async () => {
const wrapper = mount(BFormCheckboxGroup)
expect(wrapper.attributes('aria-invalid')).toBeUndefined()
wrapper.destroy()
})
it('default has attribute role=group', async () => {
const wrapper = mount(BFormCheckboxGroup)
expect(wrapper.attributes('role')).toBeDefined()
expect(wrapper.attributes('role')).toBe('group')
wrapper.destroy()
})
it('default has user provided ID', async () => {
const wrapper = mount(BFormCheckboxGroup, {
attachTo: document.body,
propsData: {
id: 'test'
}
})
expect(wrapper.attributes('id')).toBeDefined()
expect(wrapper.attributes('id')).toBe('test')
wrapper.destroy()
})
it('default has class was-validated when validated=true', async () => {
const wrapper = mount(BFormCheckboxGroup, {
attachTo: document.body,
propsData: {
validated: true
}
})
expect(wrapper.classes()).toBeDefined()
expect(wrapper.classes()).toContain('was-validated')
wrapper.destroy()
})
it('default has attribute aria-invalid=true when state=false', async () => {
const wrapper = mount(BFormCheckboxGroup, {
attachTo: document.body,
propsData: {
state: false
}
})
expect(wrapper.attributes('aria-invalid')).toBeDefined()
expect(wrapper.attributes('aria-invalid')).toBe('true')
wrapper.destroy()
})
it('default does not have attribute aria-invalid when state=true', async () => {
const wrapper = mount(BFormCheckboxGroup, {
attachTo: document.body,
propsData: {
state: true
}
})
expect(wrapper.attributes('aria-invalid')).toBeUndefined()
wrapper.destroy()
})
it('default does not have attribute aria-invalid when state=null', async () => {
const wrapper = mount(BFormCheckboxGroup, {
attachTo: document.body,
propsData: {
state: null
}
})
expect(wrapper.attributes('aria-invalid')).toBeUndefined()
wrapper.destroy()
})
it('default has attribute aria-invalid=true when aria-invalid=true', async () => {
const wrapper = mount(BFormCheckboxGroup, {
attachTo: document.body,
propsData: {
ariaInvalid: true
}
})
expect(wrapper.attributes('aria-invalid')).toBeDefined()
expect(wrapper.attributes('aria-invalid')).toBe('true')
wrapper.destroy()
})
it('default has attribute aria-invalid=true when aria-invalid="true"', async () => {
const wrapper = mount(BFormCheckboxGroup, {
attachTo: document.body,
propsData: {
ariaInvalid: 'true'
}
})
expect(wrapper.attributes('aria-invalid')).toBeDefined()
expect(wrapper.attributes('aria-invalid')).toBe('true')
wrapper.destroy()
})
it('default has attribute aria-invalid=true when aria-invalid=""', async () => {
const wrapper = mount(BFormCheckboxGroup, {
attachTo: document.body,
propsData: {
ariaInvalid: ''
}
})
expect(wrapper.attributes('aria-invalid')).toBeDefined()
expect(wrapper.attributes('aria-invalid')).toBe('true')
wrapper.destroy()
})
it('has checkboxes with input validation class "is-valid" when `state` is `true`', async () => {
const wrapper = mount(BFormCheckboxGroup, {
attachTo: document.body,
propsData: {
options: ['one', 'two', 'three'],
checked: [],
state: true
}
})
const $checkboxes = wrapper.findAll('input[type=checkbox]')
expect($checkboxes.length).toBe(3)
expect($checkboxes.wrappers.every(c => c.classes().includes('is-valid'))).toBe(true)
expect($checkboxes.wrappers.every(c => c.classes().includes('is-invalid'))).toBe(false)
wrapper.destroy()
})
it('has checkboxes with input validation class "is-invalid" when `state` is `false`', async () => {
const wrapper = mount(BFormCheckboxGroup, {
attachTo: document.body,
propsData: {
options: ['one', 'two', 'three'],
checked: [],
state: false
}
})
const $checkboxes = wrapper.findAll('input[type=checkbox]')
expect($checkboxes.length).toBe(3)
expect($checkboxes.wrappers.every(c => c.classes().includes('is-valid'))).toBe(false)
expect($checkboxes.wrappers.every(c => c.classes().includes('is-invalid'))).toBe(true)
wrapper.destroy()
})
it('has checkboxes with no input validation class when `state` is `null`', async () => {
const wrapper = mount(BFormCheckboxGroup, {
attachTo: document.body,
propsData: {
options: ['one', 'two', 'three'],
checked: [],
state: null
}
})
const $checkboxes = wrapper.findAll('input[type=checkbox]')
expect($checkboxes.length).toBe(3)
expect($checkboxes.wrappers.every(c => c.classes().includes('is-valid'))).toBe(false)
expect($checkboxes.wrappers.every(c => c.classes().includes('is-invalid'))).toBe(false)
wrapper.destroy()
})
// --- Button mode structure ---
it('button mode has classes button-group and button-group-toggle', async () => {
const wrapper = mount(BFormCheckboxGroup, {
attachTo: document.body,
propsData: {
buttons: true
}
})
expect(wrapper.classes()).toBeDefined()
expect(wrapper.classes().length).toBe(3)
expect(wrapper.classes()).toContain('btn-group')
expect(wrapper.classes()).toContain('btn-group-toggle')
expect(wrapper.classes()).toContain('bv-no-focus-ring')
wrapper.destroy()
})
it('button mode has classes button-group-vertical and button-group-toggle when stacked=true', async () => {
const wrapper = mount(BFormCheckboxGroup, {
attachTo: document.body,
propsData: {
buttons: true,
stacked: true
}
})
expect(wrapper.classes()).toBeDefined()
expect(wrapper.classes().length).toBe(3)
expect(wrapper.classes()).toContain('btn-group-vertical')
expect(wrapper.classes()).toContain('btn-group-toggle')
expect(wrapper.classes()).toContain('bv-no-focus-ring')
wrapper.destroy()
})
it('button mode has size class when size prop set', async () => {
const wrapper = mount(BFormCheckboxGroup, {
attachTo: document.body,
propsData: {
buttons: true,
size: 'lg'
}
})
expect(wrapper.classes()).toBeDefined()
expect(wrapper.classes().length).toBe(4)
expect(wrapper.classes()).toContain('btn-group')
expect(wrapper.classes()).toContain('btn-group-toggle')
expect(wrapper.classes()).toContain('btn-group-lg')
expect(wrapper.classes()).toContain('bv-no-focus-ring')
wrapper.destroy()
})
it('button mode has size class when size prop set and stacked', async () => {
const wrapper = mount(BFormCheckboxGroup, {
attachTo: document.body,
propsData: {
buttons: true,
stacked: true,
size: 'lg'
}
})
expect(wrapper.classes()).toBeDefined()
expect(wrapper.classes().length).toBe(4)
expect(wrapper.classes()).toContain('btn-group-vertical')
expect(wrapper.classes()).toContain('btn-group-toggle')
expect(wrapper.classes()).toContain('btn-group-lg')
expect(wrapper.classes()).toContain('bv-no-focus-ring')
wrapper.destroy()
})
it('button mode button variant works', async () => {
const App = {
render(h) {
return h(
BFormCheckboxGroup,
{
props: {
checked: [],
buttons: true,
buttonVariant: 'primary'
}
},
[
h(BFormCheckbox, { props: { value: 'one' } }, 'button 1'),
h(BFormCheckbox, { props: { value: 'two' } }, 'button 2'),
h(BFormCheckbox, { props: { value: 'three', buttonVariant: 'danger' } }, 'button 3')
]
)
}
}
const wrapper = mount(App, {
attachTo: document.body
})
expect(wrapper).toBeDefined()
await waitNT(wrapper.vm)
// Find all the labels with `.btn` class
const $btns = wrapper.findAll('label.btn')
expect($btns).toBeDefined()
expect($btns.length).toBe(3)
// Expect them to have the correct variant classes
expect($btns.at(0).classes()).toContain('btn-primary')
expect($btns.at(1).classes()).toContain('btn-primary')
expect($btns.at(2).classes()).toContain('btn-danger')
wrapper.destroy()
})
// --- Functionality testing ---
it('has checkboxes via options array', async () => {
const wrapper = mount(BFormCheckboxGroup, {
attachTo: document.body,
propsData: {
options: ['one', 'two', 'three'],
checked: []
}
})
expect(wrapper.vm.isRadioGroup).toEqual(false)
expect(wrapper.vm.localChecked).toEqual([])
const $inputs = wrapper.findAll('input')
expect($inputs.length).toBe(3)
expect($inputs.wrappers.every(c => c.element.matches('input[type=checkbox]'))).toBe(true)
wrapper.destroy()
})
it('has checkboxes via options array which respect disabled', async () => {
const wrapper = mount(BFormCheckboxGroup, {
attachTo: document.body,
propsData: {
options: [{ text: 'one' }, { text: 'two' }, { text: 'three', disabled: true }],
checked: []
}
})
expect(wrapper.classes()).toBeDefined()
const $inputs = wrapper.findAll('input')
expect($inputs.length).toBe(3)
expect(wrapper.vm.localChecked).toEqual([])
expect($inputs.wrappers.every(c => c.element.matches('input[type=checkbox]'))).toBe(true)
expect($inputs.at(0).attributes('disabled')).toBeUndefined()
expect($inputs.at(1).attributes('disabled')).toBeUndefined()
expect($inputs.at(2).attributes('disabled')).toBeDefined()
wrapper.destroy()
})
it('emits change event when checkbox clicked', async () => {
const wrapper = mount(BFormCheckboxGroup, {
attachTo: document.body,
propsData: {
options: ['one', 'two', 'three'],
checked: []
}
})
expect(wrapper.classes()).toBeDefined()
const $inputs = wrapper.findAll('input')
expect($inputs.length).toBe(3)
expect(wrapper.vm.localChecked).toEqual([])
await $inputs.at(0).trigger('click')
expect(wrapper.vm.localChecked).toEqual(['one'])
expect(wrapper.emitted('change')).toBeDefined()
expect(wrapper.emitted('change').length).toBe(1)
expect(wrapper.emitted('change')[0][0]).toEqual(['one'])
expect(wrapper.emitted('input')).toBeDefined()
expect(wrapper.emitted('input').length).toBe(1)
expect(wrapper.emitted('input')[0][0]).toEqual(['one'])
await $inputs.at(2).trigger('click')
expect(wrapper.vm.localChecked).toEqual(['one', 'three'])
expect(wrapper.emitted('change').length).toBe(2)
expect(wrapper.emitted('change')[1][0]).toEqual(['one', 'three'])
expect(wrapper.emitted('input').length).toBe(2)
expect(wrapper.emitted('input')[1][0]).toEqual(['one', 'three'])
await $inputs.at(0).trigger('click')
expect(wrapper.vm.localChecked).toEqual(['three'])
expect(wrapper.emitted('change').length).toBe(3)
expect(wrapper.emitted('change')[2][0]).toEqual(['three'])
expect(wrapper.emitted('input').length).toBe(3)
expect(wrapper.emitted('input')[2][0]).toEqual(['three'])
await $inputs.at(1).trigger('click')
expect(wrapper.vm.localChecked).toEqual(['three', 'two'])
expect(wrapper.emitted('change').length).toBe(4)
expect(wrapper.emitted('change')[3][0]).toEqual(['three', 'two'])
expect(wrapper.emitted('input').length).toBe(4)
expect(wrapper.emitted('input')[3][0]).toEqual(['three', 'two'])
wrapper.destroy()
})
it('does not emit "input" event when value loosely changes', async () => {
const value = ['one', 'two', 'three']
const wrapper = mount(BFormCheckboxGroup, {
attachTo: document.body,
propsData: {
options: value.slice(),
checked: value.slice()
}
})
expect(wrapper.classes()).toBeDefined()
const $inputs = wrapper.findAll('input')
expect($inputs.length).toBe(3)
expect(wrapper.vm.localChecked).toEqual(value)
expect($inputs.wrappers.every(c => c.element.matches('input[type=checkbox]'))).toBe(true)
expect($inputs.at(0).element.checked).toBe(true)
expect($inputs.at(1).element.checked).toBe(true)
expect($inputs.at(2).element.checked).toBe(true)
expect(wrapper.emitted('input')).toBeUndefined()
// Set internal value to new array reference
wrapper.vm.localChecked = value.slice()
await waitNT(wrapper.vm)
expect(wrapper.vm.localChecked).toEqual(value)
expect($inputs.wrappers.every(c => c.element.matches('input[type=checkbox]'))).toBe(true)
expect($inputs.at(0).element.checked).toBe(true)
expect($inputs.at(1).element.checked).toBe(true)
expect($inputs.at(2).element.checked).toBe(true)
expect(wrapper.emitted('input')).toBeUndefined()
// Set internal value to new array (reversed order)
wrapper.vm.localChecked = value.slice().reverse()
await waitNT(wrapper.vm)
expect(wrapper.vm.localChecked).toEqual(value.slice().reverse())
expect($inputs.wrappers.every(c => c.element.matches('input[type=checkbox]'))).toBe(true)
expect($inputs.at(0).element.checked).toBe(true)
expect($inputs.at(1).element.checked).toBe(true)
expect($inputs.at(2).element.checked).toBe(true)
expect(wrapper.emitted('input')).toBeDefined()
expect(wrapper.emitted('input').length).toBe(1)
expect(wrapper.emitted('input')[0][0]).toEqual(value.slice().reverse())
wrapper.destroy()
})
it('checkboxes reflect group checked v-model', async () => {
const wrapper = mount(BFormCheckboxGroup, {
attachTo: document.body,
propsData: {
options: ['one', 'two', 'three'],
checked: ['two']
}
})
expect(wrapper.classes()).toBeDefined()
const $inputs = wrapper.findAll('input')
expect($inputs.length).toBe(3)
expect(wrapper.vm.localChecked).toEqual(['two'])
expect($inputs.wrappers.every(c => c.element.matches('input[type=checkbox]'))).toBe(true)
expect($inputs.at(0).element.checked).toBe(false)
expect($inputs.at(1).element.checked).toBe(true)
expect($inputs.at(2).element.checked).toBe(false)
await wrapper.setProps({ checked: ['three', 'one'] })
expect(wrapper.vm.localChecked).toEqual(['three', 'one'])
expect($inputs.wrappers.every(c => c.element.matches('input[type=checkbox]'))).toBe(true)
expect($inputs.at(0).element.checked).toBe(true)
expect($inputs.at(1).element.checked).toBe(false)
expect($inputs.at(2).element.checked).toBe(true)
wrapper.destroy()
})
it('child checkboxes have is-valid classes when group state set to valid', async () => {
const wrapper = mount(BFormCheckboxGroup, {
attachTo: document.body,
propsData: {
options: ['one', 'two', 'three'],
checked: [],
state: true
}
})
expect(wrapper.classes()).toBeDefined()
const $inputs = wrapper.findAll('input')
expect($inputs.length).toBe(3)
expect(wrapper.vm.localChecked).toEqual([])
expect($inputs.wrappers.every(c => c.element.matches('input[type=checkbox]'))).toBe(true)
expect($inputs.wrappers.every(c => c.element.matches('input.is-valid'))).toBe(true)
wrapper.destroy()
})
it('child checkboxes have is-invalid classes when group state set to invalid', async () => {
const wrapper = mount(BFormCheckboxGroup, {
attachTo: document.body,
propsData: {
options: ['one', 'two', 'three'],
checked: [],
state: false
}
})
const $inputs = wrapper.findAll('input')
expect($inputs.length).toBe(3)
expect(wrapper.vm.localChecked).toEqual([])
expect($inputs.wrappers.every(c => c.element.matches('input[type=checkbox]'))).toBe(true)
expect($inputs.wrappers.every(c => c.element.matches('input.is-invalid'))).toBe(true)
wrapper.destroy()
})
it('child checkboxes have disabled attribute when group disabled', async () => {
const wrapper = mount(BFormCheckboxGroup, {
attachTo: document.body,
propsData: {
options: ['one', 'two', 'three'],
checked: [],
disabled: true
}
})
const $inputs = wrapper.findAll('input')
expect($inputs.length).toBe(3)
expect(wrapper.vm.localChecked).toEqual([])
expect($inputs.wrappers.every(c => c.element.matches('input[type=checkbox]'))).toBe(true)
expect($inputs.wrappers.every(c => c.element.matches('input[disabled]'))).toBe(true)
wrapper.destroy()
})
it('child checkboxes have required attribute when group required', async () => {
const wrapper = mount(BFormCheckboxGroup, {
attachTo: document.body,
propsData: {
name: 'group',
options: ['one', 'two', 'three'],
checked: [],
required: true
}
})
const $inputs = wrapper.findAll('input')
expect($inputs.length).toBe(3)
expect(wrapper.vm.localChecked).toEqual([])
expect($inputs.wrappers.every(c => c.element.matches('input[type=checkbox]'))).toBe(true)
expect($inputs.wrappers.every(c => c.element.matches('input[required]'))).toBe(true)
expect($inputs.wrappers.every(c => c.element.matches('input[aria-required="true"]'))).toBe(true)
wrapper.destroy()
})
it('child checkboxes have class custom-control-inline when stacked=false', async () => {
const wrapper = mount(BFormCheckboxGroup, {
attachTo: document.body,
propsData: {
name: 'group',
options: ['one', 'two', 'three'],
checked: [],
stacked: false
}
})
const $inputs = wrapper.findAll('.custom-control')
expect($inputs.length).toBe(3)
expect($inputs.wrappers.every(c => c.find('div.custom-control-inline').exists())).toBe(true)
wrapper.destroy()
})
it('child checkboxes do not have class custom-control-inline when stacked=true', async () => {
const wrapper = mount(BFormCheckboxGroup, {
attachTo: document.body,
propsData: {
name: 'group',
options: ['one', 'two', 'three'],
checked: [],
stacked: true
}
})
const $inputs = wrapper.findAll('.custom-control')
expect($inputs.length).toBe(3)
expect($inputs.wrappers.every(c => c.find('div.custom-control-inline').exists())).toBe(false)
wrapper.destroy()
})
})