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
467 lines (373 loc) • 14.8 kB
JavaScript
import { mount } from '@vue/test-utils'
import { waitNT, waitRAF } from '../../../tests/utils'
import { BCalendar } from './calendar'
import { formatYMD } from '../../utils/date'
// Note that JSDOM only supports `en-US` (`en`) locale for Intl
describe('calendar', () => {
it('has expected base structure', async () => {
const wrapper = mount(BCalendar, {
attachTo: document.body
})
expect(wrapper.vm).toBeDefined()
expect(wrapper.element.tagName).toBe('DIV')
await waitNT(wrapper.vm)
await waitRAF()
expect(wrapper.classes()).toContain('b-calendar')
expect(wrapper.find('.b-calendar>div').exists()).toBe(true)
expect(wrapper.find('.b-calendar>div').attributes('role')).toEqual('group')
expect(wrapper.find('.b-calendar>div').attributes('dir')).toBeDefined()
expect(wrapper.find('.b-calendar>div').attributes('lang')).toBeDefined()
const $header = wrapper.find('.b-calendar>div>header')
expect($header.exists()).toBe(true)
expect($header.find('output').exists()).toBe(true)
expect($header.find('output').attributes('role')).toEqual('status')
expect($header.find('output').attributes('for')).toBeDefined()
expect($header.find('output').attributes('data-selected')).toEqual('')
expect($header.find('output').attributes('aria-live')).toEqual('polite')
expect($header.find('output').attributes('aria-atomic')).toEqual('true')
expect(wrapper.find('.b-calendar>div>div.b-calendar-nav').exists()).toBe(true)
expect(wrapper.find('.b-calendar>div>div.b-calendar-nav').attributes('role')).toEqual('group')
expect(wrapper.findAll('.b-calendar>div>div.b-calendar-nav>button').length).toBe(5)
expect(wrapper.find('.b-calendar>div>div[role="application"]').exists()).toBe(true)
await waitNT(wrapper.vm)
await waitRAF()
wrapper.destroy()
})
it('has expected structure when value is set', async () => {
const wrapper = mount(BCalendar, {
attachTo: document.body,
propsData: {
value: '2020-02-15' // Leap year
}
})
expect(wrapper.vm).toBeDefined()
await waitNT(wrapper.vm)
await waitRAF()
const $header = wrapper.find('.b-calendar>div>header')
expect($header.exists()).toBe(true)
expect($header.find('output').exists()).toBe(true)
expect($header.find('output').attributes('data-selected')).toEqual('2020-02-15')
wrapper.destroy()
})
it('reacts to changes in value', async () => {
const wrapper = mount(BCalendar, {
attachTo: document.body,
propsData: {
value: '2020-01-01' // Leap year
}
})
expect(wrapper.vm).toBeDefined()
await waitNT(wrapper.vm)
await waitRAF()
expect(wrapper.vm.selectedYMD).toBe('2020-01-01')
await wrapper.setProps({
value: '2020-01-15'
})
await waitNT(wrapper.vm)
await waitRAF()
expect(wrapper.vm.selectedYMD).toBe('2020-01-15')
wrapper.destroy()
})
it('clicking a date selects date', async () => {
const wrapper = mount(BCalendar, {
attachTo: document.body,
propsData: {
value: '2020-01-01' // Leap year
}
})
expect(wrapper.vm).toBeDefined()
await waitNT(wrapper.vm)
await waitRAF()
const $grid = wrapper.find('[role="application"]')
expect($grid.exists()).toBe(true)
const $cell = wrapper.find('[data-date="2020-01-25"]')
expect($cell.exists()).toBe(true)
expect($cell.attributes('aria-selected')).toBeUndefined()
expect($cell.attributes('id')).toBeDefined()
const $btn = $cell.find('.btn')
expect($btn.exists()).toBe(true)
expect($cell.attributes('id')).toBeDefined()
expect($grid.attributes('aria-activedescendant')).toBeDefined()
expect($grid.attributes('aria-activedescendant')).not.toEqual($cell.attributes('id'))
await $btn.trigger('click')
expect($cell.attributes('aria-selected')).toBeDefined()
expect($cell.attributes('aria-selected')).toEqual('true')
expect($grid.attributes('aria-activedescendant')).toEqual($cell.attributes('id'))
wrapper.destroy()
})
it('date navigation buttons work', async () => {
const wrapper = mount(BCalendar, {
attachTo: document.body,
propsData: {
showDecadeNav: true,
value: '2020-02-15' // Leap year
}
})
expect(wrapper.vm).toBeDefined()
await waitNT(wrapper.vm)
await waitRAF()
const $grid = wrapper.find('[role="application"]')
expect($grid.exists()).toBe(true)
expect($grid.attributes('data-month')).toBe('2020-02')
const $navBtns = wrapper.findAll('.b-calendar-nav button')
expect($navBtns.length).toBe(7)
// Prev Month
await $navBtns.at(2).trigger('click')
expect($grid.attributes('data-month')).toBe('2020-01')
// Next Month
await $navBtns.at(4).trigger('click')
expect($grid.attributes('data-month')).toBe('2020-02')
// Prev Year
await $navBtns.at(1).trigger('click')
expect($grid.attributes('data-month')).toBe('2019-02')
// Next Year
await $navBtns.at(5).trigger('click')
expect($grid.attributes('data-month')).toBe('2020-02')
// Prev Decade
await $navBtns.at(0).trigger('click')
expect($grid.attributes('data-month')).toBe('2010-02')
// Next Decade
await $navBtns.at(6).trigger('click')
expect($grid.attributes('data-month')).toBe('2020-02')
// Current Month
// Handle the rare case this test is run right at midnight where
// the current month rolled over at midnight when clicked
const thisMonth1 = formatYMD(new Date()).slice(0, -3)
await $navBtns.at(3).trigger('click')
const thisMonth2 = formatYMD(new Date()).slice(0, -3)
const thisMonth = $grid.attributes('data-month')
expect(thisMonth === thisMonth1 || thisMonth === thisMonth2).toBe(true)
wrapper.destroy()
})
it('focus and blur methods work', async () => {
const wrapper = mount(BCalendar, {
attachTo: document.body,
propsData: {
value: '2020-02-15' // Leap year
}
})
expect(wrapper.vm).toBeDefined()
await waitNT(wrapper.vm)
await waitRAF()
const $grid = wrapper.find('[role="application"]')
expect($grid.exists()).toBe(true)
expect($grid.element.tagName).toBe('DIV')
expect(document.activeElement).not.toBe($grid.element)
wrapper.vm.focus()
await waitNT(wrapper.vm)
await waitRAF()
expect(document.activeElement).toBe($grid.element)
wrapper.vm.blur()
await waitNT(wrapper.vm)
await waitRAF()
expect(document.activeElement).not.toBe($grid.element)
wrapper.destroy()
})
it('clicking output header focuses grid', async () => {
const wrapper = mount(BCalendar, {
attachTo: document.body,
propsData: {
value: '2020-02-15' // Leap year
}
})
expect(wrapper.vm).toBeDefined()
await waitNT(wrapper.vm)
await waitRAF()
const $grid = wrapper.find('[role="application"]')
expect($grid.exists()).toBe(true)
expect($grid.element.tagName).toBe('DIV')
expect(document.activeElement).not.toBe($grid.element)
const $output = wrapper.find('header > output')
expect($output.exists()).toBe(true)
await $output.trigger('click')
expect(document.activeElement).toBe($grid.element)
wrapper.vm.blur()
await waitNT(wrapper.vm)
await waitRAF()
expect(document.activeElement).not.toBe($grid.element)
await $output.trigger('focus')
expect(document.activeElement).toBe($grid.element)
wrapper.destroy()
})
it('has correct header tag when "header-tag" prop is set', async () => {
const wrapper = mount(BCalendar, {
attachTo: document.body,
propsData: {
value: '2020-02-15', // Leap year,
headerTag: 'div'
}
})
expect(wrapper.vm).toBeDefined()
await waitNT(wrapper.vm)
await waitRAF()
const $header = wrapper.find('.b-calendar-header')
expect($header.exists()).toBe(true)
expect($header.element.tagName).toBe('DIV')
wrapper.destroy()
})
it('keyboard navigation works', async () => {
const wrapper = mount(BCalendar, {
attachTo: document.body,
propsData: {
value: '2020-02-15' // Leap year
}
})
expect(wrapper.vm).toBeDefined()
await waitNT(wrapper.vm)
await waitRAF()
const $grid = wrapper.find('[role="application"]')
expect($grid.exists()).toBe(true)
expect($grid.attributes('aria-activedescendant')).toBeDefined()
let $cell = wrapper.find('[data-date="2020-02-15"]')
expect($cell.exists()).toBe(true)
expect($cell.attributes('id')).toBeDefined()
expect($grid.attributes('aria-activedescendant')).toEqual($cell.attributes('id'))
// Left
await $grid.trigger('keydown.left')
$cell = wrapper.find('[data-date="2020-02-14"]')
expect($cell.exists()).toBe(true)
expect($cell.attributes('id')).toBeDefined()
expect($grid.attributes('aria-activedescendant')).toEqual($cell.attributes('id'))
// Right
await $grid.trigger('keydown.right')
$cell = wrapper.find('[data-date="2020-02-15"]')
expect($cell.exists()).toBe(true)
expect($cell.attributes('id')).toBeDefined()
expect($grid.attributes('aria-activedescendant')).toEqual($cell.attributes('id'))
// Up
await $grid.trigger('keydown.up')
$cell = wrapper.find('[data-date="2020-02-08"]')
expect($cell.exists()).toBe(true)
expect($cell.attributes('id')).toBeDefined()
expect($grid.attributes('aria-activedescendant')).toEqual($cell.attributes('id'))
// Down
await $grid.trigger('keydown.down')
$cell = wrapper.find('[data-date="2020-02-15"]')
expect($cell.exists()).toBe(true)
expect($cell.attributes('id')).toBeDefined()
expect($grid.attributes('aria-activedescendant')).toEqual($cell.attributes('id'))
// PageUp
await $grid.trigger('keydown.pageup')
$cell = wrapper.find('[data-date="2020-01-15"]')
expect($cell.exists()).toBe(true)
expect($cell.attributes('id')).toBeDefined()
expect($grid.attributes('aria-activedescendant')).toEqual($cell.attributes('id'))
// PageDown
await $grid.trigger('keydown.pagedown')
$cell = wrapper.find('[data-date="2020-02-15"]')
expect($cell.exists()).toBe(true)
expect($cell.attributes('id')).toBeDefined()
expect($grid.attributes('aria-activedescendant')).toEqual($cell.attributes('id'))
// Alt + PageUp
await $grid.trigger('keydown.pageup', { altKey: true })
$cell = wrapper.find('[data-date="2019-02-15"]')
expect($cell.exists()).toBe(true)
expect($cell.attributes('id')).toBeDefined()
expect($grid.attributes('aria-activedescendant')).toEqual($cell.attributes('id'))
// End (selected date)
await $grid.trigger('keydown.end')
$cell = wrapper.find('[data-date="2020-02-15"]')
expect($cell.exists()).toBe(true)
expect($cell.attributes('id')).toBeDefined()
expect($grid.attributes('aria-activedescendant')).toEqual($cell.attributes('id'))
// Alt + PageDown
await $grid.trigger('keydown.pagedown', { altKey: true })
$cell = wrapper.find('[data-date="2021-02-15"]')
expect($cell.exists()).toBe(true)
expect($cell.attributes('id')).toBeDefined()
expect($grid.attributes('aria-activedescendant')).toEqual($cell.attributes('id'))
// Home (today's date)
await $grid.trigger('keydown.home')
const todayID = $grid.attributes('aria-activedescendant')
expect(todayID).toBeDefined()
$cell = $grid.find(`#${todayID}`)
expect($cell.exists()).toBe(true)
expect($cell.attributes('aria-label')).toBeDefined()
expect($cell.attributes('aria-label')).toContain('(Today)')
wrapper.destroy()
})
it('should disable key navigation when `no-key-nav` prop set', () => {
const wrapper = mount(BCalendar, {
attachTo: document.body,
propsData: {
noKeyNav: true,
navButtonVariant: 'primary'
}
})
const $nav = wrapper.find('.b-calendar-nav')
const $buttons = $nav.findAll('button[tabindex="-1"]')
expect($nav.attributes('tabindex')).toEqual('-1')
expect($buttons.length).toEqual(5)
expect(wrapper.find('.b-calendar>div>div[role="application"]').attributes('tabindex')).toEqual(
'-1'
)
})
it('`nav-button-variant` changes nav button class', async () => {
const wrapper = mount(BCalendar, {
attachTo: document.body,
propsData: {
navButtonVariant: 'primary'
}
})
const $nav = wrapper.find('.b-calendar-nav')
const $buttons = $nav.findAll('button')
expect($buttons.length).toBe(5)
expect($buttons.at(0).classes()).toContain('btn-outline-primary')
expect($buttons.at(1).classes()).toContain('btn-outline-primary')
expect($buttons.at(2).classes()).toContain('btn-outline-primary')
expect($buttons.at(3).classes()).toContain('btn-outline-primary')
expect($buttons.at(4).classes()).toContain('btn-outline-primary')
})
it('disables dates based on `date-disabled-fn` prop', async () => {
const wrapper = mount(BCalendar, {
attachTo: document.body,
propsData: {
value: '2020-01-01',
dateDisabledFn(ymd) {
return ymd === '2020-01-02'
}
}
})
expect(wrapper.vm).toBeDefined()
await waitNT(wrapper.vm)
await waitRAF()
const $grid = wrapper.find('[role="application"]')
expect($grid.exists()).toBe(true)
let $cell = $grid.find('[data-date="2020-01-01"]')
expect($cell.exists()).toBe(true)
expect($cell.attributes('aria-disabled')).toBeUndefined()
$cell = $grid.find('[data-date="2020-01-02"]')
expect($cell.exists()).toBe(true)
expect($cell.attributes('aria-disabled')).toEqual('true')
$cell = $grid.find('[data-date="2020-01-03"]')
expect($cell.exists()).toBe(true)
expect($cell.attributes('aria-disabled')).toBeUndefined()
wrapper.destroy()
})
it('applies classes on dates based on `date-info-fn` prop', async () => {
const wrapper = mount(BCalendar, {
attachTo: document.body,
propsData: {
value: '2020-01-01',
dateInfoFn(ymd) {
return ymd === '2020-01-02' ? 'my-info' : null
}
}
})
expect(wrapper.vm).toBeDefined()
await waitNT(wrapper.vm)
await waitRAF()
const $grid = wrapper.find('[role="application"]')
expect($grid.exists()).toBe(true)
let $cell = $grid.find('[data-date="2020-01-01"]')
expect($cell.exists()).toBe(true)
expect($cell.classes()).not.toContain('my-info')
$cell = $grid.find('[data-date="2020-01-02"]')
expect($cell.exists()).toBe(true)
expect($cell.classes()).toContain('my-info')
$cell = $grid.find('[data-date="2020-01-03"]')
expect($cell.exists()).toBe(true)
expect($cell.classes()).not.toContain('my-info')
wrapper.destroy()
})
})