Files
user-system/frontend/admin/src/pages/auth/BootstrapAdminPage/BootstrapAdminPage.test.tsx
long-agent 3f3bb82f1d fix: v6 code review P0 auth/IDOR fixes + frontend regression patches
Backend fixes:
- auth_handler: P0 认证逻辑修复
- ratelimit: 限速中间件增强 + 新增单元测试
- auth_service: 认证服务逻辑完善 + 新增测试
- server: server 配置增强 + 新增测试
- handler_test: 新增 handler 层集成测试
- auth_bootstrap_test: bootstrap 路径测试

Frontend patches:
- LoginPage/RegisterPage: CSRF + 表单交互修复
- BootstrapAdminPage: 引导流程修复
- DevicesPage: 设备管理页修复
- auth/social-accounts/users/webhooks services: 类型修正
- csrf.ts: CSRF token 处理修正
- E2E 脚本: CDP smoke + auth e2e 增强

Docs:
- FULL_CODE_REVIEW_REPORT_2026-04-20
- report-v6 执行计划
- REAL_PROJECT_STATUS 更新
- .gitignore: 新增 .gocache-*/config.yaml 排除

验证: go build/vet 0错误, go test 42/42 PASS, 0 FAIL
2026-04-23 07:14:12 +08:00

135 lines
4.8 KiB
TypeScript

import { MemoryRouter } from 'react-router-dom'
import { render, screen, waitFor } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import { beforeEach, describe, expect, it, vi } from 'vitest'
import { AuthContext, type AuthContextValue } from '@/app/providers/auth-context'
import type { AuthCapabilities, TokenBundle } from '@/types'
import { BootstrapAdminPage } from './BootstrapAdminPage'
const getAuthCapabilitiesMock = vi.fn<() => Promise<AuthCapabilities>>()
const bootstrapAdminMock = vi.fn<(payload: unknown, bootstrapSecret: string) => Promise<TokenBundle>>()
const onLoginSuccessMock = vi.fn<(tokenBundle: TokenBundle) => Promise<void>>()
vi.mock('@/services/auth', () => ({
getAuthCapabilities: () => getAuthCapabilitiesMock(),
bootstrapAdmin: (payload: unknown, bootstrapSecret: string) => bootstrapAdminMock(payload, bootstrapSecret),
}))
const authContextValue: AuthContextValue = {
user: null,
roles: [],
isAdmin: false,
isAuthenticated: false,
isLoading: false,
onLoginSuccess: (tokenBundle) => onLoginSuccessMock(tokenBundle),
logout: vi.fn(async () => {}),
refreshUser: vi.fn(async () => {}),
}
function renderBootstrapAdminPage() {
return render(
<MemoryRouter initialEntries={['/bootstrap-admin']}>
<AuthContext.Provider value={authContextValue}>
<BootstrapAdminPage />
</AuthContext.Provider>
</MemoryRouter>,
)
}
describe('BootstrapAdminPage', () => {
beforeEach(() => {
getAuthCapabilitiesMock.mockReset()
bootstrapAdminMock.mockReset()
onLoginSuccessMock.mockReset()
getAuthCapabilitiesMock.mockResolvedValue({
password: true,
email_activation: false,
email_code: false,
sms_code: false,
password_reset: false,
admin_bootstrap_required: true,
oauth_providers: [],
})
bootstrapAdminMock.mockResolvedValue({
access_token: 'access-token',
refresh_token: 'refresh-token',
expires_in: 7200,
user: {
id: 1,
username: 'bootstrap_admin',
email: 'bootstrap_admin@example.com',
phone: '',
nickname: 'Bootstrap Admin',
avatar: '',
status: 1,
},
})
onLoginSuccessMock.mockResolvedValue(undefined)
})
it('renders the first-admin bootstrap form when the system has no active admin', async () => {
renderBootstrapAdminPage()
await waitFor(() => expect(getAuthCapabilitiesMock).toHaveBeenCalledTimes(1))
expect(screen.getByRole('heading', { name: '初始化首个管理员账号' })).toBeInTheDocument()
expect(screen.getByPlaceholderText('管理员用户名')).toBeInTheDocument()
expect(screen.getByPlaceholderText('引导密钥')).toBeInTheDocument()
expect(screen.getByPlaceholderText('管理员密码')).toBeInTheDocument()
expect(screen.getByRole('button', { name: '完成初始化并进入系统' })).toBeInTheDocument()
})
it('submits the bootstrap request and hands the created session to the auth provider', async () => {
const user = userEvent.setup()
renderBootstrapAdminPage()
await waitFor(() => expect(screen.getByPlaceholderText('管理员用户名')).toBeInTheDocument())
await user.type(screen.getByPlaceholderText('管理员用户名'), 'bootstrap_admin')
await user.type(screen.getByPlaceholderText('管理员昵称(选填)'), 'Bootstrap Admin')
await user.type(screen.getByPlaceholderText('管理员邮箱(选填)'), 'bootstrap_admin@example.com')
await user.type(screen.getByPlaceholderText('引导密钥'), 'bootstrap-secret')
await user.type(screen.getByPlaceholderText('管理员密码'), 'Bootstrap123!@#')
await user.type(screen.getByPlaceholderText('确认管理员密码'), 'Bootstrap123!@#')
await user.click(screen.getByRole('button', { name: '完成初始化并进入系统' }))
await waitFor(() =>
expect(bootstrapAdminMock).toHaveBeenCalledWith(
{
username: 'bootstrap_admin',
nickname: 'Bootstrap Admin',
email: 'bootstrap_admin@example.com',
password: 'Bootstrap123!@#',
},
'bootstrap-secret',
),
)
await waitFor(() =>
expect(onLoginSuccessMock).toHaveBeenCalledWith(expect.objectContaining({
access_token: 'access-token',
refresh_token: 'refresh-token',
})),
)
})
it('shows an informational state when admin bootstrap is already closed', async () => {
getAuthCapabilitiesMock.mockResolvedValue({
password: true,
email_activation: false,
email_code: false,
sms_code: false,
password_reset: false,
admin_bootstrap_required: false,
oauth_providers: [],
})
renderBootstrapAdminPage()
expect(await screen.findByText('管理员已完成初始化')).toBeInTheDocument()
expect(screen.getByRole('link', { name: '返回登录' })).toBeInTheDocument()
})
})