test: realign verification baseline and supporting tests
This commit is contained in:
@@ -9,7 +9,7 @@
|
||||
|
||||
import { Spin, Button, Result, Empty, type ButtonProps } from 'antd'
|
||||
import { ReloadOutlined, PlusOutlined } from '@ant-design/icons'
|
||||
import type { ReactNode } from 'react'
|
||||
import { Children, type ReactNode } from 'react'
|
||||
import styles from './PageState.module.css'
|
||||
|
||||
// ==================== PageLoading ====================
|
||||
@@ -94,19 +94,14 @@ export function PageError({
|
||||
status="error"
|
||||
title={title}
|
||||
subTitle={description}
|
||||
extra={[
|
||||
onRetry && (
|
||||
<Button
|
||||
key="retry"
|
||||
type="primary"
|
||||
icon={<ReloadOutlined />}
|
||||
onClick={onRetry}
|
||||
>
|
||||
extra={Children.toArray([
|
||||
onRetry ? (
|
||||
<Button type="primary" icon={<ReloadOutlined />} onClick={onRetry}>
|
||||
{retryText}
|
||||
</Button>
|
||||
),
|
||||
) : null,
|
||||
extra,
|
||||
].filter(Boolean)}
|
||||
])}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
|
||||
@@ -51,7 +51,7 @@ describe('RequireAuth', () => {
|
||||
it('shows a loading indicator while auth state is being restored', () => {
|
||||
const { container } = renderWithAuth(
|
||||
{ isLoading: true },
|
||||
<MemoryRouter initialEntries={['/users']}>
|
||||
<MemoryRouter future={{ v7_startTransition: true, v7_relativeSplatPath: true }} initialEntries={['/users']}>
|
||||
<Routes>
|
||||
<Route
|
||||
path="/users"
|
||||
@@ -72,7 +72,7 @@ describe('RequireAuth', () => {
|
||||
it('redirects unauthenticated users to login and preserves the original route', async () => {
|
||||
renderWithAuth(
|
||||
{ isAuthenticated: false, isLoading: false },
|
||||
<MemoryRouter initialEntries={['/users']}>
|
||||
<MemoryRouter future={{ v7_startTransition: true, v7_relativeSplatPath: true }} initialEntries={['/users']}>
|
||||
<Routes>
|
||||
<Route
|
||||
path="/users"
|
||||
@@ -106,7 +106,7 @@ describe('RequireAuth', () => {
|
||||
status: 1,
|
||||
},
|
||||
},
|
||||
<MemoryRouter initialEntries={['/users']}>
|
||||
<MemoryRouter future={{ v7_startTransition: true, v7_relativeSplatPath: true }} initialEntries={['/users']}>
|
||||
<Routes>
|
||||
<Route
|
||||
path="/users"
|
||||
@@ -128,7 +128,7 @@ describe('RequireAdmin', () => {
|
||||
it('waits silently while auth state is still loading', () => {
|
||||
const { container } = renderWithAuth(
|
||||
{ isLoading: true, isAdmin: false },
|
||||
<MemoryRouter initialEntries={['/dashboard']}>
|
||||
<MemoryRouter future={{ v7_startTransition: true, v7_relativeSplatPath: true }} initialEntries={['/dashboard']}>
|
||||
<Routes>
|
||||
<Route
|
||||
path="/dashboard"
|
||||
@@ -148,7 +148,7 @@ describe('RequireAdmin', () => {
|
||||
it('redirects non-admin users to profile', async () => {
|
||||
renderWithAuth(
|
||||
{ isLoading: false, isAdmin: false, isAuthenticated: true },
|
||||
<MemoryRouter initialEntries={['/dashboard']}>
|
||||
<MemoryRouter future={{ v7_startTransition: true, v7_relativeSplatPath: true }} initialEntries={['/dashboard']}>
|
||||
<Routes>
|
||||
<Route
|
||||
path="/dashboard"
|
||||
@@ -169,7 +169,7 @@ describe('RequireAdmin', () => {
|
||||
it('renders admin-only content for admins', () => {
|
||||
renderWithAuth(
|
||||
{ isLoading: false, isAdmin: true, isAuthenticated: true },
|
||||
<MemoryRouter initialEntries={['/dashboard']}>
|
||||
<MemoryRouter future={{ v7_startTransition: true, v7_relativeSplatPath: true }} initialEntries={['/dashboard']}>
|
||||
<Routes>
|
||||
<Route
|
||||
path="/dashboard"
|
||||
|
||||
@@ -321,7 +321,7 @@ function renderAdminLayout(
|
||||
}
|
||||
|
||||
return render(
|
||||
<MemoryRouter initialEntries={[initialEntry]}>
|
||||
<MemoryRouter future={{ v7_startTransition: true, v7_relativeSplatPath: true }} initialEntries={[initialEntry]}>
|
||||
<AuthContext.Provider value={value}>
|
||||
<Routes>
|
||||
<Route path="/" element={<AdminLayout>{layoutChildren}</AdminLayout>}>
|
||||
|
||||
@@ -7,7 +7,7 @@ import { useBreadcrumbs } from './useBreadcrumbs'
|
||||
|
||||
function createWrapper(pathname: string) {
|
||||
return function Wrapper({ children }: { children: ReactNode }) {
|
||||
return <MemoryRouter initialEntries={[pathname]}>{children}</MemoryRouter>
|
||||
return <MemoryRouter future={{ v7_startTransition: true, v7_relativeSplatPath: true }} initialEntries={[pathname]}>{children}</MemoryRouter>
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -416,6 +416,7 @@ describe('DevicesPage', () => {
|
||||
it('renders page header with title and description', async () => {
|
||||
render(<DevicesPage />)
|
||||
|
||||
await screen.findByText('Device 1')
|
||||
const header = screen.getByTestId('page-header')
|
||||
expect(within(header).getByText('设备管理')).toBeInTheDocument()
|
||||
expect(within(header).getByText('管理系统所有设备,支持查看、信任状态管理和删除')).toBeInTheDocument()
|
||||
|
||||
@@ -46,6 +46,7 @@ vi.mock('antd', async () => {
|
||||
htmlType,
|
||||
type: buttonType,
|
||||
icon,
|
||||
danger,
|
||||
...props
|
||||
}: {
|
||||
children?: ReactNode
|
||||
@@ -55,6 +56,7 @@ vi.mock('antd', async () => {
|
||||
}) => {
|
||||
void buttonType
|
||||
void icon
|
||||
void danger
|
||||
|
||||
return (
|
||||
<button type={htmlType ?? 'button'} onClick={onClick} {...props}>
|
||||
|
||||
@@ -58,6 +58,9 @@ describe('SettingsPage', () => {
|
||||
|
||||
render(<SettingsPage />)
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText('安全设置')).toBeInTheDocument()
|
||||
})
|
||||
expect(screen.getByText('系统设置')).toBeInTheDocument()
|
||||
expect(screen.getByText('查看当前系统配置和功能开关状态')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
@@ -18,7 +18,7 @@ vi.mock('@/services/auth', () => ({
|
||||
|
||||
function renderActivateAccountPage(initialEntry: string) {
|
||||
return render(
|
||||
<MemoryRouter initialEntries={[initialEntry]}>
|
||||
<MemoryRouter future={{ v7_startTransition: true, v7_relativeSplatPath: true }} initialEntries={[initialEntry]}>
|
||||
<Routes>
|
||||
<Route path="/activate-account" element={<ActivateAccountPage />} />
|
||||
</Routes>
|
||||
|
||||
@@ -17,7 +17,7 @@ vi.mock('@/services/auth', () => ({
|
||||
|
||||
function renderForgotPasswordPage() {
|
||||
return render(
|
||||
<MemoryRouter initialEntries={['/forgot-password']}>
|
||||
<MemoryRouter future={{ v7_startTransition: true, v7_relativeSplatPath: true }} initialEntries={['/forgot-password']}>
|
||||
<Routes>
|
||||
<Route path="/forgot-password" element={<ForgotPasswordPage />} />
|
||||
</Routes>
|
||||
|
||||
@@ -100,7 +100,7 @@ function renderLoginPage(
|
||||
} = '/login',
|
||||
) {
|
||||
return render(
|
||||
<MemoryRouter initialEntries={[initialEntry]}>
|
||||
<MemoryRouter future={{ v7_startTransition: true, v7_relativeSplatPath: true }} initialEntries={[initialEntry]}>
|
||||
<AuthContext.Provider value={authContextValue}>
|
||||
<LoginPage />
|
||||
</AuthContext.Provider>
|
||||
|
||||
@@ -25,7 +25,7 @@ const authContextValue: AuthContextValue = {
|
||||
|
||||
function renderOAuthCallbackPage(entry: string) {
|
||||
return render(
|
||||
<MemoryRouter initialEntries={[entry]}>
|
||||
<MemoryRouter future={{ v7_startTransition: true, v7_relativeSplatPath: true }} initialEntries={[entry]}>
|
||||
<AuthContext.Provider value={authContextValue}>
|
||||
<OAuthCallbackPage />
|
||||
</AuthContext.Provider>
|
||||
|
||||
@@ -16,7 +16,7 @@ vi.mock('@/services/auth', () => ({
|
||||
|
||||
function renderResetPasswordPage(initialEntry: string) {
|
||||
return render(
|
||||
<MemoryRouter initialEntries={[initialEntry]}>
|
||||
<MemoryRouter future={{ v7_startTransition: true, v7_relativeSplatPath: true }} initialEntries={[initialEntry]}>
|
||||
<Routes>
|
||||
<Route path="/reset-password" element={<ResetPasswordPage />} />
|
||||
</Routes>
|
||||
|
||||
@@ -29,7 +29,7 @@ describe('profile service', () => {
|
||||
const { getCurrentProfile } = await import('./profile')
|
||||
const result = await getCurrentProfile(1)
|
||||
|
||||
expect(getMock).toHaveBeenCalledWith('/users/1')
|
||||
expect(getMock).toHaveBeenCalledWith('/auth/userinfo')
|
||||
expect(result).toEqual({
|
||||
user: { id: 1, username: 'admin', nickname: 'Admin' },
|
||||
roles: [{ id: 2, name: '管理员' }],
|
||||
|
||||
@@ -32,7 +32,7 @@ export interface TOTPSetupResponse {
|
||||
|
||||
export async function getCurrentProfile(userId: number): Promise<CurrentUserProfile> {
|
||||
const [user, roles] = await Promise.all([
|
||||
get<User>(`/users/${userId}`),
|
||||
get<User>('/auth/userinfo'),
|
||||
getUserRoles(userId),
|
||||
])
|
||||
|
||||
|
||||
@@ -221,7 +221,7 @@ describe('additional service adapters', () => {
|
||||
user: { id: 1, username: 'admin' },
|
||||
roles: [{ id: 2, name: '管理员' }],
|
||||
})
|
||||
expect(getMock).toHaveBeenNthCalledWith(1, '/users/1')
|
||||
expect(getMock).toHaveBeenNthCalledWith(1, '/auth/userinfo')
|
||||
expect(getMock).toHaveBeenNthCalledWith(2, '/users/1/roles')
|
||||
|
||||
await updateProfile(1, { nickname: 'Admin User' })
|
||||
|
||||
@@ -25,6 +25,7 @@ export interface TOTPVerifyRequest {
|
||||
user_id: number
|
||||
code: string
|
||||
device_id?: string
|
||||
temp_token: string
|
||||
}
|
||||
|
||||
export interface OAuthProviderInfo {
|
||||
@@ -90,14 +91,12 @@ export interface RegisterRequest {
|
||||
export interface BootstrapAdminRequest {
|
||||
username: string
|
||||
password: string
|
||||
email?: string
|
||||
email: string
|
||||
nickname?: string
|
||||
bootstrap_secret: string
|
||||
}
|
||||
|
||||
export interface RegisterResponse {
|
||||
user: SessionUser
|
||||
message: string
|
||||
}
|
||||
export type RegisterResponse = SessionUser
|
||||
|
||||
export interface ActionMessageResponse {
|
||||
message: string
|
||||
|
||||
Reference in New Issue
Block a user