Skip to content

Commit 0bedc71

Browse files
authored
Merge pull request #1931 from terrestris/unittest-context-menu
test: add unittest for LayerTreeContextMenu
2 parents 249ce9a + 18977e1 commit 0bedc71

File tree

1 file changed

+229
-3
lines changed

1 file changed

+229
-3
lines changed
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,235 @@
1-
import LayerTreeContextMenu from './index';
1+
import React from 'react';
2+
3+
import {
4+
fireEvent,
5+
render,
6+
waitFor,
7+
screen
8+
} from '@testing-library/react';
9+
10+
import { Extent } from 'ol/extent';
11+
import OlTileLayer from 'ol/layer/Tile';
12+
import OlTileWMS from 'ol/source/TileWMS';
13+
14+
import { Provider } from 'react-redux';
15+
16+
import { useMap } from '@terrestris/react-util/dist/Hooks/useMap/useMap';
17+
18+
import {
19+
EditLevel,
20+
setFeature
21+
} from '../../../../store/editFeature';
22+
import { show } from '../../../../store/layerDetailsModal';
23+
import { store } from '../../../../store/store';
24+
25+
import {
26+
LayerTreeContextMenu,
27+
LayerTreeContextMenuProps
28+
} from './index';
29+
30+
let mockAllowedEditMode: EditLevel[];
31+
let mockLayer: OlTileLayer<OlTileWMS>;
32+
let defaultProps: LayerTreeContextMenuProps;
33+
34+
jest.mock('../../../../hooks/useAppSelector', () => ({
35+
__esModule: true,
36+
default: jest.fn()
37+
}));
38+
39+
jest.mock('@terrestris/react-util/dist/Hooks/useMap/useMap', () => ({
40+
useMap: jest.fn()
41+
}));
42+
43+
jest.mock('@terrestris/ol-util/dist/LayerUtil/LayerUtil', () => ({
44+
getExtentForLayer: jest.fn()
45+
}));
46+
47+
jest.spyOn(store, 'dispatch');
248

