diff --git a/openmetadata-ui/src/main/resources/ui/src/components/Team/TeamDetails/TeamsHeaderSection/TeamsHeadingLabel.test.tsx b/openmetadata-ui/src/main/resources/ui/src/components/Team/TeamDetails/TeamsHeaderSection/TeamsHeadingLabel.test.tsx new file mode 100644 index 00000000000..a6773cc90b5 --- /dev/null +++ b/openmetadata-ui/src/main/resources/ui/src/components/Team/TeamDetails/TeamsHeaderSection/TeamsHeadingLabel.test.tsx @@ -0,0 +1,123 @@ +/* + * 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 userEvent from '@testing-library/user-event'; +import React from 'react'; +import { TeamType } from '../../../../generated/entity/teams/team'; +import { useAuth } from '../../../../hooks/authHooks'; +import { ENTITY_PERMISSIONS } from '../../../../mocks/Permissions.mock'; +import TeamsHeadingLabel from './TeamsHeadingLabel.component'; + +jest.mock('../../../../hooks/authHooks', () => ({ + useAuth: jest.fn().mockReturnValue({ isAdminUser: true }), +})); + +jest.mock('../../../Auth/AuthProviders/AuthProvider', () => ({ + useAuthContext: jest.fn().mockReturnValue({ + currentUser: { userId: 'test-user' }, + }), +})); +const mockUpdateTeamHandler = jest.fn(); + +const teamProps = { + currentTeam: { + changeDescription: {}, + children: [], + childrenCount: 0, + defaultRoles: [], + deleted: false, + description: 'Test team description', + displayName: 'Test Team', + domain: { id: 'test-domain', type: 'domain' }, + email: 'test-team@test.com', + fullyQualifiedName: 'test-team', + href: '/test-team', + id: 'test-team', + inheritedRoles: [], + isJoinable: true, + name: 'test-team', + owner: { id: 'test-user', type: 'user' }, + owns: [], + parents: [], + policies: [], + profile: {}, + teamType: TeamType.Organization, + updatedAt: Date.now(), + updatedBy: 'test-user', + userCount: 1, + users: [{ id: 'test-user', type: 'user' }], + version: 1, + }, + updateTeamHandler: mockUpdateTeamHandler, + entityPermissions: ENTITY_PERMISSIONS, +}; + +describe('TeamsHeadingLabel', () => { + it('should render Teams Heading Label', async () => { + await act(async () => { + render(); + }); + const teamHeading = screen.getByTestId('team-heading'); + + expect(teamHeading).toHaveTextContent('Test Team'); + }); + + it('should handle edit team name', () => { + const { getByTestId } = render(); + const editButton = getByTestId('edit-team-name'); + fireEvent.click(editButton); + const teamNameInput = getByTestId('team-name-input'); + + expect(teamNameInput).toBeInTheDocument(); + }); + + it('should handle save team name', async () => { + const { getByTestId } = render(); + const editButton = getByTestId('edit-team-name'); + await act(async () => { + userEvent.click(editButton); + }); + + const saveButton = getByTestId('saveAssociatedTag'); + await act(async () => { + userEvent.click(saveButton); + }); + + expect(mockUpdateTeamHandler).toHaveBeenCalled(); + }); + + it('should handle cancel team name edit', async () => { + const { getByTestId, queryByTestId } = render( + + ); + const editButton = getByTestId('edit-team-name'); + await act(async () => { + userEvent.click(editButton); + }); + + const cancelButton = getByTestId('cancelAssociatedTag'); + await act(async () => { + userEvent.click(cancelButton); + }); + + expect(queryByTestId('team-name-input')).not.toBeInTheDocument(); + }); + + it('should not allow editing team name if user does not have permission', () => { + (useAuth as jest.Mock).mockReturnValue({ isAdminUser: false }); + const { queryByTestId } = render(); + const editButton = queryByTestId('edit-team-name'); + + expect(editButton).not.toBeInTheDocument(); + }); +}); diff --git a/openmetadata-ui/src/main/resources/ui/src/components/Team/TeamDetails/TeamsHeaderSection/TeamsInfo.test.tsx b/openmetadata-ui/src/main/resources/ui/src/components/Team/TeamDetails/TeamsHeaderSection/TeamsInfo.test.tsx new file mode 100644 index 00000000000..95e799f8ed0 --- /dev/null +++ b/openmetadata-ui/src/main/resources/ui/src/components/Team/TeamDetails/TeamsHeaderSection/TeamsInfo.test.tsx @@ -0,0 +1,142 @@ +/* + * 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 { TeamType } from '../../../../generated/entity/teams/team'; +import { useAuth } from '../../../../hooks/authHooks'; +import { ENTITY_PERMISSIONS } from '../../../../mocks/Permissions.mock'; +import TeamsInfo from './TeamsInfo.component'; + +const mockTeam = { + changeDescription: {}, + children: [], + childrenCount: 0, + defaultRoles: [], + deleted: false, + description: 'Test team description', + displayName: 'Test Team', + domain: { id: 'test-domain', type: 'domain' }, + email: 'test-team@test.com', + fullyQualifiedName: 'test-team', + href: '/test-team', + id: 'test-team', + inheritedRoles: [], + isJoinable: true, + name: 'test-team', + owner: { id: 'test-user', type: 'user' }, + owns: [], + parents: [], + policies: [], + profile: {}, + teamType: TeamType.Organization, + updatedAt: Date.now(), + updatedBy: 'test-user', + userCount: 1, + users: [{ id: 'test-user', type: 'user' }], + version: 1, +}; + +jest.mock('../../../../hooks/authHooks', () => ({ + useAuth: jest.fn().mockReturnValue({ isAdminUser: true }), +})); + +jest.mock('../../../common/OwnerLabel/OwnerLabel.component', () => ({ + OwnerLabel: jest.fn().mockImplementation(() =>
OwnerLabel
), +})); + +jest.mock('../../../common/DomainLabel/DomainLabel.component', () => ({ + DomainLabel: jest.fn().mockImplementation(() =>
DomainLabel
), +})); + +jest.mock('./TeamsSubscription.component', () => ({ + __esModule: true, + default: jest.fn().mockImplementation(() =>
TeamsSubscription
), +})); + +jest.mock('../../../common/TeamTypeSelect/TeamTypeSelect.component', () => ({ + __esModule: true, + default: jest.fn().mockImplementation(() =>
TeamTypeSelect
), +})); + +jest.mock('../../../Auth/AuthProviders/AuthProvider', () => ({ + useAuthContext: jest.fn().mockReturnValue({ + currentUser: { id: 'test-user' }, + }), +})); + +const mockEntityPermissions = { ...ENTITY_PERMISSIONS }; + +const mockUpdateTeamHandler = jest.fn(); +const teamProps = { + parentTeams: [], + isGroupType: false, + childTeamsCount: 0, + currentTeam: mockTeam, + entityPermissions: mockEntityPermissions, + isTeamDeleted: false, + updateTeamHandler: mockUpdateTeamHandler, +}; + +describe('TeamsInfo', () => { + it('should render TeamsInfo', async () => { + await act(async () => { + render(); + }); + const domainLabel = screen.getByText('DomainLabel'); + + expect(domainLabel).toBeInTheDocument(); + }); + + it('should handle edit team email', () => { + const { getByTestId } = render(); + const editButton = getByTestId('edit-email'); + fireEvent.click(editButton); + const teamEmailInput = getByTestId('email-input'); + + expect(teamEmailInput).toBeInTheDocument(); + }); + + it('should handle save team email', async () => { + const { getByTestId } = render(); + const editButton = getByTestId('edit-email'); + fireEvent.click(editButton); + const saveButton = getByTestId('save-edit-email'); + await act(async () => { + fireEvent.click(saveButton); + }); + + expect(mockUpdateTeamHandler).toHaveBeenCalled(); + }); + + it('should handle cancel team email edit', async () => { + const { getByTestId } = render(); + const editButton = getByTestId('edit-email'); + fireEvent.click(editButton); + const cancelButton = getByTestId('cancel-edit-email'); + await act(async () => { + fireEvent.click(cancelButton); + }); + + expect(screen.queryByTestId('email-input')).not.toBeInTheDocument(); + }); + + it('should not show edit button if user does not have permission', () => { + (useAuth as jest.Mock).mockReturnValue({ isAdminUser: false }); + + mockEntityPermissions.EditAll = false; + const { queryByTestId } = render(); + const ownerLabel = queryByTestId('edit-email'); + + expect(ownerLabel).not.toBeInTheDocument(); + }); +}); diff --git a/openmetadata-ui/src/main/resources/ui/src/components/Team/TeamDetails/TeamsHeaderSection/TeamsSubscription.test.tsx b/openmetadata-ui/src/main/resources/ui/src/components/Team/TeamDetails/TeamsHeaderSection/TeamsSubscription.test.tsx new file mode 100644 index 00000000000..f5ea5527ae6 --- /dev/null +++ b/openmetadata-ui/src/main/resources/ui/src/components/Team/TeamDetails/TeamsHeaderSection/TeamsSubscription.test.tsx @@ -0,0 +1,81 @@ +/* + * 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 TeamsSubscription from './TeamsSubscription.component'; + +describe('TeamsSubscription', () => { + const mockUpdateTeamSubscription = jest.fn(); + + const teamProps = { + hasEditPermission: true, + updateTeamSubscription: mockUpdateTeamSubscription, + }; + + it('renders Teams Subscription', async () => { + await act(async () => { + render(); + }); + const subscription = screen.getByTestId('teams-subscription'); + + expect(subscription).toBeInTheDocument(); + }); + + it('should handle edit team subscription', () => { + const { getByTestId } = render(); + const editButton = getByTestId('edit-team-subscription'); + fireEvent.click(editButton); + const subscriptionModal = getByTestId('subscription-modal'); + + expect(subscriptionModal).toBeInTheDocument(); + }); + + it('should handle save team subscription', async () => { + const { getByTestId, getByText } = render( + + ); + const editButton = getByTestId('edit-team-subscription'); + await act(async () => { + fireEvent.click(editButton); + }); + const saveButton = getByText('label.confirm'); + await act(async () => { + fireEvent.click(saveButton); + }); + + expect(mockUpdateTeamSubscription).toHaveBeenCalled(); + }); + + it('should render no data when no subscription', async () => { + const { getByTestId } = render(); + const noData = getByTestId('subscription-no-data'); + + expect(noData).toBeInTheDocument(); + }); + + it('should not render subscriptionRenderElement when no edit permission', async () => { + teamProps.hasEditPermission = false; + + const { queryByTestId } = render( + + ); + const noData = queryByTestId('subscription-no-data'); + + expect(noData).not.toBeInTheDocument(); + }); +}); diff --git a/openmetadata-ui/src/main/resources/ui/src/components/WelcomeScreen/WelcomScreen.test.tsx b/openmetadata-ui/src/main/resources/ui/src/components/WelcomeScreen/WelcomScreen.test.tsx new file mode 100644 index 00000000000..606abb88782 --- /dev/null +++ b/openmetadata-ui/src/main/resources/ui/src/components/WelcomeScreen/WelcomScreen.test.tsx @@ -0,0 +1,60 @@ +/* + * 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 WelcomeScreen from './WelcomeScreen.component'; + +const mockProps = { + onCloseMock: jest.fn(), +}; + +describe('WelcomeScreen', () => { + it('should render WelcomeScreen', async () => { + await act(async () => { + render(, { + wrapper: MemoryRouter, + }); + }); + const welcomeImg = screen.getByTestId('welcome-screen-img'); + + expect(welcomeImg).toBeInTheDocument(); + }); + + it('should call onClose when the close button is clicked', () => { + const { getByTestId } = render( + , + { + wrapper: MemoryRouter, + } + ); + + const closeButton = getByTestId('welcome-screen-close-btn'); + fireEvent.click(closeButton); + + expect(mockProps.onCloseMock).toHaveBeenCalled(); + }); + + it('should display the correct welcome message', () => { + const { getByText } = render( + , + { + wrapper: MemoryRouter, + } + ); + + const welcomeMessage = getByText('message.welcome-screen-message'); + + expect(welcomeMessage).toBeInTheDocument(); + }); +}); diff --git a/openmetadata-ui/src/main/resources/ui/src/components/Widgets/FeedsWidget/FeedsWidget.test.tsx b/openmetadata-ui/src/main/resources/ui/src/components/Widgets/FeedsWidget/FeedsWidget.test.tsx new file mode 100644 index 00000000000..168332b7575 --- /dev/null +++ b/openmetadata-ui/src/main/resources/ui/src/components/Widgets/FeedsWidget/FeedsWidget.test.tsx @@ -0,0 +1,152 @@ +/* + * 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 FeedsWidget from './FeedsWidget.component'; + +const mockHandleRemoveWidget = jest.fn(); + +const mockThread = [ + { + id: '33873393-bd68-46e9-bccc-7701c1c41ad6', + type: 'Task', + threadTs: 1703570590556, + about: 'test', + entityId: '6206a003-281c-4984-9728-4e949a4e4023', + posts: [ + { + id: '12345', + message: 'Resolved the Task.', + postTs: 1703570590652, + from: 'admin', + reactions: [], + }, + ], + task: { + id: 6, + type: 'RequestTestCaseFailureResolution', + assignees: [ + { + id: '2345rt', + type: 'user', + name: 'aaron_johnson0', + fullyQualifiedName: 'aaron_johnson0', + displayName: 'Aaron Johnson', + deleted: false, + }, + ], + status: 'Closed', + closedBy: 'admin', + closedAt: 1703570590648, + newValue: 'Resolution comment', + testCaseResolutionStatusId: 'f93d08e9-2d38-4d01-a294-f8b44fbb0f4a', + }, + }, +]; + +const mockUseActivityFeedProviderValue = { + entityPaging: { total: 4 }, + entityThread: mockThread, + getFeedData: jest.fn().mockImplementation(() => Promise.resolve()), + loading: false, + selectedThread: mockThread[0], + setActiveThread: jest.fn(), +}; + +const widgetProps = { + selectedGridSize: 10, + isEditView: true, + widgetKey: 'testWidgetKey', + handleRemoveWidget: mockHandleRemoveWidget, +}; + +const tabs = ['All', 'Mentions', 'Tasks']; + +jest.mock( + '../../../components/ActivityFeed/ActivityFeedList/ActivityFeedListV1.component', + () => jest.fn().mockImplementation(({ children }) =>

{children}

) +); + +jest.mock('../../common/FeedsFilterPopover/FeedsFilterPopover.component', () => + jest.fn().mockImplementation(({ children }) =>

{children}

) +); + +jest.mock('../../../rest/feedsAPI', () => ({ + getFeedsWithFilter: jest.fn().mockReturnValue(Promise.resolve(mockThread)), +})); + +jest.mock('../../../utils/CommonUtils', () => ({ + getCountBadge: jest.fn(), + getEntityDetailLink: jest.fn(), + Transi18next: jest.fn(), +})); + +jest.mock('quilljs-markdown', () => { + class MockQuillMarkdown { + constructor() { + // eslint-disable-next-line no-console + console.log('Markdown constructor'); + } + } + + const instance = new MockQuillMarkdown(); + + return instance; +}); + +jest.mock( + '../../../components/ActivityFeed/ActivityFeedProvider/ActivityFeedProvider', + () => ({ + useActivityFeedProvider: jest + .fn() + .mockImplementation(() => mockUseActivityFeedProviderValue), + }) +); + +describe('FeedsWidget', () => { + it('should render FeedsWidget', async () => { + await act(async () => { + render(); + }); + const activityFeedWidget = screen.getByTestId('activity-feed-widget'); + + expect(activityFeedWidget).toBeInTheDocument(); + }); + + it('should render All tab by default', () => { + const { getAllByRole } = render(); + const tabs = getAllByRole('tab'); + const allTab = tabs[0]; + + expect(allTab).toHaveAttribute('aria-selected', 'true'); + }); + + tabs.map((tab, index) => { + it(`should select ${tab} tab`, () => { + const { getAllByRole } = render(); + const tabs = getAllByRole('tab'); + const selectedTab = tabs[index]; + selectedTab.click(); + + expect(selectedTab.getAttribute('aria-selected')).toBe('true'); + }); + }); + + it('should handle close click when in edit view', () => { + const { getByTestId } = render(); + const closeButton = getByTestId('remove-widget-button'); + fireEvent.click(closeButton); + + expect(mockHandleRemoveWidget).toHaveBeenCalledWith(widgetProps.widgetKey); + }); +}); diff --git a/openmetadata-ui/src/main/resources/ui/src/components/Widgets/RecentlyViewed/RecentlyViewed.test.tsx b/openmetadata-ui/src/main/resources/ui/src/components/Widgets/RecentlyViewed/RecentlyViewed.test.tsx new file mode 100644 index 00000000000..e37a9d8d9c9 --- /dev/null +++ b/openmetadata-ui/src/main/resources/ui/src/components/Widgets/RecentlyViewed/RecentlyViewed.test.tsx @@ -0,0 +1,92 @@ +/* + * 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 { getRecentlyViewedData } from '../../../utils/CommonUtils'; +import RecentlyViewed from './RecentlyViewed'; + +const mockProp = { + widgetKey: 'testKey', +}; + +jest.mock( + '../../Skeleton/MyData/EntityListSkeleton/EntityListSkeleton.component', + () => { + return jest + .fn() + .mockImplementation(({ children }) =>
{children}
); + } +); +jest.mock('react-router-dom', () => ({ + useLocation: jest.fn().mockImplementation(() => ({ pathname: '' })), + + Link: jest.fn().mockImplementation(() =>
Link
), +})); + +jest.mock('../../../utils/CommonUtils', () => ({ + getRecentlyViewedData: jest.fn().mockReturnValue([ + { + displayName: 'test', + entityType: 'table', + fqn: 'test', + id: '1', + serviceType: 'BigQuery', + name: 'Test Item', + fullyQualifiedName: 'test.item', + type: 'test', + timestamp: 1706533046620, + }, + ]), + prepareLabel: jest.fn(), +})); + +describe('RecentlyViewed', () => { + it('should render RecentlyViewed', async () => { + await act(async () => { + render(); + }); + + expect(screen.getByTestId('recently-viewed-widget')).toBeInTheDocument(); + }); + + it('should call handleCloseClick when close button is clicked', async () => { + const handleRemoveWidget = jest.fn(); + const { getByTestId } = render( + + ); + fireEvent.click(getByTestId('remove-widget-button')); + + expect(handleRemoveWidget).toHaveBeenCalled(); + }); + + it('renders list item when data is not empty', async () => { + await act(async () => { + render(); + }); + + expect(screen.getByTestId('Recently Viewed-test')).toBeInTheDocument(); + }); + + it('should render no data placeholder when data is empty', async () => { + (getRecentlyViewedData as jest.Mock).mockReturnValue([]), + await act(async () => { + render(); + }); + + expect(screen.getByTestId('no-data-placeholder')).toBeInTheDocument(); + }); +}); diff --git a/openmetadata-ui/src/main/resources/ui/src/components/common/CmdKIcon/CmdKIcon.component.tsx b/openmetadata-ui/src/main/resources/ui/src/components/common/CmdKIcon/CmdKIcon.component.tsx index dba0f0f1cb3..41304336042 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/common/CmdKIcon/CmdKIcon.component.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/common/CmdKIcon/CmdKIcon.component.tsx @@ -19,21 +19,24 @@ import { NavigatorHelper } from '../../../utils/NavigatorUtils'; const CmdKIcon = () => { return ( -
+
{NavigatorHelper.isMacOs() ? ( ) : ( )} ({ + NavigatorHelper: { + isMacOs: jest.fn(), + }, +})); + +describe('CmdKIcon', () => { + it('should render CmdKIcon', async () => { + await act(async () => { + render(); + }); + + expect(screen.getByTestId('cmdicon-container')).toBeInTheDocument(); + }); + + it('should render CmdButton when isMacOs is true', () => { + (NavigatorHelper.isMacOs as jest.Mock).mockReturnValue(true); + const { getByTestId, queryByTestId } = render(); + + expect(getByTestId('cmd-button')).toBeInTheDocument(); + expect(queryByTestId('ctrl-button')).toBeNull(); + }); + + it('should render CtrlButton when isMacOs is false', () => { + (NavigatorHelper.isMacOs as jest.Mock).mockReturnValue(false); + const { getByTestId, queryByTestId } = render(); + + expect(getByTestId('ctrl-button')).toBeInTheDocument(); + expect(queryByTestId('cmd-button')).toBeNull(); + }); +}); diff --git a/openmetadata-ui/src/main/resources/ui/src/components/common/FeedsFilterPopover/FeedsFilterPopover.component.tsx b/openmetadata-ui/src/main/resources/ui/src/components/common/FeedsFilterPopover/FeedsFilterPopover.component.tsx index 55e9a03c603..6cecbe73d5a 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/common/FeedsFilterPopover/FeedsFilterPopover.component.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/common/FeedsFilterPopover/FeedsFilterPopover.component.tsx @@ -123,7 +123,11 @@ const FeedsFilterPopover = ({ showArrow={false} trigger="click" onOpenChange={setPopupVisible}> -