Co-Study4Grid / frontend /src /App.datalist.test.tsx
github-actions[bot]
Deploy d568a7b
0643cf5
Raw
History Blame Contribute Delete
3.06 kB
import React from 'react';
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
import { render, screen, waitFor, act, cleanup } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import '@testing-library/jest-dom/vitest';
import App from './App';
// Reuse the basic mocks
vi.mock('./components/VisualizationPanel', () => ({
default: () => <div data-testid="visualization-panel"></div>
}));
vi.mock('./components/ActionFeed', () => ({ default: () => <div /> }));
vi.mock('./components/OverloadPanel', () => ({ default: () => <div /> }));
vi.mock('./hooks/usePanZoom', () => ({ usePanZoom: () => ({ viewBox: null, setViewBox: vi.fn() }) }));
const mockApi = vi.hoisted(() => ({
updateConfig: vi.fn().mockResolvedValue({ monitored_lines_count: 10, total_lines_count: 10 }),
getBranches: vi.fn().mockResolvedValue({ branches: [], name_map: {} }),
getVoltageLevels: vi.fn().mockResolvedValue({ voltage_levels: ['VL1'], name_map: {} }),
getNominalVoltages: vi.fn().mockResolvedValue({ mapping: {}, unique_kv: [63, 225] }),
getVoltageLevelSubstations: vi.fn().mockResolvedValue({ mapping: {} }),
getNetworkDiagram: vi.fn().mockResolvedValue({ svg: '<svg></svg>', metadata: null }),
getUserConfig: vi.fn().mockResolvedValue({ network_path: '/path', action_file_path: '/path' }),
getConfigFilePath: vi.fn().mockResolvedValue('/config'),
saveUserConfig: vi.fn().mockResolvedValue({}),
}));
vi.mock('./api', () => ({ api: mockApi }));
describe('Datalist performance clamping', () => {
beforeEach(() => {
vi.clearAllMocks();
});
afterEach(() => {
cleanup();
});
it('exposes all branches through the contingency multi-select dropdown', async () => {
// The legacy <datalist> input was replaced by a react-select
// multi-select (PR `claude/add-nk-contingency-support-hnMwD`),
// which renders an internal <input role="combobox">. The Chromium
// lockup from 1000+ <option> children no longer applies because
// react-select filters as the user types. Sanity-check that the
// combobox is wired up and opens its menu when focused.
const largeBranches = Array.from({ length: 150 }, (_, i) => `BRANCH_${i}`);
mockApi.getBranches.mockResolvedValue({ branches: largeBranches, name_map: {} });
render(<App />);
const loadBtn = screen.getByText('🔄 Load Study');
await act(async () => { await userEvent.click(loadBtn); });
await waitFor(() => {
expect(screen.getByText('⚡ Select Contingency')).toBeInTheDocument();
}, { timeout: 5000 });
const combobox = screen.getByRole('combobox');
expect(combobox).toBeInTheDocument();
await act(async () => { await userEvent.click(combobox); });
// Filtering on a unique substring narrows the menu to a single
// hit — guards that the option list is fed from ``branches``.
await act(async () => { await userEvent.type(combobox, 'BRANCH_42'); });
await waitFor(() => {
expect(screen.getByText('BRANCH_42')).toBeInTheDocument();
});
});
});