Files
ai-ticket-platform/frontend/src/components/app/AppRouteTabs.test.tsx

143 lines
6.2 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { act, cleanup, fireEvent, render, screen, waitFor } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
import { AppRouteTabs } from '@/components/app/AppRouteTabs'
function navigate(path: string) {
act(() => {
window.location.hash = path
window.dispatchEvent(new HashChangeEvent('hashchange'))
})
}
beforeEach(() => {
vi.stubGlobal('ResizeObserver', class ResizeObserverMock {
observe() {}
unobserve() {}
disconnect() {}
})
window.sessionStorage.clear()
window.location.hash = '#/tickets/42'
})
afterEach(() => {
cleanup()
vi.unstubAllGlobals()
})
describe('已打开页面标签', () => {
it('只显示实际打开过的页面,并允许关闭非当前标签', async () => {
const user = userEvent.setup()
render(<AppRouteTabs />)
await waitFor(() => expect(screen.getAllByRole('tab')).toHaveLength(1))
expect(screen.getByRole('tab', { name: '工单详情' })).toHaveAttribute('data-state', 'active')
navigate('/knowledge')
await waitFor(() => expect(screen.getAllByRole('tab')).toHaveLength(2))
expect(screen.getByRole('tab', { name: '知识库' })).toHaveAttribute('data-state', 'active')
await user.click(screen.getByRole('button', { name: '关闭工单详情(/tickets/42)' }))
expect(screen.queryByRole('tab', { name: '工单详情' })).not.toBeInTheDocument()
expect(window.location.hash).toBe('#/knowledge')
})
it('关闭当前标签后切换到相邻页面,并在关闭最后一个标签时回到工作台', async () => {
const user = userEvent.setup()
render(<AppRouteTabs />)
navigate('/knowledge')
await waitFor(() => expect(screen.getAllByRole('tab')).toHaveLength(2))
await user.click(screen.getByRole('button', { name: '关闭知识库(/knowledge)' }))
expect(window.location.hash).toBe('#/tickets/42')
navigate('/tickets/42')
await waitFor(() => expect(screen.getByRole('tab', { name: '工单详情' })).toHaveAttribute('data-state', 'active'))
await user.click(screen.getByRole('button', { name: '关闭工单详情(/tickets/42)' }))
expect(window.location.hash).toBe('#/')
navigate('/')
await waitFor(() => expect(screen.getByRole('tab', { name: '工作台' })).toHaveAttribute('data-state', 'active'))
})
it('刷新式重新挂载后保留本次会话已打开的标签', async () => {
const { unmount } = render(<AppRouteTabs />)
navigate('/knowledge')
await waitFor(() => expect(screen.getAllByRole('tab')).toHaveLength(2))
unmount()
render(<AppRouteTabs />)
expect(screen.getByRole('tab', { name: '工单详情' })).toBeInTheDocument()
expect(screen.getByRole('tab', { name: '知识库' })).toBeInTheDocument()
})
it('右键标签可以关闭其左侧和右侧标签', async () => {
const user = userEvent.setup()
render(<AppRouteTabs />)
navigate('/knowledge')
navigate('/solutions')
await waitFor(() => expect(screen.getAllByRole('tab')).toHaveLength(3))
fireEvent.contextMenu(screen.getByRole('tab', { name: '知识库' }))
await user.click(await screen.findByRole('menuitem', { name: '关闭左侧标签' }))
expect(screen.queryByRole('tab', { name: '工单详情' })).not.toBeInTheDocument()
expect(screen.getByRole('tab', { name: '知识库' })).toBeInTheDocument()
expect(screen.getByRole('tab', { name: '解决方案库' })).toBeInTheDocument()
fireEvent.contextMenu(screen.getByRole('tab', { name: '知识库' }))
await user.click(await screen.findByRole('menuitem', { name: '关闭右侧标签' }))
expect(screen.queryByRole('tab', { name: '解决方案库' })).not.toBeInTheDocument()
expect(screen.getAllByRole('tab')).toHaveLength(1)
expect(window.location.hash).toBe('#/knowledge')
})
it('批量菜单可以关闭其他标签和关闭全部标签', async () => {
const user = userEvent.setup()
render(<AppRouteTabs />)
navigate('/knowledge')
navigate('/solutions')
await waitFor(() => expect(screen.getAllByRole('tab')).toHaveLength(3))
await user.click(screen.getByRole('button', { name: '查看全部已打开页面,共 3 个' }))
await user.click(screen.getByRole('menuitem', { name: '关闭其他标签' }))
expect(screen.getAllByRole('tab')).toHaveLength(1)
expect(screen.getByRole('tab', { name: '解决方案库' })).toBeInTheDocument()
await user.click(screen.getByRole('button', { name: '查看全部已打开页面,共 1 个' }))
await user.click(screen.getByRole('menuitem', { name: '关闭全部标签' }))
expect(screen.getAllByRole('tab')).toHaveLength(1)
expect(screen.getByRole('tab', { name: '工作台' })).toBeInTheDocument()
expect(window.location.hash).toBe('#/')
})
it('标签溢出时隐藏原生滚动条,并提供左右切换和全部页面菜单', async () => {
const user = userEvent.setup()
const { container } = render(<AppRouteTabs />)
navigate('/knowledge')
await waitFor(() => expect(screen.getAllByRole('tab')).toHaveLength(2))
const scrollArea = container.querySelector('[data-slot="app-route-tabs-scroll"]') as HTMLDivElement
const scrollBy = vi.fn()
Object.defineProperties(scrollArea, {
clientWidth: { configurable: true, value: 320 },
scrollWidth: { configurable: true, value: 720 },
scrollLeft: { configurable: true, value: 0, writable: true },
scrollBy: { configurable: true, value: scrollBy }
})
fireEvent.scroll(scrollArea)
const nextButton = await screen.findByRole('button', { name: '向右查看已打开页面' })
expect(scrollArea).toHaveClass('scrollbar-hidden', 'scroll-fade-x')
expect(screen.getByRole('button', { name: '向左查看已打开页面' })).toBeDisabled()
await user.click(nextButton)
expect(scrollBy).toHaveBeenCalledWith(expect.objectContaining({ behavior: 'smooth' }))
await user.click(screen.getByRole('button', { name: '查看全部已打开页面,共 2 个' }))
expect(screen.getByRole('menuitem', { name: /工单详情/ })).toBeInTheDocument()
expect(screen.getByRole('menuitem', { name: /知识库.*当前/ })).toHaveAttribute('aria-current', 'page')
})
})