AppShell.test.tsx 3.04 KB
import { describe, it, expect, vi } from 'vitest'
import { render, screen, waitFor } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import { Provider } from 'react-redux'
import { MemoryRouter, Routes, Route } from 'react-router-dom'
import { configureStore } from '@reduxjs/toolkit'
import authReducer from '../store/slices/authSlice'
import tabsReducer, { openTab } from '../store/slices/tabsSlice'
import AppShell from '../components/AppShell'

vi.mock('../components/NavOverlay', () => ({
  default: ({ onClose }: { onClose: () => void }) => (
    <div data-testid="nav-overlay" onClick={onClose}>NavOverlay</div>
  ),
}))

function makeStore(extraTabs = false) {
  const store = configureStore({ reducer: { auth: authReducer, tabs: tabsReducer } })
  store.dispatch({
    type: 'auth/setCredentials',
    payload: { accessToken: 'tok', refreshToken: 'ref', userInfo: { userId: 'u0', username: 'admin', userType: '超级管理员', language: '中文', brandId: 'b1' } },
  })
  if (extraTabs) {
    store.dispatch(openTab({ id: 'userlist', title: '用户列表', path: '/usr/users', closable: true }))
  }
  return store
}

function renderShell(path = '/', extraTabs = false) {
  const store = makeStore(extraTabs)
  return {
    store,
    ...render(
      <Provider store={store}>
        <MemoryRouter initialEntries={[path]}>
          <Routes>
            <Route element={<AppShell />}>
              <Route path="/" element={<div>MainPage</div>} />
              <Route path="/usr/users" element={<div>UserListPage</div>} />
            </Route>
          </Routes>
        </MemoryRouter>
      </Provider>
    ),
  }
}

describe('AppShell', () => {
  it('renders_mainTabAndUserInfo', () => {
    renderShell()
    expect(screen.getByText('主页')).toBeInTheDocument()
    expect(screen.getByText(/admin/)).toBeInTheDocument()
  })

  it('renders_openTabs', () => {
    renderShell('/', true)
    expect(screen.getByText('用户列表')).toBeInTheDocument()
  })

  it('clickTab_navigatesToTabPath', async () => {
    renderShell('/', true)
    await userEvent.click(screen.getByText('用户列表'))
    await waitFor(() => expect(screen.getByText('UserListPage')).toBeInTheDocument())
  })

  it('closeTab_removesTabAndNavigates', async () => {
    renderShell('/usr/users', true)
    await userEvent.click(screen.getByRole('button', { name: '关闭 用户列表' }))
    await waitFor(() => expect(screen.queryByText('用户列表')).not.toBeInTheDocument())
    expect(screen.getByText('MainPage')).toBeInTheDocument()
  })

  it('navToggle_showsNavOverlay', async () => {
    renderShell()
    await userEvent.click(screen.getByRole('button', { name: /全部导航/ }))
    expect(screen.getByTestId('nav-overlay')).toBeInTheDocument()
  })

  it('navToggle_secondClick_hidesOverlay', async () => {
    renderShell()
    await userEvent.click(screen.getByRole('button', { name: /全部导航/ }))
    await userEvent.click(screen.getByRole('button', { name: /全部导航/ }))
    expect(screen.queryByTestId('nav-overlay')).not.toBeInTheDocument()
  })
})