Files
novalon-website/src/app/admin/security/page.test.tsx
T
2026-03-24 11:27:23 +08:00

149 lines
4.7 KiB
TypeScript

import { describe, it, expect, jest, beforeAll, afterEach } from '@jest/globals';
import React from 'react';
import { render, screen, waitFor } from '@testing-library/react';
import '@testing-library/jest-dom';
import SecurityDashboard from './page';
jest.mock('lucide-react', () => ({
Shield: () => <span data-testid="shield-icon" />,
AlertTriangle: () => <span data-testid="alert-icon" />,
Activity: () => <span data-testid="activity-icon" />,
Lock: () => <span data-testid="lock-icon" />,
RefreshCw: () => <span data-testid="refresh-cw-icon" />,
TrendingUp: () => <span data-testid="trending-up-icon" />,
TrendingDown: () => <span data-testid="trending-down-icon" />,
}));
jest.mock('@/components/ui/button', () => ({
Button: ({ children, disabled, ...props }: any) => (
<button disabled={disabled} {...props}>
{children}
</button>
),
}));
jest.mock('@/components/ui/card', () => ({
Card: ({ children }: any) => <div data-testid="card">{children}</div>,
CardHeader: ({ children }: any) => <div data-testid="card-header">{children}</div>,
CardTitle: ({ children }: any) => <h3 data-testid="card-title">{children}</h3>,
CardContent: ({ children }: any) => <div data-testid="card-content">{children}</div>,
}));
global.fetch = jest.fn(() =>
Promise.resolve({
ok: true,
json: () => Promise.resolve({
success: true,
logs: [
{
id: '1',
timestamp: Date.now(),
type: 'captcha',
severity: 'high',
message: '验证码验证失败',
ip: '192.168.1.1',
},
],
stats: {
totalRequests: 100,
blockedRequests: 5,
captchaAttempts: 10,
rateLimitHits: 3,
maliciousContentDetected: 2,
successRate: 95,
},
}),
} as Response)
);
describe('SecurityDashboard', () => {
beforeAll(() => {
jest.clearAllMocks();
});
afterEach(() => {
jest.clearAllMocks();
});
describe('Rendering', () => {
it('should render security dashboard', () => {
render(<SecurityDashboard />);
expect(screen.getByText('安全监控仪表板')).toBeInTheDocument();
expect(screen.getByText('实时监控网站安全状态和威胁检测')).toBeInTheDocument();
});
it('should render all stat cards', () => {
render(<SecurityDashboard />);
expect(screen.getByText('总请求数')).toBeInTheDocument();
expect(screen.getByText('已拦截请求')).toBeInTheDocument();
expect(screen.getByText('验证码尝试')).toBeInTheDocument();
expect(screen.getByText('频率限制命中')).toBeInTheDocument();
expect(screen.getByText('恶意内容检测')).toBeInTheDocument();
expect(screen.getByText('成功率')).toBeInTheDocument();
});
it('should display stats values', async () => {
render(<SecurityDashboard />);
await waitFor(() => {
expect(screen.getByText('100')).toBeInTheDocument();
expect(screen.getByText('5')).toBeInTheDocument();
expect(screen.getByText('10')).toBeInTheDocument();
expect(screen.getByText('3')).toBeInTheDocument();
expect(screen.getByText('2')).toBeInTheDocument();
expect(screen.getByText('95%')).toBeInTheDocument();
});
});
});
describe('Security Logs', () => {
it('should render security logs section', async () => {
render(<SecurityDashboard />);
await waitFor(() => {
expect(screen.getByText('安全日志')).toBeInTheDocument();
});
});
it('should display log entries', async () => {
render(<SecurityDashboard />);
await waitFor(() => {
expect(screen.getByText('验证码验证失败')).toBeInTheDocument();
expect(screen.getByText('IP: 192.168.1.1')).toBeInTheDocument();
});
});
it('should have filter buttons', () => {
render(<SecurityDashboard />);
expect(screen.getByText('全部')).toBeInTheDocument();
expect(screen.getByText('高危')).toBeInTheDocument();
expect(screen.getByText('中危')).toBeInTheDocument();
expect(screen.getByText('低危')).toBeInTheDocument();
});
});
describe('Refresh Functionality', () => {
it('should have refresh button', async () => {
render(<SecurityDashboard />);
await waitFor(() => {
expect(screen.getByTestId('refresh-cw-icon')).toBeInTheDocument();
});
});
it('should call fetch when refresh is clicked', async () => {
render(<SecurityDashboard />);
await waitFor(() => {
const refreshButton = screen.getAllByRole('button')[0];
expect(refreshButton).not.toBeDisabled();
refreshButton.click();
expect(global.fetch).toHaveBeenCalled();
});
});
});
});