Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion jest.config.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ module.exports = {
transformIgnorePatterns: [
'node_modules/(?!(ol|@camptocamp/inkmap|@terrestris/*[a-z]*-util|d3-selection|color-*[a-z]*)|(rc-*[a-z]*)|' +
'filter-obj|query-string|decode-uri-component|split-on-first|shpjs/|rbush|quickselect|geostyler-openlayers-parser|' +
'geostyler-style|geotiff|quick-lru|quickselect|jsts)'
'geostyler-style|geotiff|pbf|quick-lru|quickselect|jsts)'
],
setupFiles: [
'<rootDir>/jest/__mocks__/matchMediaMock.js'
Expand Down
145 changes: 145 additions & 0 deletions src/BackgroundLayerChooser/BackgroundLayerChooser.spec.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
import OlLayer from 'ol/layer/Layer';
import OlLayerTile from 'ol/layer/Tile';
import OlMap from 'ol/Map';
import OlSourceOsm from 'ol/source/OSM';
import OlLayerImage from 'ol/layer/Image';
import OlLayerGroup from 'ol/layer/Group';
import OlSourceImageWMS from 'ol/source/ImageWMS';

import React from 'react';
import { render, fireEvent, screen, waitFor } from '@testing-library/react';

import TestUtil from '../Util/TestUtil';
import BackgroundLayerChooser from './BackgroundLayerChooser';

describe('BackgroundLayerChooser', () => {
let map: OlMap;
let layers: OlLayer[];

beforeEach(() => {
layers = [
new OlLayerTile({
source: new OlSourceOsm()
}),
new OlLayerTile({
source: new OlSourceOsm()
})
];
layers[0].set('name', 'Layer 1');
layers[1].set('name', 'Layer 2');
map = TestUtil.createMap();
map.addLayer(layers[0]);
map.addLayer(layers[1]);
});

afterEach(() => {
map?.dispose();
layers = [];
});
it('renders button and preview', () => {
const { container } = render(<BackgroundLayerChooser layers={layers as any} />);
expect(container.querySelector('.bg-layer-chooser')).toBeInTheDocument();
expect(container.querySelector('.bg-preview')).toBeInTheDocument();
expect(container.querySelector('#overview-map')).toBeInTheDocument();
});

it('shows layer options when button is clicked', () => {
const { container } = render(<BackgroundLayerChooser layers={layers as any} />);
fireEvent.click(container.querySelector('.bg-layer-chooser') as HTMLElement);
waitFor(() => {
expect(container.querySelectorAll('.bg-preview').length).toBe(2);
});
});

it('selects a layer and updates preview', () => {
const { container } = render(<BackgroundLayerChooser layers={layers as any} />);
fireEvent.click(container.querySelector('.bg-layer-chooser') as HTMLElement);
waitFor(() => {
expect(container.querySelectorAll('.bg-preview').length).toBe(2);
fireEvent.click(container.querySelectorAll('.bg-preview')[1]);
});
waitFor(() => {
expect(screen.getByText('Layer 1')).toBeInTheDocument();
expect(screen.getByText('Layer 2')).toBeInTheDocument();
});
});

it('renders no background button if allowEmptyBackground is true', () => {
const { container } = render(<BackgroundLayerChooser layers={layers as any} allowEmptyBackground />);
fireEvent.click(container.querySelector('.bg-layer-chooser') as HTMLElement);
waitFor(() => {
expect(screen.getByText('No Background')).toBeInTheDocument();
});
});

it('selects no background and updates preview', () => {
const { container } = render(<BackgroundLayerChooser layers={layers as any} allowEmptyBackground />);
fireEvent.click(container.querySelector('.bg-layer-chooser') as HTMLElement);
waitFor(() => {
const noBgButtons = screen.getAllByText('No Background');
fireEvent.click(noBgButtons[1]);
});
waitFor(() => {
expect(screen.getAllByText('No Background').length).toBeGreaterThan(0);
});
});

it('uses titleRenderer if provided', () => {
const titleRenderer = (layer: any) => <span>Custom: {layer.get('name')}</span>;
render(<BackgroundLayerChooser layers={layers as any} titleRenderer={titleRenderer} />);
expect(screen.getByText('Custom: Layer 1')).toBeInTheDocument();
});

it('shows noBackgroundTitle if provided', async () => {
const noBackgroundTitle = 'Empty';
const { container } = render(<BackgroundLayerChooser layers={layers as any} allowEmptyBackground noBackgroundTitle={noBackgroundTitle} />);
fireEvent.click(container.querySelector('.change-bg-btn') as HTMLElement);
await waitFor(() => {
expect(screen.getByText(noBackgroundTitle)).toBeInTheDocument();
});
});

it('handles OlLayerImage as background', async () => {
const imageLayer = new OlLayerImage({
source: new OlSourceImageWMS({ url: 'test', params: {} })
});
imageLayer.set('name', 'Image Layer');
render(<BackgroundLayerChooser layers={[imageLayer] as any} />);
expect(screen.getByText('Image Layer')).toBeInTheDocument();
});

it('handles OlLayerGroup as background', async () => {
const groupLayer = new OlLayerGroup({
layers: [layers[0], layers[1]]
});
groupLayer.set('name', 'Group Layer');
render(<BackgroundLayerChooser layers={[groupLayer] as any} />);
expect(screen.getByText('Group Layer')).toBeInTheDocument();
});

it('toggles layerOptionsVisible state on button click', async () => {
const { container } = render(<BackgroundLayerChooser layers={layers as any} />);
const btn = container.querySelector('.change-bg-btn') as HTMLElement;
expect(container.querySelector('.layer-cards')).not.toBeInTheDocument();
fireEvent.click(btn);
await waitFor(() => {
expect(container.querySelector('.layer-cards')).toBeInTheDocument();
});
fireEvent.click(btn);
await waitFor(() => {
expect(container.querySelector('.layer-cards')).not.toBeInTheDocument();
});
});

it('sets selectedLayer to undefined when no background is selected', async () => {
const { container } = render(<BackgroundLayerChooser layers={layers as any} allowEmptyBackground />);
fireEvent.click(container.querySelector('.change-bg-btn') as HTMLElement);
await waitFor(() => {
const noBgButton = screen.getByText('No Background');
fireEvent.click(noBgButton);
});
await waitFor(() => {
expect(screen.getAllByText('No Background').length).toBeGreaterThan(0);
});
});
});
102 changes: 102 additions & 0 deletions src/BackgroundLayerPreview/BackgroundLayerPreview.spec.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
import React from 'react';
import { render, fireEvent, screen, waitFor } from '@testing-library/react';
import OlLayerTile from 'ol/layer/Tile';
import OlSourceOsm from 'ol/source/OSM';
import OlMap from 'ol/Map';

import TestUtil from '../Util/TestUtil';
import BackgroundLayerPreview from './BackgroundLayerPreview';

describe('BackgroundLayerPreview', () => {
let map: OlMap;
let layer: OlLayerTile;

beforeEach(() => {
layer = new OlLayerTile({ source: new OlSourceOsm() });
layer.set('name', 'Test Layer');
map = TestUtil.createMap();
map.addLayer(layer);
});

it('renders with default props', () => {
const { container } = render(
<BackgroundLayerPreview
layer={layer}
onClick={jest.fn()}
backgroundLayerFilter={() => true}
/>
);
expect(screen.getByText('Test Layer')).toBeInTheDocument();
expect(container.querySelector('.map')).toBeInTheDocument();
});

it('calls onClick when clicked', () => {
const onClick = jest.fn();
render(
<BackgroundLayerPreview
layer={layer}
onClick={onClick}
backgroundLayerFilter={() => true}
/>
);
fireEvent.click(screen.getByText('Test Layer').closest('.layer-preview')!);
waitFor(() => {
expect(onClick).toHaveBeenCalled();
});
});

it('calls backgroundLayerFilter on mouse events', () => {
const filter = jest.fn(() => true);
render(
<BackgroundLayerPreview
layer={layer}
onClick={jest.fn()}
backgroundLayerFilter={filter}
/>
);
const preview = screen.getByText('Test Layer').closest('.layer-preview')!;
fireEvent.mouseOver(preview);
fireEvent.mouseLeave(preview);
waitFor(() => {
expect(filter).toHaveBeenCalled();
});
});

it('renders custom title if titleRenderer is provided', () => {
render(
<BackgroundLayerPreview
layer={layer}
onClick={jest.fn()}
backgroundLayerFilter={() => true}
titleRenderer={l => <span>Custom: {l.get('name')}</span>}
/>
);
expect(screen.getByText('Custom: Test Layer')).toBeInTheDocument();
});

it('applies selected class if activeLayer matches', () => {
render(
<BackgroundLayerPreview
layer={layer}
activeLayer={layer}
onClick={jest.fn()}
backgroundLayerFilter={() => true}
/>
);
expect(screen.getByText('Test Layer').closest('.selected')).toBeInTheDocument();
});

it('renders with custom width and height', () => {
const { container } = render(
<BackgroundLayerPreview
layer={layer}
onClick={jest.fn()}
backgroundLayerFilter={() => true}
width={200}
height={150}
/>
);
const mapDiv = container.querySelector('.map');
expect(mapDiv).toHaveStyle({ width: '200px', height: '150px' });
});
});
78 changes: 78 additions & 0 deletions src/Button/DrawCutButton/DrawCutButton.spec.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import React from 'react';
import { render, fireEvent, screen, act, waitFor } from '@testing-library/react';
import DrawCutButton from './DrawCutButton';

describe('DrawCutButton', () => {
it('renders and toggles pressed state', () => {
render(<DrawCutButton pressed={false} />);
const btn = screen.getByRole('button');
expect(btn).toBeInTheDocument();
expect(btn).toHaveAttribute('aria-pressed', 'false');
});

it('shows Popconfirm after drawing', async () => {
render(<DrawCutButton pressed={true} />);
await act(async () => {
await new Promise(resolve => setTimeout(resolve, 10));
});
waitFor(() => {
expect(screen.getByText('Perform cut?')).toBeInTheDocument();
expect(screen.getByRole('button')).toBeDisabled();
});
});

it('calls onCutEnd when provided', async () => {
const onCutEnd = jest.fn();
render(<DrawCutButton pressed={true} onCutEnd={onCutEnd} />);
await act(async () => {
await new Promise(resolve => setTimeout(resolve, 10));
});
waitFor(() => {
expect(screen.getByText('OK')).toBeInTheDocument();
fireEvent.click(screen.getByText('OK'));
});
waitFor(() => {
expect(screen.queryByText('Perform cut?')).not.toBeInTheDocument();
});
});

it('calls Popconfirm cancel', async () => {
render(<DrawCutButton pressed={true} />);
await act(async () => {
await new Promise(resolve => setTimeout(resolve, 10));
});
waitFor(() => {
expect(screen.getByText('Canceö')).toBeInTheDocument();
fireEvent.click(screen.getByText('Cancel'));
});
expect(screen.queryByText('Perform cut?')).not.toBeInTheDocument();
});

it('applies custom className and popConfirmText', () => {
render(
<DrawCutButton
pressed={false}
className="my-custom"
popConfirmText="Are you sure?"
/>
);
const btn = screen.getByRole('button');
expect(btn.className).toMatch(/my-custom/);
});

it('passes popConfirmProps to Popconfirm', async () => {
render(
<DrawCutButton
pressed={true}
popConfirmProps={{ okText: 'Yes', cancelText: 'No' }}
/>
);
await act(async () => {
await new Promise(resolve => setTimeout(resolve, 10));
});
waitFor(() => {
expect(screen.getByText('Yes')).toBeInTheDocument();
expect(screen.getByText('No')).toBeInTheDocument();
})
});
});
Loading