@eeacms/volto-accordion-block
Version:
volto-accordion-block: Volto accordion block
295 lines (271 loc) • 8.03 kB
JSX
import React from 'react';
import { render, fireEvent, screen } from '@testing-library/react';
import { Provider } from 'react-intl-redux';
import configureStore from 'redux-mock-store';
import { MemoryRouter } from 'react-router-dom';
import '@testing-library/jest-dom';
import Edit from './Edit';
import config from '@plone/volto/registry';
jest.mock('@plone/volto/components/manage/Blocks/Block/BlocksForm', () => ({
__esModule: true,
default: jest.fn(
({
children,
multiSelected,
onSelectBlock,
onChangeFormData,
properties,
}) => {
const blockList = properties.blocks
? Object.entries(properties.blocks)
: [];
return (
<div
data-testid={`blocks-form-${properties.title || 'untitled'}`}
data-multi-selected={(multiSelected || []).join(',')}
>
{blockList.map(([blockId, blockData], index) => (
<div key={blockId}>
<button
type="button"
aria-label={`Select ${blockId}`}
onClick={(e) => onSelectBlock?.(blockId, null, e)}
>
Select {blockId}
</button>
{typeof children === 'function'
? children(
{
child: blockData,
childId: blockId,
index,
},
<div>EditBlock</div>,
{
allowedBlocks: [],
block: blockId,
data: blockData,
id: blockId,
index,
onChangeBlock: jest.fn(),
onSelectBlock,
onChangeFormData,
properties,
selected: false,
type: blockData['@type'],
},
)
: null}
</div>
))}
</div>
);
},
),
}));
jest.mock('@plone/volto/components/manage/Form/BlocksToolbar', () => ({
__esModule: true,
default: () => <div>BlocksToolbar</div>,
}));
jest.mock('@plone/volto/components/manage/Form/BlockDataForm', () => ({
__esModule: true,
default: () => <div>BlockDataForm</div>,
}));
jest.mock('@plone/volto/components/manage/Sidebar/SidebarPortal', () => ({
__esModule: true,
default: ({ children }) => <div>{children}</div>,
}));
jest.mock('@plone/volto/helpers//Extensions', () => ({
withBlockExtensions: jest.fn((Component) => Component),
}));
jest.mock('@plone/volto/helpers/Blocks/Blocks', () => ({
emptyBlocksForm: jest.fn(),
getBlocksLayoutFieldname: () => 'blocks_layout',
}));
config.blocks.blocksConfig.accordion = {
...config.blocks.blocksConfig.accordion,
titleIcons: {
opened: {
rightPosition: 'chevron left',
leftPosition: 'chevron right',
},
closed: {
rightPosition: 'chevron down',
leftPosition: 'chevron down',
},
size: 'tiny',
iconComponent: 'SemanticIcon',
unfiltered: {
rightPosition: 'chevron left',
leftPosition: 'chevron right',
},
filtered: {
rightPosition: 'chevron down',
leftPosition: 'chevron down',
},
},
};
const mockStore = configureStore();
const store = mockStore({
intl: {
locale: 'en',
messages: {},
},
});
const mockData = {
'@type': 'accordion',
title: 'Accordion',
data: {
blocks: {
1: {
'@type': 'accordionPanel',
title: 'Panel 1',
blocks: {
block1: {
'@type': 'text',
},
block2: {
'@type': 'text',
},
},
blocks_layout: {
items: ['block1', 'block2'],
},
},
2: {
'@type': 'accordionPanel',
title: 'Panel 2',
blocks: {
block3: {
'@type': 'text',
},
block4: {
'@type': 'text',
},
},
blocks_layout: {
items: ['block3', 'block4'],
},
},
},
blocks_layout: {
items: ['1', '2'],
},
},
};
describe('Edit Component', () => {
beforeEach(() => {
jest.clearAllMocks();
});
it('renders the accordion title correctly', () => {
const onChangeBlock = jest.fn();
render(
<Provider store={store}>
<MemoryRouter>
<Edit data={mockData} onChangeBlock={onChangeBlock} />
</MemoryRouter>
</Provider>,
);
expect(screen.getByText('Accordion')).toBeInTheDocument();
});
it('renders the accordion panels correctly', () => {
const onChangeBlock = jest.fn();
render(
<Provider store={store}>
<MemoryRouter>
<Edit data={mockData} onChangeBlock={onChangeBlock} />
</MemoryRouter>
</Provider>,
);
expect(screen.getByDisplayValue('Panel 1')).toBeInTheDocument();
expect(screen.getByDisplayValue('Panel 2')).toBeInTheDocument();
});
it('calls onChangeBlock when the title changes', () => {
const onChangeBlock = jest.fn();
render(
<Provider store={store}>
<MemoryRouter>
<Edit data={mockData} onChangeBlock={onChangeBlock} />
</MemoryRouter>
</Provider>,
);
const titleInput = screen.getByDisplayValue('Panel 1');
fireEvent.change(titleInput, { target: { value: 'New Panel Title' } });
expect(onChangeBlock).toHaveBeenCalled();
});
it('filters the accordion panels based on the filter value', () => {
const onChangeBlock = jest.fn();
render(
<Provider store={store}>
<MemoryRouter>
<Edit
data={{ ...mockData, filtering: true }}
onChangeBlock={onChangeBlock}
/>
</MemoryRouter>
</Provider>,
);
const filterInput = screen.getByPlaceholderText('Type to filter...');
fireEvent.change(filterInput, { target: { value: 'Panel 1' } });
expect(screen.getByPlaceholderText('Enter Title')).toHaveDisplayValue(
'Panel 1',
);
expect(screen.queryByDisplayValue('Panel 2')).not.toBeInTheDocument();
});
it('renders the block toolbar when a block is selected', () => {
const onChangeBlock = jest.fn();
render(
<Provider store={store}>
<MemoryRouter>
<Edit data={mockData} selected={true} onChangeBlock={onChangeBlock} />
</MemoryRouter>
</Provider>,
);
expect(screen.getByText('BlocksToolbar')).toBeInTheDocument();
});
it('renders the block data form in the sidebar portal', () => {
const onChangeBlock = jest.fn();
render(
<Provider store={store}>
<MemoryRouter>
<Edit data={mockData} selected={true} onChangeBlock={onChangeBlock} />
</MemoryRouter>
</Provider>,
);
expect(screen.getByText('BlockDataForm')).toBeInTheDocument();
});
it('adds the disable-inner-buttons modifier when configured', () => {
const onChangeBlock = jest.fn();
render(
<Provider store={store}>
<MemoryRouter>
<Edit
data={{ ...mockData, disableInnerButtons: true }}
onChangeBlock={onChangeBlock}
/>
</MemoryRouter>
</Provider>,
);
expect(screen.getByText('Accordion').closest('fieldset')).toHaveClass(
'disable-inner-buttons',
);
});
it('forwards nested multi-selected blocks to BlocksForm', () => {
const onChangeBlock = jest.fn();
render(
<Provider store={store}>
<MemoryRouter>
<Edit data={mockData} selected={true} onChangeBlock={onChangeBlock} />
</MemoryRouter>
</Provider>,
);
fireEvent.click(screen.getByRole('button', { name: 'Select block1' }));
fireEvent.click(screen.getByRole('button', { name: 'Select block2' }), {
shiftKey: true,
});
expect(screen.getByTestId('blocks-form-Panel 1')).toHaveAttribute(
'data-multi-selected',
'block1,block2',
);
});
});