From ec53971d38d4458d65ca3a627976054c8eeceef8 Mon Sep 17 00:00:00 2001
From: ana-oprea <80201759+ana-oprea@users.noreply.github.com>
Date: Fri, 8 Sep 2023 10:14:00 +0300
Subject: [PATCH] test: add unit tests - refs #254313
---
src/Widget/AttachedFileWidget.test.jsx | 129 ++++++++++++++
src/Widget/AttachedImageWidget.test.jsx | 187 ++++++++++++++++++++-
src/Widget/MappingWidget.test.jsx | 56 ++++++
src/Widget/ObjectByTypeWidget.test.jsx | 73 ++++++++
src/Widget/ObjectListInlineWidget.test.jsx | 152 +++++++++++++++++
src/demo/BlockEdit.test.jsx | 47 ++++++
6 files changed, 643 insertions(+), 1 deletion(-)
create mode 100644 src/Widget/AttachedFileWidget.test.jsx
create mode 100644 src/Widget/MappingWidget.test.jsx
create mode 100644 src/Widget/ObjectByTypeWidget.test.jsx
create mode 100644 src/Widget/ObjectListInlineWidget.test.jsx
create mode 100644 src/demo/BlockEdit.test.jsx
diff --git a/src/Widget/AttachedFileWidget.test.jsx b/src/Widget/AttachedFileWidget.test.jsx
new file mode 100644
index 0000000..4e735b4
--- /dev/null
+++ b/src/Widget/AttachedFileWidget.test.jsx
@@ -0,0 +1,129 @@
+import React from 'react';
+import { render, fireEvent, screen, waitFor } from '@testing-library/react';
+import '@testing-library/jest-dom/extend-expect';
+import AttachedFileWidget from './AttachedFileWidget';
+import { Provider } from 'react-intl-redux';
+import configureStore from 'redux-mock-store';
+
+jest.mock('promise-file-reader', () => ({
+ readAsDataURL: jest.fn(() =>
+ Promise.resolve('data:text/plain;base64,SGVsbG8sIFdvcmxkIQ=='),
+ ),
+}));
+
+const mockStore = configureStore([]);
+const store = mockStore({
+ intl: {
+ locale: 'en',
+ messages: {},
+ formatMessage: jest.fn(),
+ subrequests: {},
+ },
+ router: {
+ location: { pathname: '/test' },
+ subrequests: {},
+ },
+});
+
+describe('AttachedFileWidget', () => {
+ const mockOnChange = jest.fn();
+ const mockOpenObjectBrowser = jest.fn();
+
+ beforeEach(() => {
+ jest.clearAllMocks();
+ });
+
+ it('renders without crashing', () => {
+ const { container } = render(
+
+
+ ,
+ );
+ expect(container).toBeInTheDocument();
+ });
+
+ it('calls onChange when a file is dropped', async () => {
+ const { container } = render(
+
+
+ ,
+ );
+
+ let dropzone;
+ await waitFor(() => {
+ dropzone = container.querySelector('.file-widget-dropzone input');
+ expect(dropzone).toBeInTheDocument();
+ });
+ expect(dropzone).toBeInTheDocument();
+
+ const file = new File(['hello'], 'hello.png', { type: 'image/png' });
+ Object.defineProperty(dropzone, 'files', {
+ value: [file],
+ });
+ fireEvent.drop(dropzone);
+
+ await waitFor(() => expect(mockOnChange).toHaveBeenCalled());
+ });
+
+ it('calls onChange when delete button is clicked', () => {
+ render(
+
+
+ ,
+ );
+
+ const deleteButton = screen.getByLabelText('delete file');
+ fireEvent.click(deleteButton);
+
+ expect(mockOnChange).toHaveBeenCalledWith('testId', null);
+ });
+
+ it('renders without crashing', async () => {
+ const { container } = render(
+
+
+ ,
+ );
+
+ let dropzone;
+ await waitFor(() => {
+ dropzone = container.querySelector('.file-widget-dropzone input');
+ expect(dropzone).toBeInTheDocument();
+ });
+ expect(dropzone).toBeInTheDocument();
+ expect(container.querySelector('.file-picker-toolbar')).toBeInTheDocument();
+ expect(
+ container.querySelector('.file-picker-toolbar button'),
+ ).toBeInTheDocument();
+ fireEvent.change(container.querySelector('.input-toolbar input'), {
+ target: { value: 'test' },
+ });
+
+ fireEvent.click(
+ container.querySelector(
+ '.file-picker-toolbar button.ui.basic.icon.primary.button',
+ ),
+ );
+ });
+});
diff --git a/src/Widget/AttachedImageWidget.test.jsx b/src/Widget/AttachedImageWidget.test.jsx
index c5f3e67..d826022 100644
--- a/src/Widget/AttachedImageWidget.test.jsx
+++ b/src/Widget/AttachedImageWidget.test.jsx
@@ -1,5 +1,5 @@
import React from 'react';
-import { render, fireEvent } from '@testing-library/react';
+import { render, fireEvent, waitFor } from '@testing-library/react';
import { AttachedImageWidget } from './AttachedImageWidget';
import { Provider } from 'react-intl-redux';
import configureStore from 'redux-mock-store';
@@ -17,7 +17,20 @@ const store = mockStore({
messages: {},
formatMessage: jest.fn(),
},
+ content: {
+ subrequests: {},
+ },
+ router: {
+ location: { pathname: '/test' },
+ },
});
+
+jest.mock('promise-file-reader', () => ({
+ readAsDataURL: jest.fn(() =>
+ Promise.resolve('data:text/plain;base64,SGVsbG8sIFdvcmxkIQ=='),
+ ),
+}));
+
describe('AttachedImageWidget', () => {
const mockCreateContent = jest.fn();
const mockOpenObjectBrowser = jest.fn();
@@ -62,4 +75,176 @@ describe('AttachedImageWidget', () => {
expect(mockOnChange).toHaveBeenCalledWith('imageId', '');
});
+
+ it('should render the component and handle URL input and cancel button', async () => {
+ const { container } = render(
+
+
+ ,
+ );
+
+ let dropzone;
+ await waitFor(() => {
+ dropzone = container.querySelector('div[tabindex="0"]');
+ expect(dropzone).toBeInTheDocument();
+ });
+ expect(dropzone).toBeInTheDocument();
+
+ fireEvent.change(
+ container.querySelector('.toolbar-inner .ui.input input[type="text"]'),
+ { target: { value: 'test' } },
+ );
+ fireEvent.click(
+ container.querySelector(
+ '.toolbar-inner .ui.buttons button.ui.basic.icon.primary.button',
+ ),
+ );
+
+ fireEvent.change(
+ container.querySelector('.toolbar-inner .ui.input input[type="text"]'),
+ { target: { value: 'test' } },
+ );
+ fireEvent.click(
+ container.querySelector(
+ '.toolbar-inner .ui.buttons button.ui.basic.icon.secondary.button.cancel',
+ ),
+ );
+ });
+
+ it('should render the component handle object browser button click', async () => {
+ const { container } = render(
+
+
+ ,
+ );
+
+ let dropzone;
+ await waitFor(() => {
+ dropzone = container.querySelector('div[tabindex="0"]');
+ expect(dropzone).toBeInTheDocument();
+ });
+ expect(dropzone).toBeInTheDocument();
+
+ fireEvent.click(
+ container.querySelector('.toolbar-inner .ui.buttons button'),
+ );
+ });
+
+ it('should handle file input and rerender based on request loading and loaded states', async () => {
+ const { rerender, container } = render(
+
+
+ ,
+ );
+
+ let dropzone;
+ await waitFor(() => {
+ dropzone = container.querySelector('div[tabindex="0"]');
+ expect(dropzone).toBeInTheDocument();
+ });
+ expect(dropzone).toBeInTheDocument();
+
+ const file = new File(['hello'], 'hello.png', { type: 'image/png' });
+ Object.defineProperty(
+ container.querySelector('label[role="button"] input[type="file"]'),
+ 'files',
+ {
+ value: [file],
+ },
+ );
+ fireEvent.change(
+ container.querySelector('label[role="button"] input[type="file"]'),
+ { target: { value: '' } },
+ );
+
+ rerender(
+
+
+ ,
+ );
+
+ rerender(
+
+
+ ,
+ );
+ });
+
+ it('should handle file input via label button ', async () => {
+ const { container } = render(
+
+
+ ,
+ );
+
+ let dropzone;
+ await waitFor(() => {
+ dropzone = container.querySelector('div[tabindex="0"]');
+ expect(dropzone).toBeInTheDocument();
+ });
+ expect(dropzone).toBeInTheDocument();
+
+ const file = new File(['hello'], 'hello.png', { type: 'image/png' });
+ Object.defineProperty(
+ container.querySelector('label[role="button"] input[type="file"]'),
+ 'files',
+ {
+ value: [file],
+ },
+ );
+ fireEvent.change(
+ container.querySelector('label[role="button"] input[type="file"]'),
+ { target: { value: '' } },
+ );
+ });
+
+ it('should handle drag and drop events ', async () => {
+ const { container } = render(
+
+
+ ,
+ );
+
+ let dropzone;
+ await waitFor(() => {
+ dropzone = container.querySelector('div[tabindex="0"]');
+ expect(dropzone).toBeInTheDocument();
+ });
+ expect(dropzone).toBeInTheDocument();
+
+ const file = new File(['hello'], 'hello.png', { type: 'image/png' });
+ Object.defineProperty(dropzone, 'files', {
+ value: [file],
+ });
+ fireEvent.dragEnter(dropzone);
+ fireEvent.dragLeave(dropzone);
+ fireEvent.drop(dropzone);
+ });
});
diff --git a/src/Widget/MappingWidget.test.jsx b/src/Widget/MappingWidget.test.jsx
new file mode 100644
index 0000000..87fcb7a
--- /dev/null
+++ b/src/Widget/MappingWidget.test.jsx
@@ -0,0 +1,56 @@
+import React from 'react';
+import { render, fireEvent } from '@testing-library/react';
+import MappingWidget from './MappingWidget';
+import '@testing-library/jest-dom/extend-expect';
+
+jest.mock('@plone/volto/components', () => ({
+ Field: ({ id, value, onChange }) => (
+ onChange(id, e.target.value)}
+ />
+ ),
+}));
+
+describe('MappingWidget', () => {
+ beforeEach(() => {
+ jest.clearAllMocks();
+ });
+ const options = [
+ { id: 'option1', title: 'Option 1' },
+ { id: 'option2', title: 'Option 2' },
+ ];
+
+ it('renders without crashing', () => {
+ const { container } = render(
+ ,
+ );
+ expect(container).toBeTruthy();
+ });
+
+ it('renders correct number of fields', () => {
+ const { getAllByTestId } = render(
+ ,
+ );
+ expect(getAllByTestId(/field-/).length).toBe(2);
+ });
+
+ it('updates value on field change', () => {
+ const onChange = jest.fn();
+ const { getByTestId } = render(
+ ,
+ );
+
+ fireEvent.change(getByTestId('field-test-option1'), {
+ target: { value: 'new value' },
+ });
+
+ expect(onChange).toHaveBeenCalledWith('test', { option1: 'new value' });
+ });
+});
diff --git a/src/Widget/ObjectByTypeWidget.test.jsx b/src/Widget/ObjectByTypeWidget.test.jsx
new file mode 100644
index 0000000..a57f765
--- /dev/null
+++ b/src/Widget/ObjectByTypeWidget.test.jsx
@@ -0,0 +1,73 @@
+import React from 'react';
+import { render, fireEvent } from '@testing-library/react';
+import ObjectByTypeWidget from './ObjectByTypeWidget';
+import '@testing-library/jest-dom/extend-expect';
+
+jest.mock('@plone/volto/components', () => ({
+ Icon: ({ name }) =>
Icon
,
+ ObjectWidget: ({ id, onChange }) => (
+
+ ),
+}));
+
+describe('ObjectByTypeWidget', () => {
+ beforeEach(() => {
+ jest.clearAllMocks();
+ });
+ const schemas = [
+ { id: 'type1', schema: { title: 'Type 1' }, icon: 'icon1' },
+ { id: 'type2', schema: { title: 'Type 2' }, icon: 'icon2' },
+ ];
+
+ it('renders without crashing', () => {
+ const { container } = render(
+ ,
+ );
+ expect(container).toBeTruthy();
+ });
+
+ it('calls onChange', () => {
+ const { container } = render(
+ {}}
+ />,
+ );
+ expect(container).toBeTruthy();
+ fireEvent.change(container.querySelector('#objectwidget-type1'), {
+ target: { value: 'test' },
+ });
+ });
+
+ it('renders correct number of tabs', () => {
+ const { getAllByTestId } = render(
+ ,
+ );
+ expect(getAllByTestId(/icon-/).length).toBe(2);
+ });
+
+ it('renders ObjectWidget for active tab', () => {
+ const { getByTestId } = render(
+ ,
+ );
+ expect(getByTestId('objectwidget-type1')).toBeInTheDocument();
+ });
+
+ it('switches tab on click', () => {
+ const { getByTestId } = render(
+ ,
+ );
+
+ fireEvent.click(getByTestId('icon-icon2'));
+ expect(getByTestId('objectwidget-type2')).toBeInTheDocument();
+ });
+});
diff --git a/src/Widget/ObjectListInlineWidget.test.jsx b/src/Widget/ObjectListInlineWidget.test.jsx
new file mode 100644
index 0000000..88a108a
--- /dev/null
+++ b/src/Widget/ObjectListInlineWidget.test.jsx
@@ -0,0 +1,152 @@
+import React from 'react';
+import { render, fireEvent } from '@testing-library/react';
+import { Provider } from 'react-intl-redux';
+import ObjectListInlineWidget from './ObjectListInlineWidget';
+import configureStore from 'redux-mock-store';
+import '@testing-library/jest-dom/extend-expect';
+
+jest.mock('@plone/volto/components', () => ({
+ FormFieldWrapper: ({ children }) => {children}
,
+ DragDropList: ({ childList, onMoveItem, children }) => {
+ const draginfo = {
+ innerRef: jest.fn(),
+ draggableProps: jest.fn(),
+ dragHandleProps: jest.fn(),
+ };
+ return (
+
+
DragDropList
+ {childList.map((child, index) => (
+
{}}
+ onClick={() => {
+ onMoveItem({
+ source: { index: 0 },
+ destination: { index: 1 },
+ });
+ }}
+ >
+ {children({ child: child[1], childId: child[0], index, draginfo })}
+
+ ))}
+
+ );
+ },
+ ObjectWidget: ({ onChange }) => (
+
+ ),
+ Icon: () => VoltoIcon
,
+}));
+
+jest.mock('uuid', () => ({
+ v4: jest.fn(() => 'uuid'),
+}));
+
+const mockStore = configureStore([]);
+const store = mockStore({
+ intl: {
+ locale: 'en',
+ messages: {},
+ formatMessage: jest.fn(),
+ },
+});
+
+describe('ObjectListInlineWidget', () => {
+ beforeEach(() => {
+ jest.clearAllMocks();
+ });
+ it('renders without crashing', () => {
+ const { container } = render(
+
+ {}}
+ />
+ ,
+ );
+ expect(container).toBeTruthy();
+ });
+
+ it('renders Add button and adds an item on click', () => {
+ const onChange = jest.fn();
+ const { getByText } = render(
+
+
+ ,
+ );
+ fireEvent.click(getByText(`Add Test`));
+ expect(onChange).toHaveBeenCalledWith('test', [
+ {
+ '@id': 'uuid',
+ },
+ ]);
+ });
+
+ it('moves an item by calling onMoveItem', () => {
+ const onChange = jest.fn();
+ const { container } = render(
+
+
+ ,
+ );
+
+ fireEvent.click(container.querySelector('.dragdrop-list-item-mock'));
+ expect(onChange).toHaveBeenCalledWith('test', [
+ { '@id': '2' },
+ { '@id': '1' },
+ ]);
+ });
+
+ it('renders DragDropList', () => {
+ const { getByText } = render(
+
+
+ ,
+ );
+ expect(getByText('DragDropList')).toBeInTheDocument();
+ });
+
+ it('renders ObjectWidget', () => {
+ const onChange = jest.fn();
+ const { container, getByText } = render(
+
+ ({ title: 'ObjectWidget' })}
+ value={[{ '@id': '1' }]}
+ title="Tessst"
+ onChange={onChange}
+ />
+ ,
+ );
+ expect(getByText('ObjectWidget')).toBeInTheDocument();
+ expect(container.querySelector('.objectwidget-mock')).toBeInTheDocument();
+ fireEvent.change(container.querySelector('.objectwidget-mock input'), {
+ target: { value: 'test' },
+ });
+ });
+});
diff --git a/src/demo/BlockEdit.test.jsx b/src/demo/BlockEdit.test.jsx
new file mode 100644
index 0000000..a750679
--- /dev/null
+++ b/src/demo/BlockEdit.test.jsx
@@ -0,0 +1,47 @@
+import React from 'react';
+import { render, fireEvent } from '@testing-library/react';
+import BlockEdit from './BlockEdit';
+import '@testing-library/jest-dom/extend-expect';
+
+jest.mock('@plone/volto/components', () => ({
+ SidebarPortal: ({ children }) => {children}
,
+}));
+jest.mock('@plone/volto/components/manage/Form/InlineForm', () => (props) => (
+
+));
+
+describe('BlockEdit', () => {
+ it('renders without crashing', () => {
+ const { container } = render();
+ expect(container).toBeTruthy();
+ });
+
+ it('renders SidebarPortal when selected is false', () => {
+ const { queryByText } = render();
+ expect(queryByText('InlineForm')).toBeInTheDocument();
+ });
+
+ it('renders SidebarPortal when selected is true', () => {
+ const { getByText } = render();
+ expect(getByText('InlineForm')).toBeInTheDocument();
+ });
+
+ it('calls onSelectBlock when clicked', () => {
+ const onSelectBlock = jest.fn();
+ const { getByRole } = render();
+ fireEvent.click(getByRole('presentation'));
+ expect(onSelectBlock).toHaveBeenCalled();
+ });
+
+ it('calls onChangeBlock when onChangeField is called', () => {
+ const onChangeBlock = jest.fn();
+ const { container } = render();
+ fireEvent.change(container.querySelector('#inlineform'), {
+ target: { value: 'foo' },
+ });
+ expect(onChangeBlock).toHaveBeenCalled();
+ });
+});