Skip to content

Commit 59cca83

Browse files
chore(tooltip, popover): add tests for modal close event (#5104)
* chore(tooltip, popover): add tests for modal close event * Update tooltip.spec.js * Update bv-tooltip.js * Update tooltip.spec.js * lint * Update tooltip.spec.js Co-authored-by: Jacob Müller <jacob.mueller.elz@gmail.com>
1 parent 27da76c commit 59cca83

File tree

2 files changed

+161
-9
lines changed

2 files changed

+161
-9
lines changed

src/components/tooltip/helpers/bv-tooltip.js

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -391,12 +391,10 @@ export const BVTooltip = /*#__PURE__*/ Vue.extend({
391391
const showEvt = this.buildEvent('show', { cancelable: true })
392392
this.emitEvent(showEvt)
393393
// Don't show if event cancelled
394-
/* istanbul ignore next: ignore for now */
394+
/* istanbul ignore if */
395395
if (showEvt.defaultPrevented) {
396396
// Destroy the template (if for some reason it was created)
397-
/* istanbul ignore next */
398397
this.destroyTemplate()
399-
/* istanbul ignore next */
400398
return
401399
}
402400
// Fix the title attribute on target
@@ -409,21 +407,19 @@ export const BVTooltip = /*#__PURE__*/ Vue.extend({
409407
hide(force = false) {
410408
// Hide the tooltip
411409
const tip = this.getTemplateElement()
410+
/* istanbul ignore if */
412411
if (!tip || !this.localShow) {
413-
/* istanbul ignore next */
414412
this.restoreTitle()
415-
/* istanbul ignore next */
416413
return
417414
}
418415

419416
// Emit cancelable BvEvent 'hide'
420417
// We disable cancelling if `force` is true
421418
const hideEvt = this.buildEvent('hide', { cancelable: !force })
422419
this.emitEvent(hideEvt)
423-
/* istanbul ignore next: ignore for now */
420+
/* istanbul ignore if: ignore for now */
424421
if (hideEvt.defaultPrevented) {
425422
// Don't hide if event cancelled
426-
/* istanbul ignore next */
427423
return
428424
}
429425

src/components/tooltip/tooltip.spec.js

Lines changed: 158 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import { BTooltip } from './tooltip'
44

55
const localVue = new CreateLocalVue()
66

7+
const MODAL_CLOSE_EVENT = 'bv::modal::hidden'
8+
79
// Our test application definition
810
const appDef = {
911
props: [
@@ -17,7 +19,8 @@ const appDef = {
1719
'btnDisabled',
1820
'variant',
1921
'customClass',
20-
'delay'
22+
'delay',
23+
'isModal'
2124
],
2225
render(h) {
2326
const tipProps = {
@@ -32,7 +35,12 @@ const appDef = {
3235
customClass: this.customClass,
3336
delay: this.delay
3437
}
35-
return h('article', { attrs: { id: 'wrapper' } }, [
38+
const wrapperData = {
39+
attrs: { id: 'wrapper' },
40+
// Class to simulate being in a modal
41+
class: { 'modal-content': !!this.isModal }
42+
}
43+
return h('article', wrapperData, [
3644
h(
3745
'button',
3846
{
@@ -108,6 +116,7 @@ describe('b-tooltip', () => {
108116
expect(wrapper.is('article')).toBe(true)
109117
expect(wrapper.attributes('id')).toBeDefined()
110118
expect(wrapper.attributes('id')).toEqual('wrapper')
119+
expect(wrapper.classes()).not.toContain('modal-content')
111120

112121
// The trigger button
113122
const $button = wrapper.find('button')
@@ -954,6 +963,153 @@ describe('b-tooltip', () => {
954963
wrapper.destroy()
955964
})
956965

966+
it('does not close on $root modal hidden event by default', async () => {
967+
jest.useFakeTimers()
968+
const App = localVue.extend(appDef)
969+
const wrapper = mount(App, {
970+
attachToDocument: true,
971+
localVue: localVue,
972+
propsData: {
973+
triggers: 'click',
974+
show: true,
975+
disabled: false,
976+
titleAttr: 'ignored'
977+
},
978+
slots: {
979+
default: 'title'
980+
}
981+
})
982+
983+
expect(wrapper.isVueInstance()).toBe(true)
984+
await waitNT(wrapper.vm)
985+
await waitRAF()
986+
await waitNT(wrapper.vm)
987+
await waitRAF()
988+
jest.runOnlyPendingTimers()
989+
await waitNT(wrapper.vm)
990+
await waitRAF()
991+
992+
expect(wrapper.is('article')).toBe(true)
993+
expect(wrapper.attributes('id')).toBeDefined()
994+
expect(wrapper.attributes('id')).toEqual('wrapper')
995+
expect(wrapper.classes()).not.toContain('modal-content')
996+
997+
// The trigger button
998+
const $button = wrapper.find('button')
999+
expect($button.exists()).toBe(true)
1000+
expect($button.attributes('id')).toBeDefined()
1001+
expect($button.attributes('id')).toEqual('foo')
1002+
expect($button.attributes('title')).toBeDefined()
1003+
expect($button.attributes('title')).toEqual('')
1004+
expect($button.attributes('data-original-title')).toBeDefined()
1005+
expect($button.attributes('data-original-title')).toEqual('ignored')
1006+
expect($button.attributes('aria-describedby')).toBeDefined()
1007+
// ID of the tooltip that will be in the body
1008+
const adb = $button.attributes('aria-describedby')
1009+
1010+
// b-tooltip wrapper
1011+
const $tipHolder = wrapper.find(BTooltip)
1012+
expect($tipHolder.exists()).toBe(true)
1013+
1014+
// Find the tooltip element in the document
1015+
const tip = document.getElementById(adb)
1016+
expect(tip).not.toBe(null)
1017+
expect(tip).toBeInstanceOf(HTMLElement)
1018+
expect(tip.tagName).toEqual('DIV')
1019+
expect(tip.classList.contains('tooltip')).toBe(true)
1020+
1021+
// Tooltip should ignore when ID is not its own
1022+
wrapper.vm.$root.$emit(MODAL_CLOSE_EVENT, 'some-modal')
1023+
await waitNT(wrapper.vm)
1024+
await waitRAF()
1025+
await waitNT(wrapper.vm)
1026+
await waitRAF()
1027+
jest.runOnlyPendingTimers()
1028+
await waitNT(wrapper.vm)
1029+
await waitRAF()
1030+
1031+
expect($button.attributes('aria-describedby')).toBeDefined()
1032+
1033+
// Tooltip element should still be in the document
1034+
expect(document.body.contains(tip)).toBe(true)
1035+
expect(document.getElementById(adb)).not.toBe(null)
1036+
1037+
wrapper.destroy()
1038+
})
1039+
1040+
it('closes on $root modal hidden event when inside a modal', async () => {
1041+
jest.useFakeTimers()
1042+
const App = localVue.extend(appDef)
1043+
const wrapper = mount(App, {
1044+
attachToDocument: true,
1045+
localVue: localVue,
1046+
propsData: {
1047+
triggers: 'click',
1048+
show: true,
1049+
disabled: false,
1050+
titleAttr: 'ignored',
1051+
isModal: true
1052+
},
1053+
slots: {
1054+
default: 'title'
1055+
}
1056+
})
1057+
1058+
expect(wrapper.isVueInstance()).toBe(true)
1059+
await waitNT(wrapper.vm)
1060+
await waitRAF()
1061+
await waitNT(wrapper.vm)
1062+
await waitRAF()
1063+
jest.runOnlyPendingTimers()
1064+
await waitNT(wrapper.vm)
1065+
await waitRAF()
1066+
1067+
expect(wrapper.is('article')).toBe(true)
1068+
expect(wrapper.attributes('id')).toBeDefined()
1069+
expect(wrapper.attributes('id')).toEqual('wrapper')
1070+
expect(wrapper.classes()).toContain('modal-content')
1071+
1072+
// The trigger button
1073+
const $button = wrapper.find('button')
1074+
expect($button.exists()).toBe(true)
1075+
expect($button.attributes('id')).toBeDefined()
1076+
expect($button.attributes('id')).toEqual('foo')
1077+
expect($button.attributes('title')).toBeDefined()
1078+
expect($button.attributes('title')).toEqual('')
1079+
expect($button.attributes('data-original-title')).toBeDefined()
1080+
expect($button.attributes('data-original-title')).toEqual('ignored')
1081+
expect($button.attributes('aria-describedby')).toBeDefined()
1082+
// ID of the tooltip that will be in the body
1083+
const adb = $button.attributes('aria-describedby')
1084+
1085+
// b-tooltip wrapper
1086+
const $tipHolder = wrapper.find(BTooltip)
1087+
expect($tipHolder.exists()).toBe(true)
1088+
1089+
// Find the tooltip element in the document
1090+
const tip = document.getElementById(adb)
1091+
expect(tip).not.toBe(null)
1092+
expect(tip).toBeInstanceOf(HTMLElement)
1093+
expect(tip.tagName).toEqual('DIV')
1094+
expect(tip.classList.contains('tooltip')).toBe(true)
1095+
1096+
// Tooltip should ignore when ID is not its own
1097+
wrapper.vm.$root.$emit(MODAL_CLOSE_EVENT, 'some-modal')
1098+
await waitNT(wrapper.vm)
1099+
await waitRAF()
1100+
await waitNT(wrapper.vm)
1101+
await waitRAF()
1102+
jest.runOnlyPendingTimers()
1103+
await waitNT(wrapper.vm)
1104+
await waitRAF()
1105+
1106+
// Tooltip element should not be in the document
1107+
expect(document.body.contains(tip)).toBe(false)
1108+
expect(document.getElementById(adb)).toBe(null)
1109+
1110+
wrapper.destroy()
1111+
})
1112+
9571113
it('closes when trigger element is no longer visible', async () => {
9581114
jest.useFakeTimers()
9591115
// Prevent warns from appearing in the test logs

0 commit comments

Comments
 (0)