Skip to content

Commit cb367e0

Browse files
authored
chore(tests): more tests (#2872)
1 parent ffac355 commit cb367e0

File tree

17 files changed

+745
-132
lines changed

17 files changed

+745
-132
lines changed

src/components/breadcrumb/fixtures/breadcrumb.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,6 @@
66
v-bind="item"
77
:key="index" />
88
</b-breadcrumb>
9-
<!-- test when one of hte items has active set to true
10-
<b-breadcrumb ref="breadcrumb3" :items="item2"></b-breadcrumb>
9+
<!-- test when one of hte items has active set to true -->
10+
<b-breadcrumb ref="breadcrumb3" :items="items3"></b-breadcrumb>
1111
</div>

src/components/breadcrumb/fixtures/breadcrumb.js

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,24 @@ window.app = new Vue({
3535
{
3636
text: 'Library'
3737
}
38+
],
39+
items3: [
40+
{
41+
text: 'Home',
42+
href: 'https://bootstrap-vue.github.io'
43+
},
44+
{
45+
text: 'Admin',
46+
href: '#',
47+
active: true
48+
},
49+
{
50+
text: 'Manage',
51+
href: '#'
52+
},
53+
{
54+
text: 'Library'
55+
}
3856
]
3957
}
4058
})

src/components/button-toolbar/button-toolbar.js

