码桶
发现社区成员的开源项目
Dashboard.test.jsx4.8 KB
import React from 'react';
import { render, screen } from '@testing-library/react';
import Dashboard from '../../src/components/Dashboard.jsx';
import { AuthProvider } from '../../src/contexts/AuthContext.jsx';
import { ToastProvider } from '../../src/contexts/ToastContext.jsx';
import { ThemeProvider } from '../../src/contexts/ThemeContext.jsx';
// Mock fetch for the audit log useEffect
beforeEach(() => {
globalThis.fetch = vi.fn(() =>
Promise.resolve(
new Response(JSON.stringify({ entries: [] }), {
status: 200,
headers: { 'content-type': 'application/json' },
})
)
);
// localStorage mock
vi.spyOn(Storage.prototype, 'getItem').mockReturnValue('{}');
});
afterEach(() => {
vi.restoreAllMocks();
});
const t = (key) => key;
const defaultZones = [
{ id: 'z1', name: 'example.com' },
{ id: 'z2', name: 'example.org' },
{ id: 'z3', name: 'example.net' },
];
const defaultAuth = {
mode: 'client',
token: 'test-token',
};
const renderWithProviders = (ui, { auth = defaultAuth } = {}) => {
return render(
<AuthProvider auth={auth} setAuth={() => {}}>
<ToastProvider showToast={() => {}}>
<ThemeProvider t={t} lang="en" changeLang={() => {}} toggleLang={() => {}} darkMode={false} setDarkMode={() => {}}>
{ui}
</ThemeProvider>
</ToastProvider>
</AuthProvider>
);
};
describe('Dashboard component', () => {
it('renders without crashing', () => {
renderWithProviders(<Dashboard zones={defaultZones} />);
});
it('renders stat cards', () => {
renderWithProviders(<Dashboard zones={defaultZones} />);
// Check that dashboard card labels are rendered via translation keys
expect(screen.getByText('dashboardZones')).toBeInTheDocument();
expect(screen.getByText('dashboardRecords')).toBeInTheDocument();
expect(screen.getByText('dashboardAccounts')).toBeInTheDocument();
expect(screen.getByText('dashboardLastLogin')).toBeInTheDocument();
});
it('shows the correct zone count', () => {
renderWithProviders(<Dashboard zones={defaultZones} />);
// Zone count should be rendered as text "3"
expect(screen.getByText('3')).toBeInTheDocument();
});
it('shows zone count of 0 for empty zones array', () => {
renderWithProviders(<Dashboard zones={[]} />);
expect(screen.getByText('0')).toBeInTheDocument();
});
it('renders DNS record count or dash when no counts available', () => {
renderWithProviders(<Dashboard zones={defaultZones} />);
// With no dnsRecordCounts prop, shows '-'
expect(screen.getByText('-')).toBeInTheDocument();
});
it('does not show activity section for non-admin client mode', () => {
renderWithProviders(<Dashboard zones={defaultZones} />);
// The recent activity section is only shown for server mode admins
expect(screen.queryByText('dashboardRecentActivity')).not.toBeInTheDocument();
});
it('shows activity section for server mode admin', async () => {
const adminAuth = {
mode: 'server',
token: 'admin-jwt',
role: 'admin',
sessions: [],
};
renderWithProviders(<Dashboard zones={defaultZones} />, { auth: adminAuth });
// The recent activity heading should appear
expect(screen.getByText('dashboardRecentActivity')).toBeInTheDocument();
});
it('shows loading indicator while audit log is loading', () => {
// Make fetch never resolve to keep loading state
globalThis.fetch = vi.fn(() => new Promise(() => {}));
const adminAuth = {
mode: 'server',
token: 'admin-jwt',
role: 'admin',
sessions: [],
};
renderWithProviders(<Dashboard zones={defaultZones} />, { auth: adminAuth });
// Loading indicator is "..."
expect(screen.getByText('...')).toBeInTheDocument();
});
it('shows "no activity" message when audit log is empty', async () => {
// fetch resolves immediately with empty entries
globalThis.fetch = vi.fn(() =>
Promise.resolve(
new Response(JSON.stringify({ entries: [] }), {
status: 200,
headers: { 'content-type': 'application/json' },
})
)
);
const adminAuth = {
mode: 'server',
token: 'admin-jwt',
role: 'admin',
sessions: [],
};
renderWithProviders(<Dashboard zones={defaultZones} />, { auth: adminAuth });
// Wait for the async fetch to complete
const noActivity = await screen.findByText('dashboardNoActivity');
expect(noActivity).toBeInTheDocument();
});
});