test: added tests for the warningSidebar
ref: N25B-450
This commit is contained in:
@@ -117,10 +117,6 @@ function WarningListItem(props: { warning: EditorWarning }) {
|
||||
|
||||
<div className={styles.meta}>
|
||||
{props.warning.type}
|
||||
{/*{props.warning.scope.id}*/}
|
||||
{/*{props.warning.scope.handleId && (*/}
|
||||
{/* <span className={styles.handle}>@{props.warning.scope.handleId}</span>*/}
|
||||
{/*)}*/}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -0,0 +1,159 @@
|
||||
import {fireEvent, render, screen} from '@testing-library/react';
|
||||
import '@testing-library/jest-dom';
|
||||
import {useReactFlow, useStoreApi} from "@xyflow/react";
|
||||
import {
|
||||
type EditorWarning,
|
||||
globalWarning
|
||||
} from "../../../../../src/pages/VisProgPage/visualProgrammingUI/components/EditorWarnings.tsx";
|
||||
import {WarningsSidebar} from "../../../../../src/pages/VisProgPage/visualProgrammingUI/components/WarningSidebar.tsx";
|
||||
import useFlowStore from "../../../../../src/pages/VisProgPage/visualProgrammingUI/VisProgStores.tsx";
|
||||
|
||||
|
||||
jest.mock('@xyflow/react', () => ({
|
||||
useReactFlow: jest.fn(),
|
||||
useStoreApi: jest.fn(),
|
||||
}));
|
||||
|
||||
jest.mock('../../../../../src/pages/VisProgPage/visualProgrammingUI/VisProgStores.tsx');
|
||||
|
||||
function makeWarning(
|
||||
overrides?: Partial<EditorWarning>
|
||||
): EditorWarning {
|
||||
return {
|
||||
scope: { id: 'node-1' },
|
||||
type: 'MISSING_INPUT',
|
||||
severity: 'ERROR',
|
||||
description: 'Missing input',
|
||||
...overrides,
|
||||
};
|
||||
}
|
||||
|
||||
describe('WarningsSidebar', () => {
|
||||
let getStateSpy: jest.SpyInstance;
|
||||
|
||||
const setCenter = jest.fn(() => Promise.resolve());
|
||||
const getNode = jest.fn();
|
||||
const addSelectedNodes = jest.fn();
|
||||
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
|
||||
// React Flow hooks
|
||||
(useReactFlow as jest.Mock).mockReturnValue({
|
||||
getNode,
|
||||
setCenter,
|
||||
});
|
||||
(useStoreApi as jest.Mock).mockReturnValue({
|
||||
getState: () => ({ addSelectedNodes }),
|
||||
});
|
||||
|
||||
// Use spyOn to override store
|
||||
const mockWarnings = [
|
||||
makeWarning({ description: 'Node warning', scope: { id: 'node-1' } }),
|
||||
makeWarning({
|
||||
description: 'Global warning',
|
||||
scope: { id: globalWarning },
|
||||
type: 'INCOMPLETE_PROGRAM',
|
||||
severity: 'WARNING',
|
||||
}),
|
||||
makeWarning({
|
||||
description: 'Info warning',
|
||||
scope: { id: 'node-2' },
|
||||
severity: 'INFO',
|
||||
}),
|
||||
];
|
||||
|
||||
getStateSpy = jest
|
||||
.spyOn(useFlowStore, 'getState')
|
||||
.mockReturnValue({
|
||||
getWarnings: () => mockWarnings,
|
||||
} as any);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
getStateSpy.mockRestore();
|
||||
});
|
||||
|
||||
it('renders warnings header', () => {
|
||||
render(<WarningsSidebar />);
|
||||
expect(screen.getByText('Warnings')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('renders all warning descriptions', () => {
|
||||
render(<WarningsSidebar />);
|
||||
expect(screen.getByText('Node warning')).toBeInTheDocument();
|
||||
expect(screen.getByText('Global warning')).toBeInTheDocument();
|
||||
expect(screen.getByText('Info warning')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('splits global and other warnings correctly', () => {
|
||||
render(<WarningsSidebar />);
|
||||
expect(screen.getByText('global:')).toBeInTheDocument();
|
||||
expect(screen.getByText('other:')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('shows empty state when no warnings exist', () => {
|
||||
getStateSpy.mockReturnValueOnce({
|
||||
getWarnings: () => [],
|
||||
} as any);
|
||||
|
||||
render(<WarningsSidebar />);
|
||||
expect(screen.getByText('No warnings!')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('filters by severity', () => {
|
||||
render(<WarningsSidebar />);
|
||||
fireEvent.click(screen.getByText('ERROR'));
|
||||
|
||||
expect(screen.getByText('Node warning')).toBeInTheDocument();
|
||||
expect(screen.queryByText('Global warning')).not.toBeInTheDocument();
|
||||
expect(screen.queryByText('Info warning')).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('filters INFO severity correctly', () => {
|
||||
render(<WarningsSidebar />);
|
||||
fireEvent.click(screen.getByText('INFO'));
|
||||
|
||||
expect(screen.getByText('Info warning')).toBeInTheDocument();
|
||||
expect(screen.queryByText('Node warning')).not.toBeInTheDocument();
|
||||
expect(screen.queryByText('Global warning')).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('clicking node warning jumps to node', async () => {
|
||||
getNode.mockReturnValue({
|
||||
id: 'node-1',
|
||||
position: { x: 100, y: 200 },
|
||||
width: 50,
|
||||
height: 50,
|
||||
});
|
||||
|
||||
render(<WarningsSidebar />);
|
||||
fireEvent.click(screen.getByText('Node warning'));
|
||||
|
||||
expect(setCenter).toHaveBeenCalledWith(
|
||||
125,
|
||||
225,
|
||||
expect.objectContaining({ zoom: 2 })
|
||||
);
|
||||
|
||||
await Promise.resolve();
|
||||
expect(addSelectedNodes).toHaveBeenCalledWith(['node-1']);
|
||||
});
|
||||
|
||||
it('clicking global warning does NOT jump', () => {
|
||||
render(<WarningsSidebar />);
|
||||
fireEvent.click(screen.getByText('Global warning'));
|
||||
|
||||
expect(setCenter).not.toHaveBeenCalled();
|
||||
expect(addSelectedNodes).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('does nothing if node does not exist', () => {
|
||||
getNode.mockReturnValue(undefined);
|
||||
|
||||
render(<WarningsSidebar />);
|
||||
fireEvent.click(screen.getByText('Node warning'));
|
||||
|
||||
expect(setCenter).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user