Lines changed: 34 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,6 @@ export default {
2222
default: false
2323
}
2424
},
25-
computed: {
26-
classObject() {
27-
return ['btn-toolbar', this.justify && !this.vertical ? 'justify-content-between' : '']
28-
}
29-
},
3025
mounted() {
3126
if (this.keyNav) {
3227
// Pre-set the tabindexes if the markup does not include tabindex="-1" on the toolbar items
@@ -41,62 +36,51 @@ export default {
4136
this.focusFirst(evt)
4237
}
4338
},
39+
stop(evt) {
40+
evt.preventDefault()
41+
evt.stopPropagation()
42+
},
4443
onKeydown(evt) {
4544
if (!this.keyNav) {
45+
/* istanbul ignore next: should never happen */
4646
return
4747
}
4848
const key = evt.keyCode
4949
const shift = evt.shiftKey
5050
if (key === KeyCodes.UP || key === KeyCodes.LEFT) {
51-
evt.preventDefault()
52-
evt.stopPropagation()
53-
if (shift) {
54-
this.focusFirst(evt)
55-
} else {
56-
this.focusNext(evt, true)
57-
}
51+
this.stop(evt)
52+
shift ? this.focusFirst(evt) : this.focusPrev(evt)
5853
} else if (key === KeyCodes.DOWN || key === KeyCodes.RIGHT) {
59-
evt.preventDefault()
60-
evt.stopPropagation()
61-
if (shift) {
62-
this.focusLast(evt)
63-
} else {
64-
this.focusNext(evt, false)
65-
}
54+
this.stop(evt)
55+
shift ? this.focusLast(evt) : this.focusNext(evt)
6656
}
6757
},
6858
setItemFocus(item) {
69-
this.$nextTick(() => {
70-
item.focus()
71-
})
59+
item && item.focus && item.focus()
7260
},
73-
focusNext(evt, prev) {
61+
focusFirst(evt) {
7462
const items = this.getItems()
75-
if (items.length < 1) {
76-
return
77-
}
78-
let index = items.indexOf(evt.target)
79-
if (prev && index > 0) {
80-
index--
81-
} else if (!prev && index < items.length - 1) {
82-
index++
83-
}
84-
if (index < 0) {
85-
index = 0
63+
this.setItemFocus(items[0])
64+
},
65+
focusPrev(evt) {
66+
let items = this.getItems()
67+
const index = items.indexOf(evt.target)
68+
if (index > -1) {
69+
items = items.slice(0, index).reverse()
70+
this.setItemFocus(items[0])
8671
}
87-
this.setItemFocus(items[index])
8872
},
89-
focusFirst(evt) {
90-
const items = this.getItems()
91-
if (items.length > 0) {
73+
focusNext(evt) {
74+
let items = this.getItems()
75+
const index = items.indexOf(evt.target)
76+
if (index > -1) {
77+
items = items.slice(index + 1)
9278
this.setItemFocus(items[0])
9379
}
9480
},
9581
focusLast(evt) {
96-
const items = this.getItems()
97-
if (items.length > 0) {
98-
this.setItemFocus([items.length - 1])
99-
}
82+
const items = this.getItems().reverse()
83+
this.setItemFocus(items[0])
10084
},
10185
getItems() {
10286
let items = selectAll(ITEM_SELECTOR, this.$el)
@@ -111,15 +95,18 @@ export default {
11195
return h(
11296
'div',
11397
{
114-
class: this.classObject,
98+
staticClass: 'btn-toolbar',
99+
class: { 'justify-content-between': this.justify },
115100
attrs: {
116101
role: 'toolbar',
117102
tabindex: this.keyNav ? '0' : null
118103
},
119-
on: {
120-
focusin: this.onFocusin,
121-
keydown: this.onKeydown
122-
}
104+
on: this.keyNav
105+
? {
106+
focusin: this.onFocusin,
107+
keydown: this.onKeydown
108+
}
109+
: {}
123110
},
124111
[this.$slots.default]
125112
)
Lines changed: 184 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,195 @@
1-
import { loadFixture, testVM } from '../../../tests/utils'
1+
import ButtonToolbar from './button-toolbar'
2+
import ButtonGroup from '../button-group/button-group'
3+
import Button from '../button/button'
4+
import { mount } from '@vue/test-utils'
5+
import Vue from 'vue'
26

37
describe('button-toolbar', () => {
4-
beforeEach(loadFixture(__dirname, 'button-toolbar'))
5-
testVM()
8+
it('toolbar root should be "div"', async () => {
9+
const wrapper = mount(ButtonToolbar, {})
10+
expect(wrapper.is('div')).toBe(true)
11+
wrapper.destroy()
12+
})
613

714
it('toolbar should contain base class', async () => {
8-
const {
9-
app: { $refs }
10-
} = window
15+
const wrapper = mount(ButtonToolbar, {})
16+
expect(wrapper.classes()).toContain('btn-toolbar')
17+
wrapper.destroy()
18+
})
1119

12-
expect($refs.toolbar).toHaveClass('btn-toolbar')
20+
it('toolbar should not have class "justify-content-between"', async () => {
21+
const wrapper = mount(ButtonToolbar, {})
22+
expect(wrapper.classes()).not.toContain('justify-content-between')
23+
wrapper.destroy()
1324
})
1425

1526
it('toolbar should have role', async () => {
16-
const {
17-
app: { $refs }
18-
} = window
27+
const wrapper = mount(ButtonToolbar, {})
28+
expect(wrapper.attributes('role')).toBe('toolbar')
29+
wrapper.destroy()
30+
})
31+
32+
it('toolbar should not have tabindex by default', async () => {
33+
const wrapper = mount(ButtonToolbar, {})
34+
expect(wrapper.attributes('tabindex')).not.toBeDefined()
35+
wrapper.destroy()
36+
})
37+
38+
it('toolbar should have class "justify-content-between" when justify set', async () => {
39+
const wrapper = mount(ButtonToolbar, {
40+
propsData: {
41+
justify: true
42+
}
43+
})
44+
expect(wrapper.classes()).toContain('justify-content-between')
45+
expect(wrapper.classes()).toContain('btn-toolbar')
46+
wrapper.destroy()
47+
})
48+
49+
it('toolbar should have tabindex when key-nav set', async () => {
50+
const wrapper = mount(ButtonToolbar, {
51+
propsData: {
52+
keyNav: true
53+
}
54+
})
55+
expect(wrapper.attributes('tabindex')).toBeDefined()
56+
expect(wrapper.attributes('tabindex')).toBe('0')
57+
expect(wrapper.element.tabIndex).toBe(0)
58+
wrapper.destroy()
59+
})
60+
61+
// These tests are wrapped in a new describe to limit the scope of the getBCR Mock
62+
describe('keyboard navigation', () => {
63+
const origGetBCR = Element.prototype.getBoundingClientRect
64+
65+
beforeEach(() => {
66+
// Mock getBCR so that the isVisible(el) test returns true
67+
// In our test below, all pagination buttons would normally be visible
68+
Element.prototype.getBoundingClientRect = jest.fn(() => {
69+
return {
70+
width: 24,
71+
height: 24,
72+
top: 0,
73+
left: 0,
74+
bottom: 0,
75+
right: 0
76+
}
77+
})
78+
})
79+
80+
afterEach(() => {
81+
// Restore prototype
82+
Element.prototype.getBoundingClientRect = origGetBCR
83+
})
84+
85+
// Test App for keynav
86+
const App = Vue.extend({
87+
render(h) {
88+
return h(ButtonToolbar, { props: { keyNav: true } }, [
89+
h(ButtonGroup, {}, [h(Button, {}, 'a'), h(Button, {}, 'b')]),
90+
h(ButtonGroup, {}, [h(Button, { props: { disabled: true } }, 'c'), h(Button, {}, 'd')]),
91+
h(ButtonGroup, {}, [h(Button, {}, 'e'), h(Button, {}, 'f')])
92+
])
93+
}
94+
})
95+
96+
it('has correct structure', async () => {
97+
const wrapper = mount(App, {
98+
attachToDocument: true
99+
})
100+
101+
await wrapper.vm.$nextTick()
102+
103+
expect(wrapper.is('div.btn-toolbar')).toBe(true)
104+
expect(wrapper.attributes('tabindex')).toBe('0')
105+
106+
const $groups = wrapper.findAll('.btn-group')
107+
expect($groups).toBeDefined()
108+
expect($groups.length).toBe(3)
109+
expect($groups.is(ButtonGroup)).toBe(true)
110+
111+
const $btns = wrapper.findAll('button')
112+
expect($btns).toBeDefined()
113+
expect($btns.length).toBe(6)
114+
expect($btns.is(Button)).toBe(true)
115+
expect($btns.at(0).is('button[tabindex="-1"')).toBe(true)
116+
expect($btns.at(1).is('button[tabindex="-1"')).toBe(true)
117+
expect($btns.at(2).is('button[tabindex="-1"')).toBe(false) // disabled button
118+
expect($btns.at(3).is('button[tabindex="-1"')).toBe(true)
119+
expect($btns.at(4).is('button[tabindex="-1"')).toBe(true)
120+
expect($btns.at(5).is('button[tabindex="-1"')).toBe(true)
121+
122+
wrapper.destroy()
123+
})
124+
125+
it('focuses first button when tabbed into', async () => {
126+
const wrapper = mount(App, {
127+
attachToDocument: true
128+
})
129+
130+
await wrapper.vm.$nextTick()
131+
132+
expect(wrapper.is('div.btn-toolbar')).toBe(true)
133+
expect(wrapper.attributes('tabindex')).toBe('0')
134+
135+
const $btns = wrapper.findAll('button')
136+
expect($btns).toBeDefined()
137+
expect($btns.length).toBe(6)
138+
139+
expect(document.activeElement).not.toBe(wrapper.element)
140+
expect(document.activeElement).not.toBe($btns.at(0).element)
141+
142+
wrapper.trigger('focusin')
143+
await wrapper.vm.$nextTick()
144+
expect(document.activeElement).toBe($btns.at(0).element)
145+
146+
wrapper.destroy()
147+
})
148+
149+
it('keyboard navigation works', async () => {
150+
const wrapper = mount(App, {
151+
attachToDocument: true
152+
})
153+
154+
await wrapper.vm.$nextTick()
155+
156+
expect(wrapper.is('div.btn-toolbar')).toBe(true)
157+
expect(wrapper.attributes('tabindex')).toBe('0')
158+
159+
const $btns = wrapper.findAll('button')
160+
expect($btns).toBeDefined()
161+
expect($btns.length).toBe(6)
162+
163+
// Focus first button
164+
$btns.at(0).element.focus()
165+
expect(document.activeElement).toBe($btns.at(0).element)
166+
167+
// Cursor right
168+
$btns.at(0).trigger('keydown.right')
169+
await wrapper.vm.$nextTick()
170+
expect(document.activeElement).toBe($btns.at(1).element)
171+
172+
// Cursor right (skips disabled button)
173+
$btns.at(1).trigger('keydown.right')
174+
await wrapper.vm.$nextTick()
175+
expect(document.activeElement).toBe($btns.at(3).element)
176+
177+
// Cursor shift-right (focuses last button)
178+
$btns.at(1).trigger('keydown.right', { shiftKey: true })
179+
await wrapper.vm.$nextTick()
180+
expect(document.activeElement).toBe($btns.at(5).element)
181+
182+
// Cursor left
183+
$btns.at(5).trigger('keydown.left')
184+
await wrapper.vm.$nextTick()
185+
expect(document.activeElement).toBe($btns.at(4).element)
186+
187+
// Cursor shift left (focuses first button)
188+
$btns.at(5).trigger('keydown.left', { shiftKey: true })
189+
await wrapper.vm.$nextTick()
190+
expect(document.activeElement).toBe($btns.at(0).element)
19191

20-
expect($refs.toolbar.$el.getAttribute('role')).toBe('toolbar')
192+
wrapper.destroy()
193+
})
21194
})
22195
})

src/components/button-toolbar/fixtures/button-toolbar.html

Lines changed: 0 additions & 17 deletions
This file was deleted.

src/components/button-toolbar/fixtures/button-toolbar.js

Lines changed: 0 additions & 3 deletions
This file was deleted.

src/components/carousel/carousel-slide.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@ export default {
114114
on: noDrag
115115
? {
116116
dragstart: e => {
117+
/* istanbul ignore next: difficult to test in JSDOM */
117118
e.preventDefault()
118119
}
119120
}

0 commit comments

Comments
 (0)