element-plus/packages/popper/__tests__/popper.spec.ts

314 lines
8.6 KiB
TypeScript
Raw Normal View History

2020-08-18 00:25:10 +08:00
import { mount } from '@vue/test-utils'
import * as Vue from 'vue'
import * as popperExports from '@popperjs/core'
import ElPopper from '../src/index.vue'
import type { VueWrapper } from '@vue/test-utils'
type UnKnownProps = Record<string, unknown>
2020-08-18 00:25:10 +08:00
jest.mock('lodash')
2020-08-18 00:25:10 +08:00
2020-08-18 18:02:28 +08:00
jest.useFakeTimers()
const { h, nextTick } = Vue
const AXIOM = 'Rem is the best girl'
2020-08-18 18:02:28 +08:00
const selector = '[role="tooltip"]'
const TEST_TRIGGER = 'test-trigger'
const MOUSE_ENTER_EVENT = 'mouseenter'
const MOUSE_LEAVE_EVENT = 'mouseleave'
const CLICK_EVENT = 'click'
const FOCUS_EVENT = 'focus'
const BLUR_EVENT = 'blur'
2020-08-18 18:02:28 +08:00
const DISPLAY_NONE = 'display: none'
2020-08-18 00:25:10 +08:00
2020-08-18 18:02:28 +08:00
const Wrapped = (props: UnKnownProps, { slots }) => h('div', h(ElPopper, props, slots))
const Transition = (_: UnKnownProps, { attrs, slots }) => h('div', attrs, slots)
2020-08-18 00:25:10 +08:00
Transition.displayName = 'Transition'
// eslint-disable-next-line
const _mount = (props: Record<string, unknown> = {}, slots = {}): VueWrapper<any> =>
mount(Wrapped, {
props,
2020-08-18 18:02:28 +08:00
slots: {
trigger: () => h('div', {
class: TEST_TRIGGER,
}),
...slots,
},
2020-08-18 00:25:10 +08:00
})
const popperMock = jest.spyOn(popperExports, 'createPopper').mockImplementation(() => ({
update: jest.fn(),
forceUpdate: jest.fn(),
setOptions: jest.fn(),
destroy: jest.fn(),
state: null,
}))
2020-08-18 00:25:10 +08:00
describe('Popper.vue', () => {
// eslint-disable-next-line
// eslint-disable-next-line
2020-08-18 00:25:10 +08:00
const oldTransition = Vue.Transition
beforeAll(() => {
// eslint-disable-next-line
;(Vue as any).Transition = Transition
})
2020-08-18 00:25:10 +08:00
afterAll(() => {
popperMock.mockReset()
// eslint-disable-next-line
;(Vue as any).Transition = oldTransition
})
beforeEach(() => {
popperMock.mockClear()
})
test('render test', () => {
let wrapper = _mount({
appendToBody: false,
}, {
default: () => AXIOM,
})
expect(wrapper.text()).toEqual(AXIOM)
wrapper = _mount({
appendToBody: false,
content: AXIOM,
})
expect(wrapper.text()).toEqual(AXIOM)
})
test('append to body', () => {
let wrapper = _mount()
expect(wrapper.find(selector).exists()).toBe(false)
2020-08-25 22:25:46 +08:00
/**
* Current layout of `ElPopper`
* --> Teleport
* --> mask
* --> transition
* --> popper
*/
2020-08-18 00:25:10 +08:00
wrapper = _mount({
appendToBody: false,
})
expect(wrapper.find('[role="tooltip"]').exists()).toBe(true)
})
test('should show popper when mouse entered and hide when popper left', async () => {
const wrapper = _mount({
appendToBody: false,
})
2020-08-18 18:02:28 +08:00
expect(wrapper.find(selector).attributes('style')).toContain(DISPLAY_NONE)
await wrapper.find(selector).trigger(MOUSE_ENTER_EVENT)
2020-08-18 00:25:10 +08:00
2020-08-18 18:02:28 +08:00
expect(wrapper.find(selector).attributes('style')).not.toContain(DISPLAY_NONE)
2020-08-18 00:25:10 +08:00
2020-08-18 18:02:28 +08:00
await wrapper.find(selector).trigger(MOUSE_LEAVE_EVENT)
2020-08-18 00:25:10 +08:00
2020-08-18 18:02:28 +08:00
expect(wrapper.find(selector).attributes('style')).toContain(DISPLAY_NONE)
2020-08-18 00:25:10 +08:00
})
test('should be able to manual open', async () => {
const wrapper = _mount({
manualMode: true,
appendToBody: false,
value: false,
})
2020-08-18 18:02:28 +08:00
expect(wrapper.find(selector).attributes('style')).toContain(DISPLAY_NONE)
await wrapper.find(selector).trigger(MOUSE_ENTER_EVENT)
2020-08-18 18:02:28 +08:00
expect(wrapper.find(selector).attributes('style')).toContain(DISPLAY_NONE)
2020-08-18 00:25:10 +08:00
await wrapper.setProps({
value: true,
})
2020-08-18 18:02:28 +08:00
expect(wrapper.find(selector).attributes('style')).not.toContain(DISPLAY_NONE)
2020-08-18 00:25:10 +08:00
})
test('should disable popper to popup', async () => {
const wrapper = _mount({
disabled: true,
appendToBody: false,
})
2020-08-18 18:02:28 +08:00
expect(wrapper.find(selector).attributes('style')).toContain(DISPLAY_NONE)
await wrapper.find(selector).trigger(MOUSE_ENTER_EVENT)
2020-08-18 00:25:10 +08:00
2020-08-18 18:02:28 +08:00
expect(wrapper.find(selector).attributes('style')).toContain(DISPLAY_NONE)
2020-08-18 00:25:10 +08:00
await wrapper.setProps({
disabled: false,
})
2020-08-18 18:02:28 +08:00
await wrapper.find(selector).trigger(MOUSE_ENTER_EVENT)
2020-08-18 18:02:28 +08:00
expect(wrapper.find(selector).attributes('style')).not.toContain(DISPLAY_NONE)
2020-08-18 00:25:10 +08:00
})
2020-08-18 18:02:28 +08:00
test('should add tab index to referrer', async () => {
2020-08-18 00:25:10 +08:00
const wrapper = _mount({
appendToBody: false,
})
2020-08-18 18:02:28 +08:00
expect(wrapper.find(`.${TEST_TRIGGER}`).attributes('tabindex')).toBe('0')
})
2020-08-18 00:25:10 +08:00
2020-08-18 18:02:28 +08:00
test('should initialize a new popper when component mounted', async () => {
_mount({
appendToBody: false,
2020-08-18 00:25:10 +08:00
})
2020-08-18 18:02:28 +08:00
expect(popperExports.createPopper).toHaveBeenCalledTimes(1)
2020-08-18 00:25:10 +08:00
})
2020-08-18 18:02:28 +08:00
test('should hide after hide after is given', async () => {
2020-08-18 00:25:10 +08:00
const wrapper = _mount({
2020-08-18 18:02:28 +08:00
hideAfter: 200,
2020-08-18 00:25:10 +08:00
appendToBody: false,
})
2020-08-18 18:02:28 +08:00
await wrapper.find(selector).trigger(MOUSE_ENTER_EVENT)
expect(wrapper.find(selector).attributes('style')).not.toContain(DISPLAY_NONE)
jest.runOnlyPendingTimers()
await nextTick()
expect(wrapper.find(selector).attributes('style')).toContain(DISPLAY_NONE)
2020-08-18 18:02:28 +08:00
})
2020-08-18 00:25:10 +08:00
2020-08-18 18:02:28 +08:00
test('should throw error when there is no trigger', () => {
const errorHandler = jest.fn()
mount(Wrapped, {
slots: {
trigger: undefined,
},
global: {
config: {
errorHandler(err: Error) {
errorHandler(err)
},
warnHandler() {
// suppress warning
},
},
},
2020-08-18 00:25:10 +08:00
})
// due to vue catches the error during rendering, and throws it asynchronously
// the only way to test this is by providing an error handler to catch it
2020-08-18 18:02:28 +08:00
expect(errorHandler).toHaveBeenCalledTimes(1)
2020-08-18 00:25:10 +08:00
})
describe('trigger', () => {
test('should work with click trigger', async () => {
const wrapper = _mount({
trigger: ['click'],
appendToBody: false,
})
await nextTick()
const trigger = wrapper.find(`.${TEST_TRIGGER}`)
const popper = wrapper.findComponent(ElPopper)
expect(popper.vm.visible).toBe(false)
// for now triggering event on element via DOMWrapper is not available so we need to apply
// old way
await trigger.trigger(CLICK_EVENT)
expect(popper.vm.visible).toBe(true)
await trigger.trigger(MOUSE_ENTER_EVENT)
expect(popper.vm.visible).toBe(true)
await trigger.trigger(FOCUS_EVENT)
expect(popper.vm.visible).toBe(true)
})
test('should work with hover trigger', async () => {
const wrapper = _mount({
trigger: ['hover'],
appendToBody: false,
})
await nextTick()
const trigger = wrapper.find(`.${TEST_TRIGGER}`)
const popper = wrapper.findComponent(ElPopper)
expect(popper.vm.visible).toBe(false)
// for now triggering event on element via DOMWrapper is not available so we need to apply
// old way
await trigger.trigger(MOUSE_ENTER_EVENT)
expect(popper.vm.visible).toBe(true)
await trigger.trigger(MOUSE_LEAVE_EVENT)
expect(popper.vm.visible).toBe(false)
await trigger.trigger(FOCUS_EVENT)
expect(popper.vm.visible).toBe(false)
await trigger.trigger(CLICK_EVENT)
expect(popper.vm.visible).toBe(false)
})
test('should work with focus trigger', async () => {
const wrapper = _mount({
trigger: [FOCUS_EVENT],
appendToBody: false,
})
await nextTick()
const trigger = wrapper.find(`.${TEST_TRIGGER}`)
const popper = wrapper.findComponent(ElPopper)
expect(popper.vm.visible).toBe(false)
// for now triggering event on element via DOMWrapper is not available so we need to apply
// old way
await trigger.trigger(FOCUS_EVENT)
expect(popper.vm.visible).toBe(true)
await trigger.trigger(BLUR_EVENT)
expect(popper.vm.visible).toBe(false)
await trigger.trigger(MOUSE_ENTER_EVENT)
expect(popper.vm.visible).toBe(false)
await trigger.trigger(CLICK_EVENT)
expect(popper.vm.visible).toBe(false)
})
test('combined trigger', async () => {
const wrapper = _mount({
trigger: [FOCUS_EVENT, CLICK_EVENT, 'hover'],
appendToBody: false,
})
await nextTick()
const trigger = wrapper.find(`.${TEST_TRIGGER}`)
const popper = wrapper.findComponent(ElPopper)
expect(popper.vm.visible).toBe(false)
// for now triggering event on element via DOMWrapper is not available so we need to apply
// old way
await trigger.trigger(CLICK_EVENT)
expect(popper.vm.visible).toBe(true)
await trigger.trigger(BLUR_EVENT)
expect(popper.vm.visible).toBe(false)
await trigger.trigger(MOUSE_ENTER_EVENT)
expect(popper.vm.visible).toBe(true)
await trigger.trigger(CLICK_EVENT)
expect(popper.vm.visible).toBe(false)
await trigger.trigger(FOCUS_EVENT)
expect(popper.vm.visible).toBe(true)
await trigger.trigger(CLICK_EVENT)
expect(popper.vm.visible).toBe(false)
})
})
2020-08-18 00:25:10 +08:00
})