From b4d16ea53fdac183c35c80fe2cf2b3c36b308194 Mon Sep 17 00:00:00 2001
From: LIUCHAO <50739490+Tsong-LC@users.noreply.github.com>
Date: Tue, 2 Aug 2022 17:54:48 +0800
Subject: [PATCH] refactor(components): [tabs] use JSX in Unit test (#9050)
* refactor(components): [tabs] use JSX in Unit test
* style(components): [tabs] use v-model
---
.../components/tabs/__tests__/tabs.test.ts | 763 ------------------
.../components/tabs/__tests__/tabs.test.tsx | 670 +++++++++++++++
2 files changed, 670 insertions(+), 763 deletions(-)
delete mode 100644 packages/components/tabs/__tests__/tabs.test.ts
create mode 100644 packages/components/tabs/__tests__/tabs.test.tsx
diff --git a/packages/components/tabs/__tests__/tabs.test.ts b/packages/components/tabs/__tests__/tabs.test.ts
deleted file mode 100644
index 511da02a0c..0000000000
--- a/packages/components/tabs/__tests__/tabs.test.ts
+++ /dev/null
@@ -1,763 +0,0 @@
-// @ts-nocheck
-import { nextTick } from 'vue'
-import { mount } from '@vue/test-utils'
-import { describe, expect, test, vi } from 'vitest'
-import { EVENT_CODE } from '@element-plus/constants'
-import Tabs from '../src/tabs'
-import TabPane from '../src/tab-pane.vue'
-import TabNav from '../src/tab-nav'
-
-describe('Tabs.vue', () => {
- test('create', async () => {
- const wrapper = mount({
- components: {
- 'el-tabs': Tabs,
- 'el-tab-pane': TabPane,
- },
- template: `
-
- A
- B
- C
- D
-
- `,
- })
-
- const tabsWrapper = wrapper.findComponent(Tabs)
- const navWrapper = wrapper.findComponent(TabNav)
- const panesWrapper = wrapper.findAllComponents(TabPane)
- await nextTick()
-
- const navItemsWrapper = navWrapper.findAll('.el-tabs__item')
-
- expect(navItemsWrapper[0].classes('is-active')).toBe(true)
- expect(panesWrapper[0].classes('el-tab-pane')).toBe(true)
- expect(panesWrapper[0].attributes('id')).toBe('pane-0')
- expect(panesWrapper[0].attributes('aria-hidden')).toEqual('false')
- expect(tabsWrapper.vm.$.exposed.currentName.value).toEqual('0')
-
- await navItemsWrapper[2].trigger('click')
- expect(navItemsWrapper[0].classes('is-active')).toBe(false)
- expect(panesWrapper[0].attributes('aria-hidden')).toEqual('true')
- expect(navItemsWrapper[2].classes('is-active')).toBe(true)
- expect(panesWrapper[2].attributes('aria-hidden')).toEqual('false')
- expect(tabsWrapper.vm.$.exposed.currentName.value).toEqual('2')
- })
-
- test('active-name', async () => {
- const wrapper = mount({
- components: {
- 'el-tabs': Tabs,
- 'el-tab-pane': TabPane,
- },
- data() {
- return {
- activeName: 'b',
- }
- },
- methods: {
- handleClick(tab) {
- this.activeName = tab.paneName
- },
- },
- template: `
-
- A
- B
- C
- D
-
- `,
- })
-
- const tabsWrapper = wrapper.findComponent(Tabs)
- const navWrapper = wrapper.findComponent(TabNav)
- const panesWrapper = wrapper.findAllComponents(TabPane)
- await nextTick()
-
- const navItemsWrapper = navWrapper.findAll('.el-tabs__item')
- expect(navItemsWrapper[1].classes('is-active')).toBe(true)
- expect(panesWrapper[1].classes('el-tab-pane')).toBe(true)
- expect(panesWrapper[1].attributes('id')).toBe('pane-b')
- expect(panesWrapper[1].attributes('aria-hidden')).toEqual('false')
- expect(tabsWrapper.vm.$.exposed.currentName.value).toEqual('b')
-
- await navItemsWrapper[2].trigger('click')
- expect(navItemsWrapper[1].classes('is-active')).toBe(false)
- expect(panesWrapper[1].attributes('aria-hidden')).toEqual('true')
- expect(navItemsWrapper[2].classes('is-active')).toBe(true)
- expect(panesWrapper[2].attributes('aria-hidden')).toEqual('false')
- expect(tabsWrapper.vm.$.exposed.currentName.value).toEqual('c')
- })
-
- test('card', async () => {
- const wrapper = mount({
- components: {
- 'el-tabs': Tabs,
- 'el-tab-pane': TabPane,
- },
- template: `
-
- A
- B
- C
- D
-
- `,
- })
-
- const tabsWrapper = wrapper.findComponent(Tabs)
- expect(tabsWrapper.classes('el-tabs--card')).toBe(true)
- })
-
- test('border card', async () => {
- const wrapper = mount({
- components: {
- 'el-tabs': Tabs,
- 'el-tab-pane': TabPane,
- },
- template: `
-
- A
- B
- C
- D
-
- `,
- })
-
- const tabsWrapper = wrapper.findComponent(Tabs)
- expect(tabsWrapper.classes('el-tabs--border-card')).toBe(true)
- })
-
- test('dynamic', async () => {
- const wrapper = mount({
- components: {
- 'el-tabs': Tabs,
- 'el-tab-pane': TabPane,
- },
- template: `
-
- Test Content
-
- `,
- data() {
- return {
- tabs: [
- {
- label: 'tab1',
- name: 'tab1',
- },
- {
- label: 'tab2',
- name: 'tab2',
- },
- {
- label: 'tab3',
- name: 'tab3',
- },
- {
- label: 'tab4',
- name: 'tab4',
- },
- ],
- }
- },
- })
-
- let navWrapper = wrapper.findComponent(TabNav)
- let panesWrapper = wrapper.findAllComponents(TabPane)
- await nextTick()
-
- let navItemsWrapper = navWrapper.findAll('.el-tabs__item')
-
- expect(navItemsWrapper.length).toEqual(4)
- expect(panesWrapper.length).toEqual(4)
-
- wrapper.vm.tabs.push({ label: 'tab5', name: 'tab5' })
-
- await nextTick()
- navWrapper = wrapper.findComponent(TabNav)
- panesWrapper = wrapper.findAllComponents(TabPane)
- navItemsWrapper = navWrapper.findAll('.el-tabs__item')
-
- expect(navItemsWrapper.length).toEqual(5)
- expect(panesWrapper.length).toEqual(5)
- })
-
- test('editable', async () => {
- const wrapper = mount({
- components: {
- 'el-tabs': Tabs,
- 'el-tab-pane': TabPane,
- },
- template: `
-
-
- {{item.content}}
-
-
- `,
- data() {
- return {
- editableTabsValue: '2',
- editableTabs: [
- {
- title: 'Tab 1',
- name: '1',
- content: 'Tab 1 content',
- },
- {
- title: 'Tab 2',
- name: '2',
- content: 'Tab 2 content',
- },
- {
- title: 'Tab 3',
- name: '3',
- content: 'Tab 3 content',
- },
- ],
- tabIndex: 3,
- }
- },
- methods: {
- handleTabsEdit(targetName, action) {
- if (action === 'add') {
- const newTabName = `${++this.tabIndex}`
- this.editableTabs.push({
- title: 'New Tab',
- name: newTabName,
- content: 'New Tab content',
- })
- this.editableTabsValue = newTabName
- }
- if (action === 'remove') {
- const tabs = this.editableTabs
- let activeName = this.editableTabsValue
- if (activeName === targetName) {
- tabs.forEach((tab, index) => {
- if (tab.name === targetName) {
- const nextTab = tabs[index + 1] || tabs[index - 1]
- if (nextTab) {
- activeName = nextTab.name
- }
- }
- })
- }
- this.editableTabsValue = activeName
- this.editableTabs = tabs.filter((tab) => tab.name !== targetName)
- }
- },
- },
- })
-
- const navWrapper = wrapper.findComponent(TabNav)
- let panesWrapper = wrapper.findAllComponents(TabPane)
- await nextTick()
-
- let navItemsWrapper = navWrapper.findAll('.el-tabs__item')
-
- expect(navItemsWrapper.length).toEqual(3)
- expect(panesWrapper.length).toEqual(3)
- expect(navItemsWrapper[1].classes('is-active')).toBe(true)
-
- // remove one tab, check panes length
- await navItemsWrapper[1].find('.is-icon-close').trigger('click')
-
- panesWrapper = wrapper.findAllComponents(TabPane)
- navItemsWrapper = navWrapper.findAll('.el-tabs__item')
-
- expect(navItemsWrapper.length).toEqual(2)
- expect(panesWrapper.length).toEqual(2)
-
- // add one tab, check panes length and current tab
- await wrapper.find('.el-tabs__new-tab').trigger('click')
-
- panesWrapper = wrapper.findAllComponents(TabPane)
- navItemsWrapper = navWrapper.findAll('.el-tabs__item')
-
- expect(navItemsWrapper.length).toEqual(3)
- expect(panesWrapper.length).toEqual(3)
- expect(navItemsWrapper[2].classes('is-active')).toBe(true)
- })
-
- test('addable & closable', async () => {
- const wrapper = mount({
- components: {
- 'el-tabs': Tabs,
- 'el-tab-pane': TabPane,
- },
- template: `
-
-
- {{item.content}}
-
-
- `,
- data() {
- return {
- editableTabsValue: '2',
- editableTabs: [
- {
- title: 'Tab 1',
- name: '1',
- content: 'Tab 1 content',
- },
- {
- title: 'Tab 2',
- name: '2',
- content: 'Tab 2 content',
- },
- ],
- tabIndex: 2,
- }
- },
- methods: {
- addTab() {
- const newTabName = `${++this.tabIndex}`
- this.editableTabs.push({
- title: 'New Tab',
- name: newTabName,
- content: 'New Tab content',
- })
- this.editableTabsValue = newTabName
- },
- removeTab(targetName) {
- const tabs = this.editableTabs
- let activeName = this.editableTabsValue
- if (activeName === targetName) {
- tabs.forEach((tab, index) => {
- if (tab.name === targetName) {
- const nextTab = tabs[index + 1] || tabs[index - 1]
- if (nextTab) {
- activeName = nextTab.name
- }
- }
- })
- }
- this.editableTabsValue = activeName
- this.editableTabs = tabs.filter((tab) => tab.name !== targetName)
- },
- },
- })
-
- const navWrapper = wrapper.findComponent(TabNav)
- await nextTick()
-
- await wrapper.find('.el-tabs__new-tab').trigger('click')
-
- let navItemsWrapper = navWrapper.findAll('.el-tabs__item')
- let panesWrapper = wrapper.findAllComponents(TabPane)
- expect(navItemsWrapper.length).toEqual(3)
- expect(panesWrapper.length).toEqual(3)
- expect(navItemsWrapper[2].classes('is-active')).toBe(true)
-
- await navItemsWrapper[2].find('.is-icon-close').trigger('click')
-
- panesWrapper = wrapper.findAllComponents(TabPane)
- navItemsWrapper = navWrapper.findAll('.el-tabs__item')
-
- expect(navItemsWrapper.length).toEqual(2)
- expect(panesWrapper.length).toEqual(2)
- })
-
- test('closable in tab-pane', async () => {
- const wrapper = mount({
- components: {
- 'el-tabs': Tabs,
- 'el-tab-pane': TabPane,
- },
- template: `
-
- A
- B
- C
- D
-
- `,
- })
-
- const navWrapper = wrapper.findComponent(TabNav)
- await nextTick()
-
- expect(navWrapper.findAll('.is-icon-close').length).toBe(2)
- })
-
- test('disabled', async () => {
- const wrapper = mount({
- components: {
- 'el-tabs': Tabs,
- 'el-tab-pane': TabPane,
- },
- template: `
-
- A
- B
- C
- D
-
- `,
- })
-
- const navWrapper = wrapper.findComponent(TabNav)
- await nextTick()
- const navItemsWrapper = navWrapper.findAll('.el-tabs__item')
- expect(navItemsWrapper[1].classes('is-active')).toBe(false)
-
- await navItemsWrapper[1].trigger('click')
- expect(navItemsWrapper[1].classes('is-active')).toBe(false)
- })
-
- test('tab-position', async () => {
- const wrapper = mount({
- components: {
- 'el-tabs': Tabs,
- 'el-tab-pane': TabPane,
- },
- template: `
-
- A
- B
- C
- D
-
- `,
- })
-
- const tabsWrapper = wrapper.findComponent(Tabs)
- await nextTick()
-
- expect(tabsWrapper.classes('el-tabs--left')).toBe(true)
- expect(tabsWrapper.find('.el-tabs__header').classes('is-left')).toBe(true)
- expect(tabsWrapper.find('.el-tabs__nav-wrap').classes('is-left')).toBe(true)
- expect(tabsWrapper.find('.el-tabs__nav').classes('is-left')).toBe(true)
- expect(tabsWrapper.find('.el-tabs__active-bar').classes('is-left')).toBe(
- true
- )
- expect(tabsWrapper.find('.el-tabs__item').classes('is-left')).toBe(true)
- })
-
- test('stretch', async () => {
- const wrapper = mount({
- components: {
- 'el-tabs': Tabs,
- 'el-tab-pane': TabPane,
- },
- template: `
-
- A
- B
- C
- D
-
- `,
- data() {
- return {
- tabPosition: 'bottom',
- }
- },
- })
-
- const tabsWrapper = wrapper.findComponent(Tabs)
- await nextTick()
-
- expect(tabsWrapper.find('.el-tabs__nav').classes('is-stretch')).toBe(true)
-
- wrapper.vm.tabPosition = 'left'
- await nextTick()
-
- expect(tabsWrapper.find('.el-tabs__nav').classes('is-stretch')).toBe(false)
- })
-
- test('tab active bar offset', async () => {
- const wrapper = mount({
- components: {
- 'el-tabs': Tabs,
- 'el-tab-pane': TabPane,
- },
- template: `
-
- A
- B
- C
- D
-
- `,
- data() {
- return {
- tabPosition: 'bottom',
- }
- },
- })
-
- const tabsWrapper = wrapper.findComponent(Tabs)
- await nextTick()
- const mockCRect = vi
- .spyOn(wrapper.find('#tab-C').element, 'getBoundingClientRect')
- .mockReturnValue({ left: 300 } as DOMRect)
- const mockComputedStyle = vi
- .spyOn(window, 'getComputedStyle')
- .mockReturnValue({ paddingLeft: '0px' } as CSSStyleDeclaration)
- await wrapper.find('#tab-C').trigger('click')
-
- await nextTick()
- expect(tabsWrapper.find('.el-tabs__active-bar').attributes().style).toMatch(
- 'translateX(300px)'
- )
-
- wrapper.vm.tabPosition = 'left'
- await nextTick()
- const mockCYRect = vi
- .spyOn(wrapper.find('#tab-C').element, 'getBoundingClientRect')
- .mockReturnValue({ top: 200 } as DOMRect)
- await wrapper.find('#tab-A').trigger('click')
- await wrapper.find('#tab-C').trigger('click')
-
- await nextTick()
- expect(tabsWrapper.find('.el-tabs__active-bar').attributes().style).toMatch(
- 'translateY(200px)'
- )
-
- mockCRect.mockRestore()
- mockCYRect.mockRestore()
- mockComputedStyle.mockRestore()
- wrapper.unmount()
- })
-
- test('horizonal-scrollable', async () => {
- // TODO: jsdom not support `clientWidth`.
- })
-
- test('vertical-scrollable', async () => {
- // TODO: jsdom not support `clientWidth`.
- })
-
- test('should work with lazy', async () => {
- const wrapper = mount({
- components: {
- 'el-tabs': Tabs,
- 'el-tab-pane': TabPane,
- },
- template: `
-
- A
- B
- C
- D
-
- `,
- data() {
- return {
- activeName: 'A',
- }
- },
- })
-
- const navWrapper = wrapper.findComponent(TabNav)
- await nextTick()
- const navItemsWrapper = navWrapper.findAll('.el-tabs__item')
-
- expect(wrapper.findAll('.el-tab-pane').length).toBe(3)
-
- await navItemsWrapper[3].trigger('click')
-
- expect(wrapper.findAll('.el-tab-pane').length).toBe(4)
- })
-
- test('before leave', async () => {
- const wrapper = mount({
- components: {
- 'el-tabs': Tabs,
- 'el-tab-pane': TabPane,
- },
- template: `
-
- A
- B
- C
- D
-
- `,
- data() {
- return {
- activeName: 'tab-B',
- }
- },
- methods: {
- beforeLeave() {
- return new window.Promise((resolve, reject) => {
- reject()
- })
- },
- },
- })
-
- const navWrapper = wrapper.findComponent(TabNav)
- const panesWrapper = wrapper.findAllComponents(TabPane)
- await nextTick()
- const navItemsWrapper = navWrapper.findAll('.el-tabs__item')
-
- expect(navItemsWrapper[1].classes('is-active')).toBe(true)
- expect(panesWrapper[1].attributes('style')).toBeFalsy()
-
- await navItemsWrapper[3].trigger('click')
-
- expect(navItemsWrapper[1].classes('is-active')).toBe(true)
- expect(panesWrapper[1].attributes('style')).toBeFalsy()
- })
-
- test('keyboard event', async () => {
- const wrapper = mount({
- components: {
- 'el-tabs': Tabs,
- 'el-tab-pane': TabPane,
- },
- template: `
-
- A
- B
- C
- D
-
- `,
- data() {
- return {
- activeName: 'second',
- }
- },
- })
-
- const vm = wrapper.vm
- await nextTick()
-
- await wrapper
- .find('#tab-second')
- .trigger('keydown', { code: EVENT_CODE.right })
- expect(vm.activeName).toEqual('third')
-
- await wrapper
- .find('#tab-third')
- .trigger('keydown', { code: EVENT_CODE.right })
- expect(vm.activeName).toEqual('fourth')
-
- await wrapper
- .find('#tab-fourth')
- .trigger('keydown', { code: EVENT_CODE.right })
- expect(vm.activeName).toEqual('second')
-
- await wrapper
- .find('#tab-second')
- .trigger('keydown', { code: EVENT_CODE.left })
- expect(vm.activeName).toEqual('fourth')
- })
-
- test('resize', async () => {
- // TODO: jsdom not support `clientWidth`.
- })
-
- test('DOM update finished calculating navOffset', async () => {
- const tabs: string[] = []
- for (let i = 0; i < 5000; i++) {
- tabs.push(i.toString())
- }
- const wrapper = mount({
- components: {
- 'el-tabs': Tabs,
- 'el-tab-pane': TabPane,
- },
- template: `
-
-
-
- `,
- data() {
- return {
- activeName: '0',
- tabs,
- }
- },
- })
-
- const tabsWrapper = wrapper.findComponent(Tabs)
- await nextTick()
-
- const mockRect = vi
- .spyOn(wrapper.find('#tab-4999').element, 'getBoundingClientRect')
- .mockReturnValue({ left: 5000 } as DOMRect)
- const mockComputedStyle = vi
- .spyOn(window, 'getComputedStyle')
- .mockReturnValue({ paddingLeft: '0px' } as CSSStyleDeclaration)
-
- await wrapper.find('#tab-4999').trigger('click')
- await nextTick()
-
- expect(tabsWrapper.find('.el-tabs__active-bar').attributes().style).toMatch(
- 'translateX(5000px)'
- )
-
- mockRect.mockRestore()
- mockComputedStyle.mockRestore()
- wrapper.unmount()
- })
-
- test('value type', async () => {
- const wrapper = mount({
- components: {
- 'el-tabs': Tabs,
- 'el-tab-pane': TabPane,
- },
- data() {
- return {
- activeName: 0,
- }
- },
- methods: {
- handleClick(tab) {
- this.activeName = tab.paneName
- },
- },
- template: `
-
- A
- B
- C
- D
-
- `,
- })
-
- const navWrapper = wrapper.findComponent(TabNav)
- await nextTick()
-
- const navItemsWrapper = navWrapper.findAll('.el-tabs__item')
- ;[1, 0, 2, 0, 3, 0, 1].forEach((val) => {
- navItemsWrapper[val].trigger('click')
- expect(wrapper.vm.activeName).toEqual(val)
- })
- })
-})
diff --git a/packages/components/tabs/__tests__/tabs.test.tsx b/packages/components/tabs/__tests__/tabs.test.tsx
new file mode 100644
index 0000000000..6f6694d0a2
--- /dev/null
+++ b/packages/components/tabs/__tests__/tabs.test.tsx
@@ -0,0 +1,670 @@
+// @ts-nocheck
+import { nextTick, ref } from 'vue'
+import { mount } from '@vue/test-utils'
+import { describe, expect, test, vi } from 'vitest'
+import { EVENT_CODE } from '@element-plus/constants'
+import Tabs from '../src/tabs'
+import TabPane from '../src/tab-pane.vue'
+import TabNav from '../src/tab-nav'
+
+describe('Tabs.vue', () => {
+ test('create', async () => {
+ const wrapper = mount(() => (
+
+ A
+ B
+
+ C
+
+ D
+
+ ))
+
+ const tabsWrapper = wrapper.findComponent(Tabs)
+ const navWrapper = wrapper.findComponent(TabNav)
+ const panesWrapper = wrapper.findAllComponents(TabPane)
+ await nextTick()
+
+ const navItemsWrapper = navWrapper.findAll('.el-tabs__item')
+
+ expect(navItemsWrapper[0].classes('is-active')).toBe(true)
+ expect(panesWrapper[0].classes('el-tab-pane')).toBe(true)
+ expect(panesWrapper[0].attributes('id')).toBe('pane-0')
+ expect(panesWrapper[0].attributes('aria-hidden')).toEqual('false')
+ expect(tabsWrapper.vm.$.exposed.currentName.value).toEqual('0')
+
+ await navItemsWrapper[2].trigger('click')
+ expect(navItemsWrapper[0].classes('is-active')).toBe(false)
+ expect(panesWrapper[0].attributes('aria-hidden')).toEqual('true')
+ expect(navItemsWrapper[2].classes('is-active')).toBe(true)
+ expect(panesWrapper[2].attributes('aria-hidden')).toEqual('false')
+ expect(tabsWrapper.vm.$.exposed.currentName.value).toEqual('2')
+ })
+
+ test('active-name', async () => {
+ const activeName = ref('b')
+ const handleClick = (tab) => {
+ activeName.value = tab.paneName
+ }
+ const wrapper = mount(() => (
+
+
+ A
+
+
+ B
+
+
+ C
+
+
+ D
+
+
+ ))
+
+ const tabsWrapper = wrapper.findComponent(Tabs)
+ const navWrapper = wrapper.findComponent(TabNav)
+ const panesWrapper = wrapper.findAllComponents(TabPane)
+ await nextTick()
+
+ const navItemsWrapper = navWrapper.findAll('.el-tabs__item')
+ expect(navItemsWrapper[1].classes('is-active')).toBe(true)
+ expect(panesWrapper[1].classes('el-tab-pane')).toBe(true)
+ expect(panesWrapper[1].attributes('id')).toBe('pane-b')
+ expect(panesWrapper[1].attributes('aria-hidden')).toEqual('false')
+ expect(tabsWrapper.vm.$.exposed.currentName.value).toEqual('b')
+
+ await navItemsWrapper[2].trigger('click')
+ expect(navItemsWrapper[1].classes('is-active')).toBe(false)
+ expect(panesWrapper[1].attributes('aria-hidden')).toEqual('true')
+ expect(navItemsWrapper[2].classes('is-active')).toBe(true)
+ expect(panesWrapper[2].attributes('aria-hidden')).toEqual('false')
+ expect(tabsWrapper.vm.$.exposed.currentName.value).toEqual('c')
+ })
+
+ test('card', async () => {
+ const wrapper = mount(() => (
+
+ A
+ B
+
+ C
+
+ D
+
+ ))
+
+ const tabsWrapper = wrapper.findComponent(Tabs)
+ expect(tabsWrapper.classes('el-tabs--card')).toBe(true)
+ })
+
+ test('border card', async () => {
+ const wrapper = mount(() => (
+
+ A
+ B
+
+ C
+
+ D
+
+ ))
+
+ const tabsWrapper = wrapper.findComponent(Tabs)
+ expect(tabsWrapper.classes('el-tabs--border-card')).toBe(true)
+ })
+
+ test('dynamic', async () => {
+ const tabs = ref([
+ {
+ label: 'tab1',
+ name: 'tab1',
+ },
+ {
+ label: 'tab2',
+ name: 'tab2',
+ },
+ {
+ label: 'tab3',
+ name: 'tab3',
+ },
+ {
+ label: 'tab4',
+ name: 'tab4',
+ },
+ ])
+ const wrapper = mount(() => (
+
+ {tabs.value.map((tab) => (
+
+ Test Content
+
+ ))}
+
+ ))
+
+ let navWrapper = wrapper.findComponent(TabNav)
+ let panesWrapper = wrapper.findAllComponents(TabPane)
+ await nextTick()
+
+ let navItemsWrapper = navWrapper.findAll('.el-tabs__item')
+
+ expect(navItemsWrapper.length).toEqual(4)
+ expect(panesWrapper.length).toEqual(4)
+
+ tabs.value.push({ label: 'tab5', name: 'tab5' })
+
+ await nextTick()
+ navWrapper = wrapper.findComponent(TabNav)
+ panesWrapper = wrapper.findAllComponents(TabPane)
+ navItemsWrapper = navWrapper.findAll('.el-tabs__item')
+
+ expect(navItemsWrapper.length).toEqual(5)
+ expect(panesWrapper.length).toEqual(5)
+ })
+
+ test('editable', async () => {
+ const editableTabsValue = ref('2')
+ const editableTabs = ref([
+ {
+ title: 'Tab 1',
+ name: '1',
+ content: 'Tab 1 content',
+ },
+ {
+ title: 'Tab 2',
+ name: '2',
+ content: 'Tab 2 content',
+ },
+ {
+ title: 'Tab 3',
+ name: '3',
+ content: 'Tab 3 content',
+ },
+ ])
+ const tabIndex = ref(3)
+ const handleTabsEdit = (targetName, action) => {
+ if (action === 'add') {
+ const newTabName = `${++tabIndex.value}`
+ editableTabs.value.push({
+ title: 'New Tab',
+ name: newTabName,
+ content: 'New Tab content',
+ })
+ editableTabsValue.value = newTabName
+ }
+ if (action === 'remove') {
+ const tabs = editableTabs.value
+ let activeName = editableTabsValue.value
+ if (activeName === targetName) {
+ tabs.forEach((tab, index) => {
+ if (tab.name === targetName) {
+ const nextTab = tabs[index + 1] || tabs[index - 1]
+ if (nextTab) {
+ activeName = nextTab.name
+ }
+ }
+ })
+ }
+ editableTabsValue.value = activeName
+ editableTabs.value = tabs.filter((tab) => tab.name !== targetName)
+ }
+ }
+ const wrapper = mount(() => (
+
+ {editableTabs.value.map((tab) => (
+
+ {tab.content}
+
+ ))}
+
+ ))
+
+ const navWrapper = wrapper.findComponent(TabNav)
+ let panesWrapper = wrapper.findAllComponents(TabPane)
+ await nextTick()
+
+ let navItemsWrapper = navWrapper.findAll('.el-tabs__item')
+
+ expect(navItemsWrapper.length).toEqual(3)
+ expect(panesWrapper.length).toEqual(3)
+ expect(navItemsWrapper[1].classes('is-active')).toBe(true)
+
+ // remove one tab, check panes length
+ await navItemsWrapper[1].find('.is-icon-close').trigger('click')
+
+ panesWrapper = wrapper.findAllComponents(TabPane)
+ navItemsWrapper = navWrapper.findAll('.el-tabs__item')
+ expect(navItemsWrapper.length).toEqual(2)
+ expect(panesWrapper.length).toEqual(2)
+
+ // add one tab, check panes length and current tab
+ await wrapper.find('.el-tabs__new-tab').trigger('click')
+
+ panesWrapper = wrapper.findAllComponents(TabPane)
+ navItemsWrapper = navWrapper.findAll('.el-tabs__item')
+
+ expect(navItemsWrapper.length).toEqual(3)
+ expect(panesWrapper.length).toEqual(3)
+ expect(navItemsWrapper[2].classes('is-active')).toBe(true)
+ })
+
+ test('addable & closable', async () => {
+ const editableTabsValue = ref('2')
+ const editableTabs = ref([
+ {
+ title: 'Tab 1',
+ name: '1',
+ content: 'Tab 1 content',
+ },
+ {
+ title: 'Tab 2',
+ name: '2',
+ content: 'Tab 2 content',
+ },
+ ])
+ const tabIndex = ref(2)
+ const addTab = () => {
+ const newTabName = `${++tabIndex.value}`
+ editableTabs.value.push({
+ title: 'New Tab',
+ name: newTabName,
+ content: 'New Tab content',
+ })
+ editableTabsValue.value = newTabName
+ }
+ const removeTab = (targetName) => {
+ const tabs = editableTabs.value
+ let activeName = editableTabsValue.value
+ if (activeName === targetName) {
+ tabs.forEach((tab, index) => {
+ if (tab.name === targetName) {
+ const nextTab = tabs[index + 1] || tabs[index - 1]
+ if (nextTab) {
+ activeName = nextTab.name
+ }
+ }
+ })
+ }
+ editableTabsValue.value = activeName
+ editableTabs.value = tabs.filter((tab) => tab.name !== targetName)
+ }
+
+ const wrapper = mount(() => (
+
+ {editableTabs.value.map((item) => (
+
+ ))}
+
+ ))
+
+ const navWrapper = wrapper.findComponent(TabNav)
+ await nextTick()
+
+ await wrapper.find('.el-tabs__new-tab').trigger('click')
+
+ let navItemsWrapper = navWrapper.findAll('.el-tabs__item')
+ let panesWrapper = wrapper.findAllComponents(TabPane)
+ expect(navItemsWrapper.length).toEqual(3)
+ expect(panesWrapper.length).toEqual(3)
+ expect(navItemsWrapper[2].classes('is-active')).toBe(true)
+
+ await navItemsWrapper[2].find('.is-icon-close').trigger('click')
+
+ panesWrapper = wrapper.findAllComponents(TabPane)
+ navItemsWrapper = navWrapper.findAll('.el-tabs__item')
+
+ expect(navItemsWrapper.length).toEqual(2)
+ expect(panesWrapper.length).toEqual(2)
+ })
+
+ test('closable in tab-pane', async () => {
+ const wrapper = mount(() => (
+
+
+ A
+
+ B
+
+ C
+
+ D
+
+ ))
+
+ const navWrapper = wrapper.findComponent(TabNav)
+ await nextTick()
+
+ expect(navWrapper.findAll('.is-icon-close').length).toBe(2)
+ })
+
+ test('disabled', async () => {
+ const wrapper = mount(() => (
+
+ A
+
+ B
+
+ C
+ D
+
+ ))
+
+ const navWrapper = wrapper.findComponent(TabNav)
+ await nextTick()
+ const navItemsWrapper = navWrapper.findAll('.el-tabs__item')
+ expect(navItemsWrapper[1].classes('is-active')).toBe(false)
+
+ await navItemsWrapper[1].trigger('click')
+ expect(navItemsWrapper[1].classes('is-active')).toBe(false)
+ })
+
+ test('tab-position', async () => {
+ const wrapper = mount(() => (
+
+ A
+ B
+
+ C
+
+ D
+
+ ))
+
+ const tabsWrapper = wrapper.findComponent(Tabs)
+ await nextTick()
+
+ expect(tabsWrapper.classes('el-tabs--left')).toBe(true)
+ expect(tabsWrapper.find('.el-tabs__header').classes('is-left')).toBe(true)
+ expect(tabsWrapper.find('.el-tabs__nav-wrap').classes('is-left')).toBe(true)
+ expect(tabsWrapper.find('.el-tabs__nav').classes('is-left')).toBe(true)
+ expect(tabsWrapper.find('.el-tabs__active-bar').classes('is-left')).toBe(
+ true
+ )
+ expect(tabsWrapper.find('.el-tabs__item').classes('is-left')).toBe(true)
+ })
+
+ test('stretch', async () => {
+ const tabPosition = ref('bottom')
+ const wrapper = mount(() => (
+
+ A
+ B
+ C
+ D
+
+ ))
+
+ const tabsWrapper = wrapper.findComponent(Tabs)
+ await nextTick()
+
+ expect(tabsWrapper.find('.el-tabs__nav').classes('is-stretch')).toBe(true)
+
+ tabPosition.value = 'left'
+ await nextTick()
+
+ expect(tabsWrapper.find('.el-tabs__nav').classes('is-stretch')).toBe(false)
+ })
+
+ test('tab active bar offset', async () => {
+ const tabPosition = ref('bottom')
+ const wrapper = mount(() => (
+
+
+ A
+
+
+ B
+
+
+ C
+
+
+ D
+
+
+ ))
+
+ const tabsWrapper = wrapper.findComponent(Tabs)
+ await nextTick()
+ const mockCRect = vi
+ .spyOn(wrapper.find('#tab-C').element, 'getBoundingClientRect')
+ .mockReturnValue({ left: 300 } as DOMRect)
+ const mockComputedStyle = vi
+ .spyOn(window, 'getComputedStyle')
+ .mockReturnValue({ paddingLeft: '0px' } as CSSStyleDeclaration)
+ await wrapper.find('#tab-C').trigger('click')
+
+ await nextTick()
+ expect(tabsWrapper.find('.el-tabs__active-bar').attributes().style).toMatch(
+ 'translateX(300px)'
+ )
+
+ tabPosition.value = 'left'
+ await nextTick()
+ const mockCYRect = vi
+ .spyOn(wrapper.find('#tab-C').element, 'getBoundingClientRect')
+ .mockReturnValue({ top: 200 } as DOMRect)
+ await wrapper.find('#tab-A').trigger('click')
+ await wrapper.find('#tab-C').trigger('click')
+
+ await nextTick()
+ expect(tabsWrapper.find('.el-tabs__active-bar').attributes().style).toMatch(
+ 'translateY(200px)'
+ )
+
+ mockCRect.mockRestore()
+ mockCYRect.mockRestore()
+ mockComputedStyle.mockRestore()
+ wrapper.unmount()
+ })
+
+ test('horizonal-scrollable', async () => {
+ // TODO: jsdom not support `clientWidth`.
+ })
+
+ test('vertical-scrollable', async () => {
+ // TODO: jsdom not support `clientWidth`.
+ })
+
+ test('should work with lazy', async () => {
+ const activeName = ref('A')
+ const wrapper = mount(() => (
+
+
+ A
+
+
+ B
+
+
+ C
+
+
+ D
+
+
+ ))
+
+ const navWrapper = wrapper.findComponent(TabNav)
+ await nextTick()
+ const navItemsWrapper = navWrapper.findAll('.el-tabs__item')
+
+ expect(wrapper.findAll('.el-tab-pane').length).toBe(3)
+
+ await navItemsWrapper[3].trigger('click')
+
+ expect(wrapper.findAll('.el-tab-pane').length).toBe(4)
+ })
+
+ test('before leave', async () => {
+ const activeName = ref('tab-B')
+ const beforeLeave = () => {
+ return new window.Promise((resolve, reject) => {
+ reject()
+ })
+ }
+ const wrapper = mount(() => (
+
+
+ A
+
+
+ B
+
+
+ C
+
+
+ D
+
+
+ ))
+
+ const navWrapper = wrapper.findComponent(TabNav)
+ const panesWrapper = wrapper.findAllComponents(TabPane)
+ await nextTick()
+ const navItemsWrapper = navWrapper.findAll('.el-tabs__item')
+
+ expect(navItemsWrapper[1].classes('is-active')).toBe(true)
+ expect(panesWrapper[1].attributes('style')).toBeFalsy()
+
+ await navItemsWrapper[3].trigger('click')
+
+ expect(navItemsWrapper[1].classes('is-active')).toBe(true)
+ expect(panesWrapper[1].attributes('style')).toBeFalsy()
+ })
+
+ test('keyboard event', async () => {
+ const activeName = ref('second')
+ const wrapper = mount(() => (
+
+
+ A
+
+
+ B
+
+
+ C
+
+
+ D
+
+
+ ))
+
+ await nextTick()
+
+ await wrapper
+ .find('#tab-second')
+ .trigger('keydown', { code: EVENT_CODE.right })
+ expect(activeName.value).toEqual('third')
+
+ await wrapper
+ .find('#tab-third')
+ .trigger('keydown', { code: EVENT_CODE.right })
+ expect(activeName.value).toEqual('fourth')
+
+ await wrapper
+ .find('#tab-fourth')
+ .trigger('keydown', { code: EVENT_CODE.right })
+ expect(activeName.value).toEqual('second')
+
+ await wrapper
+ .find('#tab-second')
+ .trigger('keydown', { code: EVENT_CODE.left })
+ expect(activeName.value).toEqual('fourth')
+ })
+
+ test('resize', async () => {
+ // TODO: jsdom not support `clientWidth`.
+ })
+
+ test('DOM update finished calculating navOffset', async () => {
+ const tabs = ref([])
+ for (let i = 0; i < 5000; i++) {
+ tabs.value.push(i.toString())
+ }
+ const activeName = ref('0')
+ const wrapper = mount(() => (
+
+ {tabs.value.map((item) => (
+
+ ))}
+
+ ))
+
+ const tabsWrapper = wrapper.findComponent(Tabs)
+ await nextTick()
+
+ const mockRect = vi
+ .spyOn(wrapper.find('#tab-4999').element, 'getBoundingClientRect')
+ .mockReturnValue({ left: 5000 } as DOMRect)
+ const mockComputedStyle = vi
+ .spyOn(window, 'getComputedStyle')
+ .mockReturnValue({ paddingLeft: '0px' } as CSSStyleDeclaration)
+
+ await wrapper.find('#tab-4999').trigger('click')
+ await nextTick()
+
+ expect(tabsWrapper.find('.el-tabs__active-bar').attributes().style).toMatch(
+ 'translateX(5000px)'
+ )
+
+ mockRect.mockRestore()
+ mockComputedStyle.mockRestore()
+ wrapper.unmount()
+ })
+
+ test('value type', async () => {
+ const activeName = ref(0)
+ const handleClick = (tab) => {
+ activeName.value = tab.paneName
+ }
+ const wrapper = mount(() => (
+
+
+ A
+
+
+ B
+
+
+ C
+
+
+ D
+
+
+ ))
+
+ const navWrapper = wrapper.findComponent(TabNav)
+ await nextTick()
+
+ const navItemsWrapper = navWrapper.findAll('.el-tabs__item')
+ ;[1, 0, 2, 0, 3, 0, 1].forEach((val) => {
+ navItemsWrapper[val].trigger('click')
+ expect(activeName.value).toEqual(val)
+ })
+ })
+})