349
describe('<LayerTreeContextMenu />', () => {
50+
beforeEach(() => {
51+
mockLayer = new OlTileLayer({
52+
source: new OlTileWMS({
53+
url: 'https://shogun2022.intranet.terrestris.de/geoserver/ows?',
54+
params: {
55+
LAYERS: ['some_layer'],
56+
useBearerToken: true
57+
}
58+
})
59+
});
60+
61+
defaultProps = {
62+
layer: mockLayer,
63+
visibleLegendsIds: [],
64+
setVisibleLegendsIds: jest.fn()
65+
};
66+
});
67+
68+
afterEach(() => {
69+
jest.resetAllMocks();
70+
});
71+
72+
it('renders the context menu button', () => {
73+
const { container } = render(
74+
<Provider store={store}>
75+
<LayerTreeContextMenu {...defaultProps} />
76+
</Provider>
77+
);
78+
79+
expect(container.querySelector('.ant-dropdown-trigger')).toBeInTheDocument();
80+
});
81+
82+
it('opens the dropdown menu when clicked', async () => {
83+
render(
84+
<Provider store={store}>
85+
<LayerTreeContextMenu {...defaultProps} />
86+
</Provider>
87+
);
88+
const triggerElem = document.querySelector('.ant-dropdown-trigger');
89+
await fireEvent.click(triggerElem as Element);
90+
91+
await waitFor(() => {
92+
expect(document.querySelector('.ant-dropdown')).not.toBeNull();
93+
});
94+
});
95+
96+
it('dispatches correct action when clicking "Edit Layer"', async () => {
97+
mockAllowedEditMode = ['CREATE'];
98+
jest.requireMock('../../../../hooks/useAppSelector').default.mockImplementation((callback: any) => callback({
99+
editFeature: {
100+
userEditMode: mockAllowedEditMode
101+
},
102+
layerTree: { metadataVisible: true }
103+
}));
104+
jest.spyOn(mockLayer, 'get').mockImplementation((key) => {
105+
if (key === 'editable') {
106+
return true;
107+
}
108+
return undefined;
109+
});
110+
111+
render(
112+
<Provider store={store}>
113+
<LayerTreeContextMenu {...defaultProps} />
114+
</Provider>
115+
);
116+
117+
const triggerElem = document.querySelector('.ant-dropdown-trigger');
118+
await fireEvent.click(triggerElem as Element);
119+
120+
await expect(mockLayer.get('editable')).toBe(true);
4121

5-
it('is defined', () => {
6-
expect(LayerTreeContextMenu).not.toBeUndefined();
122+
await waitFor(() => {
123+
expect(screen.getByText('LayerTreeContextMenu.editLayer')).toBeVisible();
124+
});
125+
126+
await fireEvent.click(screen.getByText('LayerTreeContextMenu.editLayer'));
127+
128+
await waitFor(() => {
129+
expect(store.dispatch).toHaveBeenCalledWith(setFeature(null));
130+
});
131+
});
132+
133+
it('dispatches correct action when clicking "Layer Details"', async () => {
134+
jest.requireMock('../../../../hooks/useAppSelector').default.mockImplementation((callback: any) => callback({
135+
editFeature: {
136+
userEditMode: mockAllowedEditMode
137+
},
138+
layerTree: { metadataVisible: true }
139+
}));
140+
render(
141+
<Provider store={store}>
142+
<LayerTreeContextMenu {...defaultProps} />
143+
</Provider>
144+
);
145+
146+
const triggerElem = document.querySelector('.ant-dropdown-trigger');
147+
await fireEvent.click(triggerElem as Element);
148+
149+
await fireEvent.click(screen.getByText('LayerTreeContextMenu.layerDetails'));
150+
151+
await waitFor(() => {
152+
expect(store.dispatch).toHaveBeenCalledWith(show());
153+
});
7154
});
8155

156+
it('handles zoomToLayerExtent correctly', async () => {
157+
// eslint-disable-next-line @typescript-eslint/no-require-imports
158+
jest.spyOn(require('@terrestris/ol-util/dist/LayerUtil/LayerUtil'), 'getExtentForLayer').mockResolvedValue([0, 0, 10, 10] as Extent);
159+
(useMap as jest.Mock).mockReturnValue({
160+
getView: jest.fn().mockReturnValue({
161+
getProjection: jest.fn().mockReturnValue('EPSG:3857'),
162+
fit: jest.fn()
163+
})
164+
});
165+
render(
166+
<Provider store={store}>
167+
<LayerTreeContextMenu {...defaultProps} />
168+
</Provider>
169+
);
170+
171+
const triggerElem = document.querySelector('.ant-dropdown-trigger');
172+
await fireEvent.click(triggerElem as Element);
173+
174+
await waitFor(() => {
175+
expect(screen.getByText('LayerTreeContextMenu.layerZoomToExtent')).toBeVisible();
176+
});
177+
await fireEvent.click(screen.getByText('LayerTreeContextMenu.layerZoomToExtent'));
178+
179+
await waitFor(() => {
180+
expect(useMap()?.getView().fit).toHaveBeenCalled();
181+
});
182+
});
183+
184+
it('displays error notification if zoomToLayerExtent fails', async () => {
185+
// eslint-disable-next-line @typescript-eslint/no-require-imports
186+
jest.spyOn(require('@terrestris/ol-util/dist/LayerUtil/LayerUtil'), 'getExtentForLayer').mockRejectedValue(new Error('Zoom failed'));
187+
(useMap as jest.Mock).mockReturnValue({ getView: jest.fn(() => ({ fit: jest.fn() })) });
188+
189+
render(
190+
<Provider store={store}>
191+
<LayerTreeContextMenu {...defaultProps} />
192+
</Provider>
193+
);
194+
195+
const triggerElem = document.querySelector('.ant-dropdown-trigger');
196+
await fireEvent.click(triggerElem as Element);
197+
198+
await waitFor(() => {
199+
expect(screen.getByText('LayerTreeContextMenu.layerZoomToExtent')).toBeVisible();
200+
});
201+
202+
await fireEvent.click(screen.getByText('LayerTreeContextMenu.layerZoomToExtent'));
203+
await waitFor(() => {
204+
expect(screen.getByText('LayerTreeContextMenu.extentError')).toBeInTheDocument();
205+
});
206+
});
207+
208+
it('handles showLegend correctly', async () => {
209+
const mockSetVisibleLegendsIds = jest.fn();
210+
211+
render(
212+
<Provider store={store}>
213+
<LayerTreeContextMenu
214+
layer={mockLayer}
215+
visibleLegendsIds={[]}
216+
setVisibleLegendsIds={mockSetVisibleLegendsIds}
217+
/>
218+
</Provider>
219+
);
220+
221+
const triggerElem = document.querySelector('.ant-dropdown-trigger');
222+
await fireEvent.click(triggerElem as Element);
223+
224+
await waitFor(() => {
225+
expect(screen.getByText('LayerTreeContextMenu.showLegend')).toBeVisible();
226+
});
227+
228+
fireEvent.click(screen.getByText('LayerTreeContextMenu.showLegend'));
229+
230+
await waitFor(() => {
231+
expect(mockSetVisibleLegendsIds).toHaveBeenCalled();
232+
});
233+
234+
});
9235
});

0 commit comments

Comments
 (0)