You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
gcgj-dify-1.7.0/web/app/components/header/account-setting/mfa-page.test.tsx

204 lines
5.5 KiB
TypeScript

import React from 'react'
import { render, screen, fireEvent, waitFor } from '@testing-library/react'
import '@testing-library/jest-dom'
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
import MFAPage from './mfa-page'
// Mock the translation hook
jest.mock('react-i18next', () => ({
useTranslation: () => ({
t: (key: string) => key,
}),
}))
// Mock the MFA service
jest.mock('@/service/use-mfa', () => ({
mfaService: {
getStatus: jest.fn(),
setupInit: jest.fn(),
setupComplete: jest.fn(),
disable: jest.fn(),
},
}))
// Mock the Toast component
jest.mock('@/app/components/base/toast', () => ({
__esModule: true,
default: {
error: jest.fn(),
success: jest.fn(),
},
}))
describe('MFAPage Component', () => {
let queryClient: QueryClient
beforeEach(() => {
queryClient = new QueryClient({
defaultOptions: {
queries: { retry: false },
},
})
})
const renderMFAPage = () => {
return render(
<QueryClientProvider client={queryClient}>
<MFAPage />
</QueryClientProvider>
)
}
test('renders loading state initially', () => {
const { mfaService } = require('@/service/use-mfa')
mfaService.getStatus.mockImplementation(() => new Promise(() => {})) // Never resolves
renderMFAPage()
expect(screen.getByText('Loading...')).toBeInTheDocument()
})
test('renders enable button when MFA is disabled', async () => {
const { mfaService } = require('@/service/use-mfa')
mfaService.getStatus.mockResolvedValue({ enabled: false })
renderMFAPage()
await waitFor(() => {
expect(screen.getByText('common.settings.mfaEnable')).toBeInTheDocument()
})
})
test('renders disable button when MFA is enabled', async () => {
const { mfaService } = require('@/service/use-mfa')
mfaService.getStatus.mockResolvedValue({
enabled: true,
setup_at: '2025-01-01T12:00:00'
})
renderMFAPage()
await waitFor(() => {
expect(screen.getByText('common.settings.mfaDisable')).toBeInTheDocument()
})
})
test('opens setup modal when enable button is clicked', async () => {
const { mfaService } = require('@/service/use-mfa')
mfaService.getStatus.mockResolvedValue({ enabled: false })
mfaService.setupInit.mockResolvedValue({
secret: 'TEST_SECRET',
qr_code: 'data:image/png;base64,test'
})
renderMFAPage()
await waitFor(() => {
expect(screen.getByText('common.settings.mfaEnable')).toBeInTheDocument()
})
fireEvent.click(screen.getByText('common.settings.mfaEnable'))
await waitFor(() => {
expect(screen.getByText('mfa.setup.title')).toBeInTheDocument()
})
})
test('completes MFA setup successfully', async () => {
const { mfaService } = require('@/service/use-mfa')
const Toast = require('@/app/components/base/toast').default
mfaService.getStatus.mockResolvedValue({ enabled: false })
mfaService.setupInit.mockResolvedValue({
secret: 'TEST_SECRET',
qr_code: 'data:image/png;base64,test'
})
mfaService.setupComplete.mockResolvedValue({
message: 'Success',
backup_codes: ['CODE1', 'CODE2', 'CODE3']
})
renderMFAPage()
// Click enable
await waitFor(() => {
fireEvent.click(screen.getByText('common.settings.mfaEnable'))
})
// Enter TOTP code
await waitFor(() => {
const input = screen.getByPlaceholderText('mfa.setup.totpPlaceholder')
fireEvent.change(input, { target: { value: '123456' } })
})
// Click next
fireEvent.click(screen.getByText('common.operation.next'))
await waitFor(() => {
expect(Toast.success).toHaveBeenCalledWith('mfa.setup.success')
})
})
test('shows error when setup fails', async () => {
const { mfaService } = require('@/service/use-mfa')
const Toast = require('@/app/components/base/toast').default
mfaService.getStatus.mockResolvedValue({ enabled: false })
mfaService.setupInit.mockResolvedValue({
secret: 'TEST_SECRET',
qr_code: 'data:image/png;base64,test'
})
mfaService.setupComplete.mockRejectedValue(new Error('Invalid TOTP'))
renderMFAPage()
// Click enable
await waitFor(() => {
fireEvent.click(screen.getByText('common.settings.mfaEnable'))
})
// Enter TOTP code
await waitFor(() => {
const input = screen.getByPlaceholderText('mfa.setup.totpPlaceholder')
fireEvent.change(input, { target: { value: 'wrong' } })
})
// Click next
fireEvent.click(screen.getByText('common.operation.next'))
await waitFor(() => {
expect(Toast.error).toHaveBeenCalledWith('Invalid TOTP')
})
})
test('disables MFA successfully', async () => {
const { mfaService } = require('@/service/use-mfa')
const Toast = require('@/app/components/base/toast').default
mfaService.getStatus.mockResolvedValue({
enabled: true,
setup_at: '2025-01-01T12:00:00'
})
mfaService.disable.mockResolvedValue({ message: 'Success' })
renderMFAPage()
// Click disable
await waitFor(() => {
fireEvent.click(screen.getByText('common.settings.mfaDisable'))
})
// Enter password
await waitFor(() => {
const input = screen.getByPlaceholderText('mfa.disable.passwordPlaceholder')
fireEvent.change(input, { target: { value: 'password123' } })
})
// Click confirm
fireEvent.click(screen.getByText('common.operation.confirm'))
await waitFor(() => {
expect(Toast.success).toHaveBeenCalledWith('mfa.disable.success')
})
})
})