learning_ai_invt_trdg/web/src/tabs/ConfigTab.dom.test.tsx

116 lines
4.2 KiB
TypeScript

// @vitest-environment jsdom
import { beforeEach, describe, expect, it, vi } from 'vitest';
import { render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { ConfigTab } from './ConfigTab';
const {
authState,
fetchDynamicConfigItemsMock,
upsertDynamicConfigItemsMock
} = vi.hoisted(() => ({
authState: {
profile: { role: 'admin' } as any
},
fetchDynamicConfigItemsMock: vi.fn(),
upsertDynamicConfigItemsMock: vi.fn()
}));
vi.mock('../components/AuthContext', () => ({
useAuth: () => authState
}));
vi.mock('../lib/dynamicConfigApi', () => ({
fetchDynamicConfigItems: fetchDynamicConfigItemsMock,
upsertDynamicConfigItems: upsertDynamicConfigItemsMock
}));
describe('ConfigTab DOM behavior', () => {
beforeEach(() => {
authState.profile.role = 'admin';
fetchDynamicConfigItemsMock.mockReset();
upsertDynamicConfigItemsMock.mockReset();
fetchDynamicConfigItemsMock.mockResolvedValue([
{ key: 'BOT_MODE', value: 'enabled', description: 'Bot mode' },
{ key: 'API_KEY', value: 'masked', description: 'Secret key' }
]);
upsertDynamicConfigItemsMock.mockResolvedValue(undefined);
});
it('loads configs, supports edit/reset, and saves with success message', async () => {
const user = userEvent.setup();
render(<ConfigTab />);
await waitFor(() => {
expect(screen.getByDisplayValue('enabled')).toBeInTheDocument();
expect(screen.getByRole('button', { name: 'Commit Changes' })).toBeDisabled();
});
const modeTextarea = screen.getByDisplayValue('enabled');
await user.clear(modeTextarea);
await user.type(modeTextarea, 'disabled');
expect(screen.getByRole('button', { name: 'Commit Changes' })).toBeEnabled();
expect(screen.getByRole('button', { name: 'Abort Changes' })).toBeInTheDocument();
await user.click(screen.getByRole('button', { name: 'Abort Changes' }));
expect(screen.getByDisplayValue('enabled')).toBeInTheDocument();
const resetModeTextarea = screen.getByDisplayValue('enabled');
await user.clear(resetModeTextarea);
await user.type(resetModeTextarea, 'disabled');
await user.click(screen.getByRole('button', { name: 'Commit Changes' }));
await waitFor(() => {
expect(upsertDynamicConfigItemsMock).toHaveBeenCalledTimes(1);
expect(screen.getByText('SYNC COMPLETE')).toBeInTheDocument();
});
expect(upsertDynamicConfigItemsMock.mock.calls[0][0]).toEqual(
expect.arrayContaining([
expect.objectContaining({ key: 'BOT_MODE', value: 'disabled' }),
expect.objectContaining({ key: 'API_KEY', value: 'masked' })
])
);
}, 20000);
it('renders empty-state table when no config rows exist', async () => {
fetchDynamicConfigItemsMock.mockResolvedValueOnce([]);
render(<ConfigTab />);
await waitFor(() => {
expect(screen.getByText('Configuration Map Null')).toBeInTheDocument();
});
});
it('shows save error banner when upsert fails', async () => {
upsertDynamicConfigItemsMock.mockRejectedValueOnce(new Error('write failed'));
const user = userEvent.setup();
render(<ConfigTab />);
await waitFor(() => {
expect(screen.getByDisplayValue('enabled')).toBeInTheDocument();
});
const modeTextarea = screen.getByDisplayValue('enabled');
await user.clear(modeTextarea);
await user.type(modeTextarea, 'paused');
await user.click(screen.getByRole('button', { name: 'Commit Changes' }));
await waitFor(() => {
expect(screen.getByText('CRITICAL ERROR')).toBeInTheDocument();
expect(screen.getByText(/Sync failed: write failed/)).toBeInTheDocument();
});
}, 20000);
it('denies access to non-admin users without fetching dynamic config', () => {
authState.profile.role = 'user';
render(<ConfigTab />);
expect(screen.getByText(/Access Denied/i)).toBeInTheDocument();
expect(fetchDynamicConfigItemsMock).not.toHaveBeenCalled();
});
});