import { defineComponent, nextTick, ref } from 'vue' import { mount } from '@vue/test-utils' import { afterEach, describe, expect, test, vi } from 'vitest' import { debugWarn } from '@element-plus/utils' import Input from '../../input/src/input.vue' import Collapse from '../src/collapse.vue' import CollapseItem from '../src/collapse-item.vue' import type { VueWrapper } from '@vue/test-utils' import type { CollapseItemInstance } from '../src/instance' const AXIOM = 'Rem is the best girl' vi.mock('@element-plus/utils/error', () => ({ debugWarn: vi.fn(), })) describe('Collapse.vue', () => { afterEach(() => { vi.clearAllMocks() }) test('create', async () => { const wrapper = mount( defineComponent({ data() { return { activeNames: ['1'] as string[], } }, render() { return (
111
222
333
444
) }, }) ) const vm = wrapper.vm const collapseWrapper = wrapper.findComponent(Collapse) const collapseItemWrappers = collapseWrapper.findAllComponents( CollapseItem ) as VueWrapper[] const collapseItemHeaderEls = vm.$el.querySelectorAll( '.el-collapse-item__header' ) expect(collapseItemWrappers[0].vm.isActive).toBe(true) collapseItemHeaderEls[2].click() await nextTick() expect(collapseItemWrappers[0].vm.isActive).toBe(true) expect(collapseItemWrappers[2].vm.isActive).toBe(true) collapseItemHeaderEls[0].click() await nextTick() expect(collapseItemWrappers[0].vm.isActive).toBe(false) }) test('accordion', async () => { const wrapper = mount( defineComponent({ data() { return { activeNames: ['1'], } }, render() { return (
111
222
333
444
) }, }) ) const vm = wrapper.vm const collapseWrapper = wrapper.findComponent(Collapse) const collapseItemWrappers = collapseWrapper.findAllComponents( CollapseItem ) as VueWrapper[] const collapseItemHeaderEls = vm.$el.querySelectorAll( '.el-collapse-item__header' ) expect(collapseItemWrappers[0].vm.isActive).toBe(true) collapseItemHeaderEls[2].click() await nextTick() expect(collapseItemWrappers[0].vm.isActive).toBe(false) expect(collapseItemWrappers[2].vm.isActive).toBe(true) collapseItemHeaderEls[0].click() await nextTick() expect(collapseItemWrappers[0].vm.isActive).toBe(true) expect(collapseItemWrappers[2].vm.isActive).toBe(false) }) test('event:change', async () => { const onChange = vi.fn() const wrapper = mount( defineComponent({ data() { return { activeNames: ['1'], } }, render() { return (
111
222
333
444
) }, }) ) const vm = wrapper.vm const collapseWrapper = wrapper.findComponent(Collapse) const collapseItemWrappers = collapseWrapper.findAllComponents( CollapseItem ) as VueWrapper[] const collapseItemHeaderEls = vm.$el.querySelectorAll( '.el-collapse-item__header' ) expect(collapseItemWrappers[0].vm.isActive).toBe(true) expect(vm.activeNames).toEqual(['1']) expect(onChange).not.toHaveBeenCalled() collapseItemHeaderEls[2].click() await nextTick() expect(onChange).toHaveBeenCalledTimes(1) expect(collapseItemWrappers[0].vm.isActive).toBe(true) expect(collapseItemWrappers[2].vm.isActive).toBe(true) expect(vm.activeNames).toEqual(['1', '3']) collapseItemHeaderEls[0].click() await nextTick() expect(onChange).toHaveBeenCalledTimes(2) expect(collapseItemWrappers[0].vm.isActive).toBe(false) expect(vm.activeNames).toEqual(['3']) }) test('deep watch modelValue', async () => { const wrapper = mount( defineComponent({ data() { return { activeNames: ['1'], } }, mounted() { this.activeNames.push('2') }, render() { return (
111
222
333
444
) }, }) ) await nextTick() const collapseWrapper = wrapper.findComponent(Collapse) const collapseItemWrappers = collapseWrapper.findAllComponents( CollapseItem ) as VueWrapper[] expect(collapseItemWrappers[0].vm.isActive).toBe(true) expect(collapseItemWrappers[1].vm.isActive).toBe(true) }) test('title slot', async () => { const wrapper = mount({ render() { return ( { return (
{AXIOM}
) }, }} >
) }, }) expect(wrapper.find('.title-wrapper').text()).toBe(AXIOM) await wrapper.find('.el-collapse-item__header').trigger('click') expect(wrapper.find('.title-wrapper').classes()).toContain('is-active') }) test('beforeCollapse function return promise', async () => { const activeNames = ref([]) const asyncResult = ref('error') const beforeCollapse = () => { return new Promise((resolve, reject) => { setTimeout(() => { return asyncResult.value == 'success' ? resolve(true) : reject(new Error('Error')) }, 1000) }) } const wrapper = mount(() => (
111
222
333
444
)) const vm = wrapper.vm const collapseWrapper = wrapper.findComponent(Collapse) const collapseItemWrappers = collapseWrapper.findAllComponents( CollapseItem ) as VueWrapper[] const collapseItemHeaderEls = vm.$el.querySelectorAll( '.el-collapse-item__header' ) vi.useFakeTimers() collapseItemHeaderEls[0].click() vi.runAllTimers() await nextTick() expect(collapseItemWrappers[0].vm.isActive).toBe(false) expect(debugWarn).toHaveBeenCalledTimes(0) asyncResult.value = 'success' collapseItemHeaderEls[0].click() vi.runAllTimers() await nextTick() expect(collapseItemWrappers[0].vm.isActive).toBe(true) expect(debugWarn).toHaveBeenCalledTimes(1) collapseItemHeaderEls[1].click() vi.runAllTimers() await nextTick() expect(collapseItemWrappers[0].vm.isActive).toBe(true) expect(collapseItemWrappers[1].vm.isActive).toBe(true) expect(debugWarn).toHaveBeenCalledTimes(1) }) test('beforeCollapse function return boolean', async () => { const activeNames = ref([]) const result = ref(false) const beforeCollapse = () => { return result.value } const wrapper = mount(() => (
111
222
333
444
)) const vm = wrapper.vm const collapseWrapper = wrapper.findComponent(Collapse) const collapseItemWrappers = collapseWrapper.findAllComponents( CollapseItem ) as VueWrapper[] const collapseItemHeaderEls = vm.$el.querySelectorAll( '.el-collapse-item__header' ) collapseItemHeaderEls[0].click() await nextTick() expect(collapseItemWrappers[0].vm.isActive).toBe(false) result.value = true collapseItemHeaderEls[0].click() await nextTick() expect(collapseItemWrappers[0].vm.isActive).toBe(true) collapseItemHeaderEls[1].click() await nextTick() expect(collapseItemWrappers[0].vm.isActive).toBe(true) expect(collapseItemWrappers[1].vm.isActive).toBe(true) }) describe('Nested Input Interaction', () => { const createWrapper = (withInput: boolean = false) => { return mount( defineComponent({ data: () => ({ activeNames: ['1'], inputText: '', }), render() { return ( (
{withInput ? ( ) : ( 'title1' )}
), }} >
111
222
) }, }) ) } test('should not toggle collapse when clicking on input', async () => { const wrapper = createWrapper(true) const input = wrapper.find('[data-testid="test-input"]') const header = wrapper.find('.el-collapse-item__header') await input.trigger('click') await nextTick() const collapseItem = wrapper.findComponent(CollapseItem) expect(collapseItem.vm.isActive).toBe(true) await header.trigger('click') await nextTick() expect(collapseItem.vm.isActive).toBe(false) }) test('should not toggle collapse when pressing enter on input', async () => { const wrapper = createWrapper(true) const input = wrapper.find('[data-testid="test-input"]') const header = wrapper.find('.el-collapse-item__header') await input.trigger('keydown.enter') await nextTick() const collapseItem = wrapper.findComponent(CollapseItem) expect(collapseItem.vm.isActive).toBe(true) await header.trigger('keydown.enter') await nextTick() expect(collapseItem.vm.isActive).toBe(false) }) test('should not toggle collapse when pressing space on input', async () => { const wrapper = createWrapper(true) const input = wrapper.find('[data-testid="test-input"]') const header = wrapper.find('.el-collapse-item__header') await input.trigger('keydown.space') await nextTick() const collapseItem = wrapper.findComponent(CollapseItem) expect(collapseItem.vm.isActive).toBe(true) await header.trigger('keydown.space') await nextTick() expect(collapseItem.vm.isActive).toBe(false) }) }) describe('Accessibility', () => { test('should have appropriate ARIA attributes', async () => { const wrapper = mount({ data() { return { activeNames: ['1'], } }, render() { return (
111
222
333
444
) }, }) const collapseWrapper = wrapper.findComponent(Collapse) const collapseItemWrappers = collapseWrapper.findAllComponents( CollapseItem ) as VueWrapper[] collapseItemWrappers.forEach((item, index) => { const header = item.find('.el-collapse-item__header') const content = item.find('.el-collapse-item__wrap') const isDisabled = item.props('disabled') expect(header.attributes('role')).toBe('button') expect(header.attributes('aria-controls')).toBe( content.attributes('id') ) expect(header.attributes('tabindex')).toBe(isDisabled ? undefined : '0') expect(header.attributes('aria-disabled')).toBe( isDisabled ? 'true' : 'false' ) expect(header.attributes('aria-expanded')).toBe( collapseItemWrappers[index].vm.isActive?.toString() ) expect(content.attributes('aria-labelledby')).toBe( header.attributes('id') ) expect(content.attributes('aria-hidden')).toBe( (!collapseItemWrappers[index].vm.isActive).toString() ) }) }) }) })