// REQ-USR-003: AppLayout 外壳装配 + 标签↔路由同步(ready / navOverlayOpen / tabOpen 态)
import { describe, it, expect } from 'vitest';
import { screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { Routes, Route, useLocation } from 'react-router-dom';
import { renderShell } from './renderShell';
import AppLayout from '../../src/layouts/AppLayout/AppLayout';
import type { AuthUser } from '../../src/api/types';
const ADMIN: AuthUser = { id: 1, sUserName: '朱子纯', sUserType: '超级管理员', sLanguage: '中文' };
function LocProbe() {
const loc = useLocation();
return
{loc.pathname}
;
}
function renderLayout(initialEntries: string[]) {
return renderShell(
}>
home-outlet
>
}
/>
users-outlet
>
}
/>
,
{ initialEntries, preloadedAuth: { token: 't', user: ADMIN } },
);
}
describe('AppLayout shell', () => {
it('renders TopBar + Outlet when ready', () => {
renderLayout(['/']);
// 顶栏(全部导航 + 当前用户)
expect(screen.getByRole('button', { name: '全部导航' })).toBeInTheDocument();
expect(screen.getByText('朱子纯(超级管理员)')).toBeInTheDocument();
// Outlet 子内容
expect(screen.getByTestId('home-outlet')).toBeInTheDocument();
});
it('toggle 全部导航 opens/closes overlay', async () => {
renderLayout(['/']);
expect(screen.queryByTestId('nav-overlay')).not.toBeInTheDocument();
await userEvent.click(screen.getByRole('button', { name: '全部导航' }));
expect(screen.getByTestId('nav-overlay')).toBeInTheDocument();
// 点遮罩关闭
await userEvent.click(screen.getByTestId('nav-overlay-mask'));
expect(screen.queryByTestId('nav-overlay')).not.toBeInTheDocument();
});
it('nav overlay 用户列表 navigates and opens tab', async () => {
renderLayout(['/']);
await userEvent.click(screen.getByRole('button', { name: '全部导航' }));
await userEvent.click(screen.getByRole('button', { name: /用户列表/ }));
// overlay 关闭
expect(screen.queryByTestId('nav-overlay')).not.toBeInTheDocument();
// URL 到 /usr/users
expect(screen.getByTestId('loc').textContent).toBe('/usr/users');
// 顶栏出现「用户列表」标签并激活
const tab = screen.getByTestId('tab-userlist');
expect(tab).toHaveTextContent('用户列表');
expect(tab.getAttribute('aria-pressed')).toBe('true');
});
it('clicking home tab navigates back to /', async () => {
renderLayout(['/']);
// 先打开用户列表标签
await userEvent.click(screen.getByRole('button', { name: '全部导航' }));
await userEvent.click(screen.getByRole('button', { name: /用户列表/ }));
expect(screen.getByTestId('loc').textContent).toBe('/usr/users');
// 点主页标签回 /
await userEvent.click(screen.getByTestId('tab-home'));
expect(screen.getByTestId('loc').textContent).toBe('/');
expect(screen.getByTestId('tab-home').getAttribute('aria-pressed')).toBe('true');
});
it('active tab syncs with current route', () => {
renderLayout(['/usr/users']);
// 直接进 /usr/users,用户列表标签应存在且激活
const tab = screen.getByTestId('tab-userlist');
expect(tab.getAttribute('aria-pressed')).toBe('true');
});
});