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
135 lines
4.8 KiB
TypeScript
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()
|
|
})
|
|
})
|