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
386 lines (323 loc) • 11.6 kB
JavaScript
import { mount } from '@vue/test-utils'
import { BButton } from './button'
describe('button', () => {
it('has default structure and classes', async () => {
const wrapper = mount(BButton)
expect(wrapper.element.tagName).toBe('BUTTON')
expect(wrapper.attributes('type')).toBeDefined()
expect(wrapper.attributes('type')).toBe('button')
expect(wrapper.classes()).toContain('btn')
expect(wrapper.classes()).toContain('btn-secondary')
expect(wrapper.classes().length).toBe(2)
expect(wrapper.attributes('href')).toBeUndefined()
expect(wrapper.attributes('role')).toBeUndefined()
expect(wrapper.attributes('disabled')).toBeUndefined()
expect(wrapper.attributes('aria-disabled')).toBeUndefined()
expect(wrapper.attributes('aria-pressed')).toBeUndefined()
expect(wrapper.attributes('autocomplete')).toBeUndefined()
expect(wrapper.attributes('tabindex')).toBeUndefined()
wrapper.destroy()
})
it('renders a link when href provided', async () => {
const wrapper = mount(BButton, {
propsData: {
href: '/foo/bar'
}
})
expect(wrapper.element.tagName).toBe('A')
expect(wrapper.attributes('href')).toBeDefined()
expect(wrapper.attributes('href')).toBe('/foo/bar')
expect(wrapper.attributes('type')).toBeUndefined()
expect(wrapper.classes()).toContain('btn')
expect(wrapper.classes()).toContain('btn-secondary')
expect(wrapper.classes().length).toBe(2)
expect(wrapper.attributes('role')).toBeUndefined()
expect(wrapper.attributes('disabled')).toBeUndefined()
expect(wrapper.attributes('aria-disabled')).toBeUndefined()
expect(wrapper.attributes('aria-pressed')).toBeUndefined()
expect(wrapper.attributes('autocomplete')).toBeUndefined()
expect(wrapper.attributes('tabindex')).toBeUndefined()
wrapper.destroy()
})
it('renders default slot content', async () => {
const wrapper = mount(BButton, {
slots: {
default: '<span>foobar</span>'
}
})
expect(wrapper.element.tagName).toBe('BUTTON')
expect(wrapper.attributes('type')).toBeDefined()
expect(wrapper.attributes('type')).toBe('button')
expect(wrapper.classes()).toContain('btn')
expect(wrapper.classes()).toContain('btn-secondary')
expect(wrapper.classes().length).toBe(2)
expect(wrapper.find('span').exists()).toBe(true)
expect(wrapper.text()).toBe('foobar')
wrapper.destroy()
})
it('applies variant class', async () => {
const wrapper = mount(BButton, {
propsData: {
variant: 'danger'
}
})
expect(wrapper.element.tagName).toBe('BUTTON')
expect(wrapper.attributes('type')).toBeDefined()
expect(wrapper.attributes('type')).toBe('button')
expect(wrapper.classes()).toContain('btn')
expect(wrapper.classes()).toContain('btn-danger')
expect(wrapper.classes().length).toBe(2)
wrapper.destroy()
})
it('applies block class', async () => {
const wrapper = mount(BButton, {
propsData: {
block: true
}
})
expect(wrapper.element.tagName).toBe('BUTTON')
expect(wrapper.attributes('type')).toBeDefined()
expect(wrapper.attributes('type')).toBe('button')
expect(wrapper.classes()).toContain('btn')
expect(wrapper.classes()).toContain('btn-secondary')
expect(wrapper.classes()).toContain('btn-block')
expect(wrapper.classes().length).toBe(3)
wrapper.destroy()
})
it('applies rounded-pill class when pill prop set', async () => {
const wrapper = mount(BButton, {
propsData: {
pill: true
}
})
expect(wrapper.element.tagName).toBe('BUTTON')
expect(wrapper.attributes('type')).toBeDefined()
expect(wrapper.attributes('type')).toBe('button')
expect(wrapper.classes()).toContain('btn')
expect(wrapper.classes()).toContain('btn-secondary')
expect(wrapper.classes()).toContain('rounded-pill')
expect(wrapper.classes().length).toBe(3)
wrapper.destroy()
})
it('applies rounded-0 class when squared prop set', async () => {
const wrapper = mount(BButton, {
propsData: {
squared: true
}
})
expect(wrapper.element.tagName).toBe('BUTTON')
expect(wrapper.attributes('type')).toBeDefined()
expect(wrapper.attributes('type')).toBe('button')
expect(wrapper.classes()).toContain('btn')
expect(wrapper.classes()).toContain('btn-secondary')
expect(wrapper.classes()).toContain('rounded-0')
expect(wrapper.classes().length).toBe(3)
wrapper.destroy()
})
it('renders custom root element', async () => {
const wrapper = mount(BButton, {
propsData: {
tag: 'div'
}
})
expect(wrapper.element.tagName).toBe('DIV')
expect(wrapper.attributes('type')).toBeUndefined()
expect(wrapper.classes()).toContain('btn')
expect(wrapper.classes()).toContain('btn-secondary')
expect(wrapper.classes().length).toBe(2)
expect(wrapper.attributes('role')).toBe('button')
expect(wrapper.attributes('aria-disabled')).toBe('false')
expect(wrapper.attributes('tabindex')).toBe('0')
expect(wrapper.attributes('disabled')).toBeUndefined()
expect(wrapper.attributes('aria-pressed')).toBeUndefined()
expect(wrapper.attributes('autocomplete')).toBeUndefined()
wrapper.destroy()
})
it('button has attribute disabled when disabled set', async () => {
const wrapper = mount(BButton, {
propsData: {
disabled: true
}
})
expect(wrapper.element.tagName).toBe('BUTTON')
expect(wrapper.attributes('type')).toBe('button')
expect(wrapper.classes()).toContain('btn')
expect(wrapper.classes()).toContain('btn-secondary')
expect(wrapper.classes()).toContain('disabled')
expect(wrapper.classes().length).toBe(3)
expect(wrapper.attributes('aria-disabled')).toBeUndefined()
wrapper.destroy()
})
it('link has attribute aria-disabled when disabled set', async () => {
const wrapper = mount(BButton, {
propsData: {
href: '/foo/bar',
disabled: true
}
})
expect(wrapper.element.tagName).toBe('A')
expect(wrapper.classes()).toContain('btn')
expect(wrapper.classes()).toContain('btn-secondary')
expect(wrapper.classes()).toContain('disabled')
// Both <b-button> and <b-link> add the class 'disabled'
// `vue-functional-data-merge` or Vue doesn't appear to de-dup classes
// expect(wrapper.classes().length).toBe(3)
// Actually returns 4, as disabled is there twice
expect(wrapper.attributes('aria-disabled')).toBeDefined()
expect(wrapper.attributes('aria-disabled')).toBe('true')
// Shouldn't have a role with href not `#`
expect(wrapper.attributes('role')).not.toEqual('button')
wrapper.destroy()
})
it('link with href="#" should have role="button"', async () => {
const wrapper = mount(BButton, {
propsData: {
href: '#'
}
})
expect(wrapper.element.tagName).toBe('A')
expect(wrapper.classes()).toContain('btn')
expect(wrapper.classes()).toContain('btn-secondary')
expect(wrapper.classes()).not.toContain('disabled')
expect(wrapper.attributes('role')).toEqual('button')
wrapper.destroy()
})
it('should emit click event when clicked', async () => {
let called = 0
let event = null
const wrapper = mount(BButton, {
listeners: {
click: e => {
event = e
called++
}
}
})
expect(wrapper.element.tagName).toBe('BUTTON')
expect(called).toBe(0)
expect(event).toEqual(null)
await wrapper.find('button').trigger('click')
expect(called).toBe(1)
expect(event).toBeInstanceOf(MouseEvent)
wrapper.destroy()
})
it('link with href="#" should treat keydown.space as click', async () => {
let called = 0
let event = null
const wrapper = mount(BButton, {
propsData: {
href: '#'
},
listeners: {
click: e => {
event = e
called++
}
}
})
expect(wrapper.element.tagName).toBe('A')
expect(wrapper.classes()).toContain('btn')
expect(wrapper.classes()).toContain('btn-secondary')
expect(wrapper.classes()).not.toContain('disabled')
expect(wrapper.attributes('role')).toEqual('button')
expect(called).toBe(0)
expect(event).toEqual(null)
// We add keydown.space to make links act like buttons
await wrapper.find('.btn').trigger('keydown.space')
expect(called).toBe(1)
expect(event).toBeInstanceOf(Event)
// Links treat keydown.enter natively as a click
wrapper.destroy()
})
it('should not emit click event when clicked and disabled', async () => {
let called = 0
const wrapper = mount(BButton, {
propsData: {
disabled: true
},
listeners: {
click: () => {
called++
}
}
})
expect(wrapper.element.tagName).toBe('BUTTON')
expect(called).toBe(0)
await wrapper.find('button').trigger('click')
expect(called).toBe(0)
wrapper.destroy()
})
it('should not have `.active` class and `aria-pressed` when pressed is null', async () => {
const wrapper = mount(BButton, {
propsData: {
pressed: null
}
})
expect(wrapper.classes()).not.toContain('active')
expect(wrapper.attributes('aria-pressed')).toBeUndefined()
await wrapper.find('button').trigger('click')
expect(wrapper.classes()).not.toContain('active')
expect(wrapper.attributes('aria-pressed')).toBeUndefined()
expect(wrapper.attributes('autocomplete')).toBeUndefined()
wrapper.destroy()
})
it('should not have `.active` class and have `aria-pressed="false"` when pressed is false', async () => {
const wrapper = mount(BButton, {
propsData: {
pressed: false
}
})
expect(wrapper.classes()).not.toContain('active')
expect(wrapper.attributes('aria-pressed')).toBeDefined()
expect(wrapper.attributes('aria-pressed')).toBe('false')
expect(wrapper.attributes('autocomplete')).toBeDefined()
expect(wrapper.attributes('autocomplete')).toBe('off')
wrapper.destroy()
})
it('should have `.active` class and have `aria-pressed="true"` when pressed is true', async () => {
const wrapper = mount(BButton, {
propsData: {
pressed: true
}
})
expect(wrapper.classes()).toContain('active')
expect(wrapper.attributes('aria-pressed')).toBeDefined()
expect(wrapper.attributes('aria-pressed')).toBe('true')
expect(wrapper.attributes('autocomplete')).toBeDefined()
expect(wrapper.attributes('autocomplete')).toBe('off')
wrapper.destroy()
})
it('pressed should have `.focus` class when focused', async () => {
const wrapper = mount(BButton, {
propsData: {
pressed: false
}
})
expect(wrapper.classes()).not.toContain('focus')
await wrapper.trigger('focusin')
expect(wrapper.classes()).toContain('focus')
await wrapper.trigger('focusout')
expect(wrapper.classes()).not.toContain('focus')
wrapper.destroy()
})
it('should update the parent sync value on click and when pressed is not null', async () => {
let called = 0
const values = []
const wrapper = mount(BButton, {
propsData: {
pressed: false
},
listeners: {
'update:pressed': value => {
values.push(value)
called++
}
}
})
expect(called).toBe(0)
await wrapper.find('button').trigger('click')
expect(called).toBe(1)
expect(values[0]).toBe(true)
wrapper.destroy()
})
})