diff --git a/openmetadata-ui/src/main/resources/ui/src/pages/SwaggerPage/index.test.tsx b/openmetadata-ui/src/main/resources/ui/src/pages/SwaggerPage/index.test.tsx
new file mode 100644
index 00000000000..b8919692b2f
--- /dev/null
+++ b/openmetadata-ui/src/main/resources/ui/src/pages/SwaggerPage/index.test.tsx
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2024 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 { render, screen } from '@testing-library/react';
+import React from 'react';
+import SwaggerPage from './index';
+
+jest.mock('./RapiDocReact', () => {
+ return jest.fn().mockImplementation((props) => (
+
+
RapiDocReact.component
+
{props['api-key-value']}
+
+ ));
+});
+
+describe('SwaggerPage component', () => {
+ it('renders SwaggerPage component correctly', async () => {
+ // Mocking localStorage.getItem method
+ const mockGetItem = jest.spyOn(window.localStorage.__proto__, 'getItem');
+ mockGetItem.mockReturnValue('fakeToken'); // Mocking the return value of getItem
+
+ render( );
+
+ expect(await screen.findByTestId('fluid-container')).toBeInTheDocument();
+ expect(
+ await screen.findByText('RapiDocReact.component')
+ ).toBeInTheDocument();
+ expect(await screen.findByText('Bearer fakeToken')).toBeInTheDocument();
+ });
+});
diff --git a/openmetadata-ui/src/main/resources/ui/src/pages/TableDetailsPageV1/FrequentlyJoinedTables/FrequentlyJoinedTables.component.tsx b/openmetadata-ui/src/main/resources/ui/src/pages/TableDetailsPageV1/FrequentlyJoinedTables/FrequentlyJoinedTables.component.tsx
index cda03031dbf..54956bb6e48 100644
--- a/openmetadata-ui/src/main/resources/ui/src/pages/TableDetailsPageV1/FrequentlyJoinedTables/FrequentlyJoinedTables.component.tsx
+++ b/openmetadata-ui/src/main/resources/ui/src/pages/TableDetailsPageV1/FrequentlyJoinedTables/FrequentlyJoinedTables.component.tsx
@@ -33,13 +33,19 @@ export const FrequentlyJoinedTables = ({
const { t } = useTranslation();
return (
-
+
{t('label.frequently-joined-table-plural')}
-
+
{joinedTables.map((table) => (
{
+ it('should render the component', async () => {
+ render( , {
+ wrapper: MemoryRouter,
+ });
+
+ expect(
+ await screen.findByTestId('frequently-joint-table-container')
+ ).toBeInTheDocument();
+ expect(
+ await screen.findByTestId('frequently-joint-data-container')
+ ).toBeInTheDocument();
+ expect(
+ await screen.findByText('label.frequently-joined-table-plural')
+ ).toBeInTheDocument();
+ });
+
+ it("should show the table's name and join count", async () => {
+ render( , {
+ wrapper: MemoryRouter,
+ });
+
+ expect(await screen.findByText('test')).toBeInTheDocument();
+ expect(await screen.findByText('1')).toBeInTheDocument();
+ });
+});
diff --git a/openmetadata-ui/src/main/resources/ui/src/pages/TasksPage/RequestDescriptionPage/RequestDescriptionPage.test.tsx b/openmetadata-ui/src/main/resources/ui/src/pages/TasksPage/RequestDescriptionPage/RequestDescriptionPage.test.tsx
new file mode 100644
index 00000000000..6fc80ae859d
--- /dev/null
+++ b/openmetadata-ui/src/main/resources/ui/src/pages/TasksPage/RequestDescriptionPage/RequestDescriptionPage.test.tsx
@@ -0,0 +1,141 @@
+/*
+ * Copyright 2024 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, fireEvent, render, screen } from '@testing-library/react';
+import React, { forwardRef } from 'react';
+import { postThread } from '../../../rest/feedsAPI';
+import RequestDescription from './RequestDescriptionPage';
+
+const mockUseHistory = {
+ push: jest.fn(),
+ goBack: jest.fn(),
+};
+jest.mock('react-router-dom', () => ({
+ ...jest.requireActual('react-router-dom'),
+ useParams: jest.fn().mockReturnValue({ entityType: 'table' }),
+ useLocation: jest
+ .fn()
+ .mockReturnValue({ search: 'field=columns&value="address.street_name"' }),
+ useHistory: jest.fn().mockImplementation(() => mockUseHistory),
+}));
+jest.mock('../../../components/common/ResizablePanels/ResizablePanels', () =>
+ jest.fn().mockImplementation(({ firstPanel, secondPanel }) => (
+ <>
+ {firstPanel.children}
+ {secondPanel.children}
+ >
+ ))
+);
+jest.mock('../../../utils/TasksUtils', () => ({
+ fetchEntityDetail: jest
+ .fn()
+ .mockImplementation((_entityType, _decodedEntityFQN, setEntityData) => {
+ setEntityData({
+ id: 'id1',
+ name: 'dim_location',
+ fullyQualifiedName: 'sample_data.ecommerce_db.shopify.dim_location',
+ tableType: 'Regular',
+ owner: {
+ id: 'id1',
+ name: 'sample_data',
+ type: 'User',
+ },
+ });
+ }),
+ fetchOptions: jest.fn(),
+ getBreadCrumbList: jest.fn().mockReturnValue([]),
+ getTaskMessage: jest.fn().mockReturnValue('Task message'),
+}));
+jest.mock('../shared/Assignees', () =>
+ jest.fn().mockImplementation(() => Assignees.component
)
+);
+jest.mock(
+ '../../../components/ExploreV1/ExploreSearchCard/ExploreSearchCard',
+ () =>
+ jest.fn().mockImplementation(() => ExploreSearchCard.component
)
+);
+jest.mock(
+ '../../../components/common/TitleBreadcrumb/TitleBreadcrumb.component',
+ () => jest.fn().mockImplementation(() => TitleBreadcrumb.component
)
+);
+jest.mock('../../../components/common/RichTextEditor/RichTextEditor', () =>
+ forwardRef(
+ jest.fn().mockImplementation(() => RichTextEditor.component
)
+ )
+);
+jest.mock('../../../rest/feedsAPI', () => ({
+ postThread: jest.fn().mockResolvedValue({}),
+}));
+jest.mock('../../../hooks/useFqn', () => ({
+ useFqn: jest
+ .fn()
+ .mockReturnValue({ fqn: 'sample_data.ecommerce_db.shopify.dim_location' }),
+}));
+
+describe('RequestDescriptionPage', () => {
+ it('should render component', async () => {
+ render( );
+
+ expect(
+ await screen.findByText('TitleBreadcrumb.component')
+ ).toBeInTheDocument();
+ expect(await screen.findByText('Assignees.component')).toBeInTheDocument();
+ expect(
+ await screen.findByText('RichTextEditor.component')
+ ).toBeInTheDocument();
+ expect(await screen.findByTestId('form-title')).toBeInTheDocument();
+ expect(await screen.findByTestId('form-container')).toBeInTheDocument();
+ expect(await screen.findByTestId('title')).toBeInTheDocument();
+ expect(await screen.findByTestId('cancel-btn')).toBeInTheDocument();
+ expect(await screen.findByTestId('submit-btn')).toBeInTheDocument();
+ });
+
+ it("should go back to previous page when 'Cancel' button is clicked", async () => {
+ render( );
+ const cancelBtn = await screen.findByTestId('cancel-btn');
+
+ act(() => {
+ fireEvent.click(cancelBtn);
+ });
+
+ expect(mockUseHistory.goBack).toHaveBeenCalled();
+ });
+
+ it('should submit form when submit button is clicked', async () => {
+ const mockPostThread = postThread as jest.Mock;
+ render( );
+ const submitBtn = await screen.findByTestId('submit-btn');
+
+ await act(async () => {
+ fireEvent.click(submitBtn);
+ });
+
+ expect(mockPostThread).toHaveBeenCalledWith({
+ about:
+ '<#E::table::sample_data.ecommerce_db.shopify.dim_location::columns::"address.street_name"::description>',
+ from: undefined,
+ message: 'Task message',
+ taskDetails: {
+ assignees: [
+ {
+ id: 'id1',
+ type: 'User',
+ },
+ ],
+ oldValue: '',
+ suggestion: undefined,
+ type: 'RequestDescription',
+ },
+ type: 'Task',
+ });
+ });
+});
diff --git a/openmetadata-ui/src/main/resources/ui/src/pages/TasksPage/RequestDescriptionPage/RequestDescriptionPage.tsx b/openmetadata-ui/src/main/resources/ui/src/pages/TasksPage/RequestDescriptionPage/RequestDescriptionPage.tsx
index 8adac5b74b2..ce59149b535 100644
--- a/openmetadata-ui/src/main/resources/ui/src/pages/TasksPage/RequestDescriptionPage/RequestDescriptionPage.tsx
+++ b/openmetadata-ui/src/main/resources/ui/src/pages/TasksPage/RequestDescriptionPage/RequestDescriptionPage.tsx
@@ -209,7 +209,11 @@ const RequestDescription = () => {
entity: t('label.task'),
})}
- {
className="w-full justify-end"
data-testid="cta-buttons"
size={16}>
-
+
{t('label.back')}
diff --git a/openmetadata-ui/src/main/resources/ui/src/pages/TasksPage/RequestTagPage/RequestTagPage.test.tsx b/openmetadata-ui/src/main/resources/ui/src/pages/TasksPage/RequestTagPage/RequestTagPage.test.tsx
new file mode 100644
index 00000000000..00fd24efd3b
--- /dev/null
+++ b/openmetadata-ui/src/main/resources/ui/src/pages/TasksPage/RequestTagPage/RequestTagPage.test.tsx
@@ -0,0 +1,141 @@
+/*
+ * Copyright 2024 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, fireEvent, render, screen } from '@testing-library/react';
+import React from 'react';
+import { MemoryRouter } from 'react-router-dom';
+import { postThread } from '../../../rest/feedsAPI';
+import RequestTag from './RequestTagPage';
+
+const mockUseHistory = {
+ push: jest.fn(),
+ goBack: jest.fn(),
+};
+jest.mock('react-router-dom', () => ({
+ ...jest.requireActual('react-router-dom'),
+ useParams: jest.fn().mockReturnValue({ entityType: 'table' }),
+ useLocation: jest
+ .fn()
+ .mockReturnValue({ search: 'field=columns&value="address.street_name"' }),
+ useHistory: jest.fn().mockImplementation(() => mockUseHistory),
+}));
+jest.mock('../../../components/common/ResizablePanels/ResizablePanels', () =>
+ jest.fn().mockImplementation(({ firstPanel, secondPanel }) => (
+ <>
+ {firstPanel.children}
+ {secondPanel.children}
+ >
+ ))
+);
+jest.mock('../../../utils/TasksUtils', () => ({
+ fetchEntityDetail: jest
+ .fn()
+ .mockImplementation((_entityType, _decodedEntityFQN, setEntityData) => {
+ setEntityData({
+ id: 'id1',
+ name: 'dim_location',
+ fullyQualifiedName: 'sample_data.ecommerce_db.shopify.dim_location',
+ tableType: 'Regular',
+ owner: {
+ id: 'id1',
+ name: 'sample_data',
+ type: 'User',
+ },
+ });
+ }),
+ fetchOptions: jest.fn(),
+ getBreadCrumbList: jest.fn().mockReturnValue([]),
+ getTaskMessage: jest.fn().mockReturnValue('Task message'),
+}));
+jest.mock('../shared/Assignees', () =>
+ jest.fn().mockImplementation(() => Assignees.component
)
+);
+jest.mock(
+ '../../../components/common/TitleBreadcrumb/TitleBreadcrumb.component',
+ () => jest.fn().mockImplementation(() => TitleBreadcrumb.component
)
+);
+jest.mock('../../../rest/feedsAPI', () => ({
+ postThread: jest.fn().mockResolvedValue({}),
+}));
+jest.mock(
+ '../../../components/ExploreV1/ExploreSearchCard/ExploreSearchCard',
+ () =>
+ jest.fn().mockImplementation(() => ExploreSearchCard.component
)
+);
+jest.mock('../shared/TagSuggestion', () =>
+ jest.fn().mockImplementation(() => TagSuggestion.component
)
+);
+jest.mock('../../../hooks/useFqn', () => ({
+ useFqn: jest
+ .fn()
+ .mockReturnValue({ fqn: 'sample_data.ecommerce_db.shopify.dim_location' }),
+}));
+
+describe('RequestTagPage', () => {
+ it('should render component', async () => {
+ render( , { wrapper: MemoryRouter });
+
+ expect(
+ await screen.findByText('TitleBreadcrumb.component')
+ ).toBeInTheDocument();
+ expect(await screen.findByText('Assignees.component')).toBeInTheDocument();
+ expect(
+ await screen.findByText('TagSuggestion.component')
+ ).toBeInTheDocument();
+ expect(await screen.findByTestId('form-title')).toBeInTheDocument();
+ expect(await screen.findByTestId('form-container')).toBeInTheDocument();
+ expect(await screen.findByTestId('title')).toBeInTheDocument();
+ expect(await screen.findByTestId('cancel-btn')).toBeInTheDocument();
+ expect(await screen.findByTestId('submit-tag-request')).toBeInTheDocument();
+ });
+
+ it("should go back to previous page when 'Cancel' button is clicked", async () => {
+ render( , { wrapper: MemoryRouter });
+ const cancelBtn = await screen.findByTestId('cancel-btn');
+
+ act(() => {
+ fireEvent.click(cancelBtn);
+ });
+
+ expect(mockUseHistory.goBack).toHaveBeenCalled();
+ });
+
+ it('should submit form when submit button is clicked', async () => {
+ const mockPostThread = postThread as jest.Mock;
+ render( , { wrapper: MemoryRouter });
+
+ const submitBtn = await screen.findByTestId('submit-tag-request');
+
+ await act(async () => {
+ fireEvent.click(submitBtn);
+ });
+
+ expect(mockPostThread).toHaveBeenCalledWith({
+ about:
+ '<#E::table::sample_data.ecommerce_db.shopify.dim_location::columns::"address.street_name"::tags>',
+ from: undefined,
+ message: 'Task message',
+ taskDetails: {
+ assignees: [
+ {
+ id: 'id1',
+ type: 'User',
+ },
+ ],
+ oldValue: '[]',
+ suggestion: '[]',
+ type: 'RequestTag',
+ },
+ type: 'Task',
+ });
+ });
+});
diff --git a/openmetadata-ui/src/main/resources/ui/src/pages/TasksPage/RequestTagPage/RequestTagPage.tsx b/openmetadata-ui/src/main/resources/ui/src/pages/TasksPage/RequestTagPage/RequestTagPage.tsx
index 3468f339cb0..f18c7aaa99e 100644
--- a/openmetadata-ui/src/main/resources/ui/src/pages/TasksPage/RequestTagPage/RequestTagPage.tsx
+++ b/openmetadata-ui/src/main/resources/ui/src/pages/TasksPage/RequestTagPage/RequestTagPage.tsx
@@ -196,6 +196,7 @@ const RequestTag = () => {
})}