149 lines
4.7 KiB
TypeScript
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();
|
|
});
|
|
});
|
|
});
|
|
});
|