From 9dadc7989c24c184c55392a2c35db88c0c3e5361 Mon Sep 17 00:00:00 2001 From: Shailesh Parmar Date: Fri, 8 Apr 2022 04:21:06 +0530 Subject: [PATCH] UI: Add Unit test for AddWebhook component (#3911) Co-authored-by: Vivek Ratnavel Subramanian --- .../components/AddWebhook/AddWebhook.test.tsx | 400 ++++++++++++++++++ .../src/components/AddWebhook/AddWebhook.tsx | 18 +- 2 files changed, 410 insertions(+), 8 deletions(-) create mode 100644 openmetadata-ui/src/main/resources/ui/src/components/AddWebhook/AddWebhook.test.tsx diff --git a/openmetadata-ui/src/main/resources/ui/src/components/AddWebhook/AddWebhook.test.tsx b/openmetadata-ui/src/main/resources/ui/src/components/AddWebhook/AddWebhook.test.tsx new file mode 100644 index 00000000000..f18b57d3515 --- /dev/null +++ b/openmetadata-ui/src/main/resources/ui/src/components/AddWebhook/AddWebhook.test.tsx @@ -0,0 +1,400 @@ +/* + * Copyright 2021 Collate + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { + act, + findAllByText, + findByTestId, + findByText, + fireEvent, + queryByTestId, + queryByText, + render, +} from '@testing-library/react'; +import React from 'react'; +import { MemoryRouter } from 'react-router'; +import { FormSubmitType } from '../../enums/form.enum'; +import { Webhook } from '../../generated/entity/events/webhook'; +import AddWebhook from './AddWebhook'; +import { AddWebhookProps } from './AddWebhook.interface'; + +jest.mock( + '../containers/PageLayout', + () => + ({ + children, + rightPanel, + }: { + children: React.ReactNode; + rightPanel: React.ReactNode; + }) => + ( +
+
{rightPanel}
+ {children} +
+ ) +); + +const mockDropdownFunction = jest.fn().mockImplementation((fn) => { + fn('event', 'test'); +}); + +jest.mock('../dropdown/DropDown', () => { + return jest + .fn() + .mockImplementation(({ onSelect }) => ( +

mockDropdownFunction(onSelect)}>DropDown.component

+ )); +}); + +jest.mock('../buttons/CopyToClipboardButton/CopyToClipboardButton', () => { + return jest + .fn() + .mockImplementation(() =>

CopyToClipboardButton.component

); +}); + +jest.mock('../common/editor/MarkdownWithPreview', () => { + return jest + .fn() + .mockImplementation(() =>

MarkdownWithPreview.component

); +}); + +jest.mock('../Modals/ConfirmationModal/ConfirmationModal', () => { + return jest.fn().mockImplementation(({ onCancel, onConfirm }) => ( +
+

ConfirmationModal.component

+ + +
+ )); +}); + +const mockData = { + id: 'c0a00c5a-4687-4508-b23d-ab9a2996a8e0', + name: 'test hook', + endpoint: 'http://test.com', + eventFilters: [ + { + eventType: 'entityCreated', + entities: ['*'], + }, + ], + batchSize: 10, + timeout: 10, + enabled: true, + secretKey: 'Lgo71tlvzAyQYm2U1Al3wxmU86SGkJ2ceHtRUsZN2BCwW97RfT', + version: 0.1, + updatedAt: 1649319208832, + updatedBy: 'anonymous', + status: 'active', + href: 'http://localhost:8585/api/v1/webhook/c0a00c5a-4687-4508-b23d-ab9a2996a8e0', + deleted: false, +}; + +const addWebhookProps: AddWebhookProps = { + header: 'add webhook', + mode: FormSubmitType.ADD, + onCancel: jest.fn(), + onSave: jest.fn(), + onDelete: jest.fn(), + saveState: 'initial', + deleteState: 'initial', + allowAccess: true, +}; + +describe('Test AddWebhook component', () => { + it('Component should render properly', async () => { + const { container } = render(, { + wrapper: MemoryRouter, + }); + + const pageLayout = await findByTestId(container, 'PageLayout'); + const rightPanel = await findByTestId(container, 'right-panel-content'); + const header = await findByTestId(container, 'header'); + const formContainer = await findByTestId(container, 'formContainer'); + const nameField = await findByTestId(container, 'name'); + const markdownWithPreview = await findByText( + container, + /MarkdownWithPreview.component/i + ); + const endpointUrl = await findByTestId(container, 'endpoint-url'); + const active = await findByTestId(container, 'active'); + const entityCreatedCheckbox = await findByTestId( + container, + 'entity-created-checkbox' + ); + const entityUpdatedCheckbox = await findByTestId( + container, + 'entity-updated-checkbox' + ); + const entityDeletedCheckbox = await findByTestId( + container, + 'entity-deleted-checkbox' + ); + const showAdvancedButton = await findByTestId(container, 'show-advanced'); + const cancelWebhook = await findByTestId(container, 'cancel-webhook'); + const saveWebhook = await findByTestId(container, 'save-webhook'); + const dropdown = await findAllByText(container, /DropDown.component/i); + + expect(pageLayout).toBeInTheDocument(); + expect(rightPanel).toBeInTheDocument(); + expect(header).toBeInTheDocument(); + expect( + await findByText(container, addWebhookProps.header) + ).toBeInTheDocument(); + expect(formContainer).toBeInTheDocument(); + expect(nameField).toBeInTheDocument(); + expect(markdownWithPreview).toBeInTheDocument(); + expect(endpointUrl).toBeInTheDocument(); + expect(active).toBeInTheDocument(); + expect(entityCreatedCheckbox).toBeInTheDocument(); + expect(entityUpdatedCheckbox).toBeInTheDocument(); + expect(entityDeletedCheckbox).toBeInTheDocument(); + expect(showAdvancedButton).toBeInTheDocument(); + expect(cancelWebhook).toBeInTheDocument(); + expect(saveWebhook).toBeInTheDocument(); + expect(dropdown.length).toBe(3); + }); + + it('Input fields should work properly', async () => { + const { container } = render(, { + wrapper: MemoryRouter, + }); + + const endpointUrl = await findByTestId(container, 'endpoint-url'); + const nameField = await findByTestId(container, 'name'); + const active = await findByTestId(container, 'active'); + const entityCreatedCheckbox = await findByTestId( + container, + 'entity-created-checkbox' + ); + const entityUpdatedCheckbox = await findByTestId( + container, + 'entity-updated-checkbox' + ); + const entityDeletedCheckbox = await findByTestId( + container, + 'entity-deleted-checkbox' + ); + const dropdown = await findAllByText(container, /DropDown.component/i); + const saveWebhook = await findByTestId(container, 'save-webhook'); + const cancelWebhook = await findByTestId(container, 'cancel-webhook'); + + fireEvent.click(saveWebhook); + + expect( + await findByText(container, 'Webhook name is required.') + ).toBeInTheDocument(); + expect( + await findByText(container, 'Webhook endpoint is required.') + ).toBeInTheDocument(); + expect( + await findByText(container, 'Webhook event filters are required.') + ).toBeInTheDocument(); + expect(active).toHaveClass('open'); + expect(entityCreatedCheckbox).not.toBeChecked(); + expect(entityUpdatedCheckbox).not.toBeChecked(); + expect(entityDeletedCheckbox).not.toBeChecked(); + + fireEvent.change(nameField, { + target: { + value: 'name field', + }, + }); + fireEvent.change(endpointUrl, { + target: { + value: 'http://test.com', + }, + }); + fireEvent.click(active); + fireEvent.click(entityCreatedCheckbox); + fireEvent.click(entityUpdatedCheckbox); + fireEvent.click(entityDeletedCheckbox); + fireEvent.click(dropdown[0]); + fireEvent.click(dropdown[1]); + fireEvent.click(dropdown[2]); + + expect(nameField).toHaveValue('name field'); + expect(endpointUrl).toHaveValue('http://test.com'); + expect(active).not.toHaveClass('open'); + expect(entityCreatedCheckbox).toBeChecked(); + expect(entityUpdatedCheckbox).toBeChecked(); + expect(entityDeletedCheckbox).toBeChecked(); + expect(mockDropdownFunction).toBeCalledTimes(3); + + fireEvent.click(saveWebhook); + fireEvent.click(cancelWebhook); + + expect(addWebhookProps.onSave).toBeCalledTimes(1); + expect(addWebhookProps.onCancel).toBeCalledTimes(1); + }); + + it('onClick of show advance config, appropriate field should be visible', async () => { + await act(async () => { + const { container } = render(, { + wrapper: MemoryRouter, + }); + + const showAdvancedButton = await findByTestId(container, 'show-advanced'); + + expect(showAdvancedButton).toBeInTheDocument(); + + fireEvent.click(showAdvancedButton); + + // advance config fields tests + const batchSize = await findByTestId(container, 'batch-size'); + const connectionTimeout = await findByTestId( + container, + 'connection-timeout' + ); + const secretKey = await findByTestId(container, 'secret-key'); + const generateSecretButtom = await findByTestId( + container, + 'generate-secret' + ); + + expect(batchSize).toBeInTheDocument(); + expect(connectionTimeout).toBeInTheDocument(); + expect(secretKey).toBeInTheDocument(); + expect(secretKey).toHaveValue(''); + expect(secretKey).toHaveAttribute('readOnly'); + expect(generateSecretButtom).toBeInTheDocument(); + + fireEvent.change(batchSize, { + target: { + value: 'batchSize', + }, + }); + fireEvent.change(connectionTimeout, { + target: { + value: 'connectionTimeout', + }, + }); + + // string should not added as its number feild + expect(batchSize).not.toHaveValue('batchSize'); + expect(connectionTimeout).not.toHaveValue('connectionTimeout'); + + fireEvent.change(batchSize, { + target: { + value: 10, + }, + }); + fireEvent.change(connectionTimeout, { + target: { + value: 10, + }, + }); + + expect(batchSize).toHaveValue(10); + expect(connectionTimeout).toHaveValue(10); + }); + }); + + it('secret key generation should work properly', async () => { + await act(async () => { + const { container } = render(, { + wrapper: MemoryRouter, + }); + jest.useFakeTimers(); + + const showAdvancedButton = await findByTestId(container, 'show-advanced'); + + expect(showAdvancedButton).toBeInTheDocument(); + + fireEvent.click(showAdvancedButton); + + const secretKey = await findByTestId(container, 'secret-key'); + const generateSecretButtom = await findByTestId( + container, + 'generate-secret' + ); + + expect(secretKey).toHaveValue(''); + expect( + queryByText(container, 'CopyToClipboardButton.component') + ).not.toBeInTheDocument(); + expect(queryByTestId(container, 'clear-secret')).not.toBeInTheDocument(); + + fireEvent.click(generateSecretButtom); + jest.runAllTimers(); + + expect(secretKey).toHaveValue(); + expect( + await findByText(container, 'CopyToClipboardButton.component') + ).toBeInTheDocument(); + expect(await findByTestId(container, 'clear-secret')).toBeInTheDocument(); + + // onClick of delete secret test + fireEvent.click(await findByTestId(container, 'clear-secret')); + + expect( + queryByText(container, 'CopyToClipboardButton.component') + ).not.toBeInTheDocument(); + expect(queryByTestId(container, 'clear-secret')).not.toBeInTheDocument(); + expect(secretKey).toHaveValue(''); + }); + }); + + it('If data is provided, it should work accordingly', async () => { + await act(async () => { + const { container } = render( + , + { + wrapper: MemoryRouter, + } + ); + + const header = await findByTestId(container, 'header'); + const deleteWebhook = await findByTestId(container, 'delete-webhook'); + + expect(header).toBeInTheDocument(); + expect(await findByText(container, 'Edit Webhook')).toBeInTheDocument(); + expect(deleteWebhook).toBeInTheDocument(); + expect( + queryByText(container, 'ConfirmationModal.component') + ).not.toBeInTheDocument(); + + fireEvent.click(deleteWebhook); + + // on click of delete button confirmation modal should open + expect( + queryByText(container, 'ConfirmationModal.component') + ).toBeInTheDocument(); + + // on click of cancelModal confirmation modal should close + fireEvent.click(await findByText(container, 'cancelModal')); + + expect( + queryByText(container, 'ConfirmationModal.component') + ).not.toBeInTheDocument(); + + fireEvent.click(deleteWebhook); + + expect( + queryByText(container, 'ConfirmationModal.component') + ).toBeInTheDocument(); + + // on click of confirmDelete delete function should call + fireEvent.click(await findByText(container, 'confirmDelete')); + + expect(addWebhookProps.onDelete).toBeCalled(); + }); + }); +}); diff --git a/openmetadata-ui/src/main/resources/ui/src/components/AddWebhook/AddWebhook.tsx b/openmetadata-ui/src/main/resources/ui/src/components/AddWebhook/AddWebhook.tsx index e38af0af1b7..5be7c9dc4cb 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/AddWebhook/AddWebhook.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/AddWebhook/AddWebhook.tsx @@ -464,8 +464,10 @@ const AddWebhook: FunctionComponent = ({ classes="tw-max-w-full-hd tw-bg-white tw-pt-4" layout={PageLayoutType['2ColRTL']} rightPanel={fetchRightPanel()}> -
{header}
-
+
+ {header} +
+