Add unit test cases (#14981)

* unit test case of welcome screen & recently viewed

* add team type select unit test

* add unit test case for resizable panels

* add unit test case for Panel Container

* unit test case for CmdKIcon

* add unit test case for feed filter popover

* add unit test fir feeds widget

* add unit test case for form builder

* add unit test case for form builder

* add unit test case of teams heading label

* unit test case of teams info

* unit test case of teams subscription

* unit test case of add data quality test page

* unit test of add ingestion page

* code refactor
This commit is contained in:
Harsh Vador 2024-02-06 19:32:30 +05:30 committed by GitHub
parent b8713690f0
commit 0659e02f6f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
20 changed files with 1370 additions and 5 deletions

View File

@ -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(<TeamsHeadingLabel {...teamProps} />);
});
const teamHeading = screen.getByTestId('team-heading');
expect(teamHeading).toHaveTextContent('Test Team');
});
it('should handle edit team name', () => {
const { getByTestId } = render(<TeamsHeadingLabel {...teamProps} />);
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(<TeamsHeadingLabel {...teamProps} />);
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(
<TeamsHeadingLabel {...teamProps} />
);
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(<TeamsHeadingLabel {...teamProps} />);
const editButton = queryByTestId('edit-team-name');
expect(editButton).not.toBeInTheDocument();
});
});

View File

@ -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(() => <div>OwnerLabel</div>),
}));
jest.mock('../../../common/DomainLabel/DomainLabel.component', () => ({
DomainLabel: jest.fn().mockImplementation(() => <div>DomainLabel</div>),
}));
jest.mock('./TeamsSubscription.component', () => ({
__esModule: true,
default: jest.fn().mockImplementation(() => <div>TeamsSubscription</div>),
}));
jest.mock('../../../common/TeamTypeSelect/TeamTypeSelect.component', () => ({
__esModule: true,
default: jest.fn().mockImplementation(() => <div>TeamTypeSelect</div>),
}));
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(<TeamsInfo {...teamProps} />);
});
const domainLabel = screen.getByText('DomainLabel');
expect(domainLabel).toBeInTheDocument();
});
it('should handle edit team email', () => {
const { getByTestId } = render(<TeamsInfo {...teamProps} />);
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(<TeamsInfo {...teamProps} />);
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(<TeamsInfo {...teamProps} />);
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(<TeamsInfo {...teamProps} />);
const ownerLabel = queryByTestId('edit-email');
expect(ownerLabel).not.toBeInTheDocument();
});
});

View File

@ -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(<TeamsSubscription {...teamProps} />);
});
const subscription = screen.getByTestId('teams-subscription');
expect(subscription).toBeInTheDocument();
});
it('should handle edit team subscription', () => {
const { getByTestId } = render(<TeamsSubscription {...teamProps} />);
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(
<TeamsSubscription {...teamProps} />
);
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(<TeamsSubscription {...teamProps} />);
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(
<TeamsSubscription
{...teamProps}
subscription={{
gChat: { endpoint: 'test-endpoint' },
}}
/>
);
const noData = queryByTestId('subscription-no-data');
expect(noData).not.toBeInTheDocument();
});
});

View File

@ -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(<WelcomeScreen onClose={mockProps.onCloseMock} />, {
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(
<WelcomeScreen onClose={mockProps.onCloseMock} />,
{
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(
<WelcomeScreen onClose={mockProps.onCloseMock} />,
{
wrapper: MemoryRouter,
}
);
const welcomeMessage = getByText('message.welcome-screen-message');
expect(welcomeMessage).toBeInTheDocument();
});
});

View File

@ -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 }) => <p>{children}</p>)
);
jest.mock('../../common/FeedsFilterPopover/FeedsFilterPopover.component', () =>
jest.fn().mockImplementation(({ children }) => <p>{children}</p>)
);
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(<FeedsWidget {...widgetProps} />);
});
const activityFeedWidget = screen.getByTestId('activity-feed-widget');
expect(activityFeedWidget).toBeInTheDocument();
});
it('should render All tab by default', () => {
const { getAllByRole } = render(<FeedsWidget {...widgetProps} />);
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(<FeedsWidget {...widgetProps} />);
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(<FeedsWidget {...widgetProps} />);
const closeButton = getByTestId('remove-widget-button');
fireEvent.click(closeButton);
expect(mockHandleRemoveWidget).toHaveBeenCalledWith(widgetProps.widgetKey);
});
});

View File

@ -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 }) => <div>{children}</div>);
}
);
jest.mock('react-router-dom', () => ({
useLocation: jest.fn().mockImplementation(() => ({ pathname: '' })),
Link: jest.fn().mockImplementation(() => <div>Link</div>),
}));
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(<RecentlyViewed widgetKey={mockProp.widgetKey} />);
});
expect(screen.getByTestId('recently-viewed-widget')).toBeInTheDocument();
});
it('should call handleCloseClick when close button is clicked', async () => {
const handleRemoveWidget = jest.fn();
const { getByTestId } = render(
<RecentlyViewed
isEditView
handleRemoveWidget={handleRemoveWidget}
widgetKey="testKey"
/>
);
fireEvent.click(getByTestId('remove-widget-button'));
expect(handleRemoveWidget).toHaveBeenCalled();
});
it('renders list item when data is not empty', async () => {
await act(async () => {
render(<RecentlyViewed widgetKey={mockProp.widgetKey} />);
});
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(<RecentlyViewed widgetKey={mockProp.widgetKey} />);
});
expect(screen.getByTestId('no-data-placeholder')).toBeInTheDocument();
});
});

View File

@ -19,21 +19,24 @@ import { NavigatorHelper } from '../../../utils/NavigatorUtils';
const CmdKIcon = () => {
return (
<div className="d-flex items-center">
<div className="d-flex items-center" data-testid="cmdicon-container">
{NavigatorHelper.isMacOs() ? (
<CmdButton
data-testid="cmd-button"
style={{
backgroundColor: 'white',
}}
/>
) : (
<CtrlButton
data-testid="ctrl-button"
style={{
backgroundColor: 'white',
}}
/>
)}
<KButton
data-testid="k-button"
style={{
marginLeft: '4px',
backgroundColor: 'white',

View File

@ -0,0 +1,48 @@
/*
* 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, render, screen } from '@testing-library/react';
import React from 'react';
import { NavigatorHelper } from '../../../utils/NavigatorUtils';
import CmdKIcon from './CmdKIcon.component';
jest.mock('../../../utils/NavigatorUtils', () => ({
NavigatorHelper: {
isMacOs: jest.fn(),
},
}));
describe('CmdKIcon', () => {
it('should render CmdKIcon', async () => {
await act(async () => {
render(<CmdKIcon />);
});
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(<CmdKIcon />);
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(<CmdKIcon />);
expect(getByTestId('ctrl-button')).toBeInTheDocument();
expect(queryByTestId('cmd-button')).toBeNull();
});
});

View File

@ -123,7 +123,11 @@ const FeedsFilterPopover = ({
showArrow={false}
trigger="click"
onOpenChange={setPopupVisible}>
<Button className="flex-center" icon={<FilterIcon height={16} />} />
<Button
className="flex-center"
data-testid="filter-button"
icon={<FilterIcon height={16} />}
/>
</Popover>
);
};

View File

@ -0,0 +1,91 @@
/*
* 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 { FeedFilter } from '../../../enums/mydata.enum';
import FeedsFilterPopover from './FeedsFilterPopover.component';
const onUpdateMock = jest.fn();
const mockProps = {
defaultFilter: FeedFilter.ALL,
onUpdate: onUpdateMock,
};
jest.mock('../../Auth/AuthProviders/AuthProvider', () => ({
useAuthContext: jest.fn(() => ({
currentUser: {
isAdmin: true,
},
})),
}));
describe('FeedsFilterPopover', () => {
it('should render Feeds Filter Popover', async () => {
await act(async () => {
render(<FeedsFilterPopover {...mockProps} />);
});
const filterButton = screen.getByTestId('filter-button');
fireEvent.click(
filterButton,
new MouseEvent('hover', {
bubbles: true,
cancelable: true,
})
);
expect(screen.getByTestId('cancel-button')).toBeInTheDocument();
expect(
screen.getByTestId('selectable-list-update-btn')
).toBeInTheDocument();
});
it('should update filter when an item is clicked', async () => {
await act(async () => {
render(<FeedsFilterPopover {...mockProps} />);
});
const filterButton = screen.getByTestId('filter-button');
fireEvent.click(
filterButton,
new MouseEvent('hover', {
bubbles: true,
cancelable: true,
})
);
const listItem = screen.getByText('message.feed-filter-all');
fireEvent.click(listItem);
fireEvent.click(screen.getByTestId('selectable-list-update-btn'));
expect(onUpdateMock).toHaveBeenCalledWith(FeedFilter.ALL);
});
it('should close popover when cancel button is clicked', async () => {
await act(async () => {
render(<FeedsFilterPopover {...mockProps} />);
});
const filterButton = screen.getByTestId('filter-button');
fireEvent.click(
filterButton,
new MouseEvent('hover', {
bubbles: true,
cancelable: true,
})
);
const cancelButton = screen.getByTestId('cancel-button');
fireEvent.click(cancelButton);
expect(screen.queryByTestId('cancel-button')).not.toBeInTheDocument();
});
});

View File

@ -0,0 +1,121 @@
/*
* 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 validator from '@rjsf/validator-ajv8';
import { fireEvent, render, screen } from '@testing-library/react';
import React from 'react';
import { LOADING_STATE } from '../../../enums/common.enum';
import { ServiceCategory } from '../../../enums/service.enum';
import { transformErrors } from '../../../utils/formUtils';
import FormBuilder, { Props } from './FormBuilder';
describe('FormBuilder', () => {
const mockOnSubmit = jest.fn();
const mockOnCancel = jest.fn();
const props = {
okText: 'Submit',
cancelText: 'Cancel',
serviceCategory: ServiceCategory.DASHBOARD_SERVICES,
showFormHeader: true,
status: 'initial',
onCancel: mockOnCancel,
onSubmit: mockOnSubmit,
useSelectWidget: true,
schema: {},
formData: {},
uiSchema: {},
validator: validator,
} as Props;
it('should render Form Builder', () => {
const { getByTestId } = render(
<FormBuilder
cancelText="Cancel"
okText="OK"
schema={{ type: 'object' }}
serviceCategory={ServiceCategory.DASHBOARD_SERVICES}
transformErrors={transformErrors}
validator={validator}
onCancel={jest.fn()}
onSubmit={jest.fn()}
/>
);
expect(getByTestId('buttons')).toBeInTheDocument();
expect(getByTestId('submit-btn')).toBeInTheDocument();
});
it('should call onSubmit when submit button is clicked', () => {
render(<FormBuilder {...props} />);
fireEvent.click(screen.getByText('Submit'));
expect(mockOnSubmit).toHaveBeenCalled();
});
it('should handle cancel button click', () => {
const { getByText } = render(
<FormBuilder
cancelText="Close"
okText="OK"
schema={{ type: 'object' }}
serviceCategory={ServiceCategory.DASHBOARD_SERVICES}
validator={validator}
onCancel={mockOnCancel}
onSubmit={jest.fn()}
/>
);
const cancelButton = getByText('Close');
fireEvent.click(cancelButton);
expect(mockOnCancel).toHaveBeenCalled();
});
it('should display loader when status is waiting', () => {
const { getByTestId } = render(
<FormBuilder
cancelText="Cancel"
okText="OK"
schema={{ type: 'object' }}
serviceCategory={ServiceCategory.DASHBOARD_SERVICES}
status={LOADING_STATE.WAITING}
validator={validator}
onSubmit={jest.fn()}
/>
);
expect(getByTestId('loader')).toBeInTheDocument();
});
it('should display check icon when status is success', () => {
const { getByRole } = render(
<FormBuilder
cancelText="Cancel"
okText="OK"
schema={{ type: 'object' }}
serviceCategory={ServiceCategory.DASHBOARD_SERVICES}
status={LOADING_STATE.SUCCESS}
validator={validator}
onSubmit={jest.fn()}
/>
);
expect(getByRole('img')).toBeInTheDocument();
});
it('does not show form header when showFormHeader is false', () => {
const newProps = { ...props, showFormHeader: false };
render(<FormBuilder {...newProps} />);
expect(screen.queryByText('Form Header')).toBeNull();
});
});

View File

@ -30,7 +30,7 @@ import MultiSelectWidget from '../../JsonSchemaWidgets/MultiSelectWidget';
import PasswordWidget from '../../JsonSchemaWidgets/PasswordWidget';
import Loader from '../../Loader/Loader';
interface Props extends FormProps {
export interface Props extends FormProps {
okText: string;
cancelText: string;
serviceCategory: ServiceCategory;

View File

@ -0,0 +1,72 @@
/*
* 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 } from '@testing-library/react';
import React from 'react';
import PanelContainer from './PanelContainer';
const mockProps = {
className: 'test-class',
dimensions: { width: 500, height: 500 },
overlay: {
displayThreshold: 400,
header: 'Test Header',
},
};
describe('PanelContainer', () => {
it('should renders PanelContainer', () => {
const { getByTestId } = render(
<PanelContainer {...mockProps}>
<div>Child Component</div>
</PanelContainer>
);
expect(getByTestId('panel-container')).toBeInTheDocument();
});
it('should render overlay when dimensions width is less than displayThreshold', () => {
const overlay = {
displayThreshold: 500,
header: 'Test Header',
};
const dimensions = { width: 400, height: 500 };
const { getByText } = render(
<PanelContainer dimensions={dimensions} overlay={overlay}>
<div>Child Component</div>
</PanelContainer>
);
expect(getByText('Test Header')).toBeInTheDocument();
});
it('should not render overlay when width is greater than displayThreshold', () => {
const { queryByText } = render(
<PanelContainer {...mockProps}>
<div>Child Component</div>
</PanelContainer>
);
expect(queryByText('Test Header')).toBeNull();
});
it('should pass className to div', () => {
const { container } = render(
<PanelContainer className="test-class">
<div>Child Component</div>
</PanelContainer>
);
expect(container.querySelector('.test-class')).toBeInTheDocument();
});
});

View File

@ -20,7 +20,9 @@ const PanelContainer: React.FC<React.PropsWithChildren<PanelContainerProps>> =
const width = dimensions?.width ?? 0;
return (
<div className={classNames(className, 'panel-container')}>
<div
className={classNames(className, 'panel-container')}
data-testid="panel-container">
{overlay && width <= overlay.displayThreshold && (
<div className="light-overlay">
<Typography.Title

View File

@ -38,6 +38,7 @@ const ResizablePanels: React.FC<ResizablePanelsProps> = ({
className={classNames(firstPanel.className, {
'full-width': hideSecondPanel,
})}
data-testid={firstPanel.className}
flex={firstPanel.flex}
minSize={firstPanel.minWidth}
onStopResize={(args) => {
@ -69,6 +70,7 @@ const ResizablePanels: React.FC<ResizablePanelsProps> = ({
className={classNames(secondPanel.className, {
hidden: hideSecondPanel,
})}
data-testid={secondPanel.className}
flex={secondPanel.flex}
minSize={secondPanel.minWidth}
onStopResize={(args) => {

View File

@ -0,0 +1,94 @@
/*
* 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, render, screen } from '@testing-library/react';
import React from 'react';
import ResizablePanels from './ResizablePanels';
jest.mock('../../../components/DocumentTitle/DocumentTitle', () =>
jest.fn().mockImplementation(() => <div>DocumentTitle</div>)
);
const firstPanel = {
children: <div>First Panel</div>,
minWidth: 100,
className: 'first-panel',
flex: 0.5,
onStopResize: jest.fn(),
};
const secondPanel = {
children: <div>Second Panel</div>,
minWidth: 100,
className: 'second-panel',
flex: 0.5,
onStopResize: jest.fn(),
};
describe('ResizablePanels', () => {
it('should render ResizablePanels', () => {
const { getByTestId } = render(
<ResizablePanels
className="test-class"
firstPanel={firstPanel}
hideSecondPanel={false}
orientation="vertical"
pageTitle="Test Page"
secondPanel={secondPanel}
/>
);
expect(getByTestId(firstPanel.className)).toBeInTheDocument();
expect(getByTestId(secondPanel.className)).toBeInTheDocument();
});
it('should hide the second panel when hideSecondPanel is true', async () => {
await act(async () => {
render(
<ResizablePanels
hideSecondPanel
firstPanel={firstPanel}
pageTitle="Test Page"
secondPanel={secondPanel}
/>
);
});
expect(screen.getByTestId('second-panel')).toHaveClass('hidden');
});
it('should set the orientation of the panels to horizontal', () => {
const { container } = render(
<ResizablePanels
firstPanel={firstPanel}
orientation="horizontal"
pageTitle="Test Page"
secondPanel={secondPanel}
/>
);
expect(
container.querySelector('.reflex-container.horizontal')
).toBeInTheDocument();
});
it('should pass className to ReflexContainer', () => {
const { container } = render(
<ResizablePanels
className="test-class"
firstPanel={firstPanel}
pageTitle="Test Page"
secondPanel={secondPanel}
/>
);
expect(container.querySelector('.test-class')).toBeInTheDocument();
});
});

View File

@ -0,0 +1,59 @@
/*
* 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 { fireEvent, render } from '@testing-library/react';
import React from 'react';
import { TeamType } from '../../../generated/entity/teams/team';
import TeamTypeSelect from './TeamTypeSelect.component';
const handleShowTypeSelector = jest.fn();
const updateTeamType = jest.fn();
const mockProps = {
showGroupOption: true,
handleShowTypeSelector: handleShowTypeSelector,
parentTeamType: TeamType.Organization,
teamType: TeamType.Department,
updateTeamType: updateTeamType,
};
jest.mock('../../../utils/TeamUtils', () => ({
getTeamOptionsFromType: jest.fn().mockReturnValue([
{ label: 'BusinessUnit', value: 'BusinessUnit' },
{ label: 'Division', value: 'Division' },
{ label: 'Department', value: 'Department' },
{ label: 'Group', value: 'Group' },
]),
}));
describe('TeamTypeSelect', () => {
it('should render TeamTypeSelect', () => {
const { getByTestId } = render(<TeamTypeSelect {...mockProps} />);
expect(getByTestId('team-type-select')).toBeInTheDocument();
});
it('should call handleCancel when cancel button is clicked', () => {
const { getByTestId } = render(<TeamTypeSelect {...mockProps} />);
fireEvent.click(getByTestId('cancel-btn'));
expect(handleShowTypeSelector).toHaveBeenCalledWith(false);
expect(updateTeamType).not.toHaveBeenCalled();
});
it('should call handleSubmit when save button is clicked', () => {
const { getByTestId } = render(<TeamTypeSelect {...mockProps} />);
fireEvent.click(getByTestId('save-btn'));
expect(updateTeamType).toHaveBeenCalled();
});
});

View File

@ -0,0 +1,83 @@
/*
* 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, render, screen } from '@testing-library/react';
import React from 'react';
import { ProfilerDashboardType } from '../../enums/table.enum';
import { getTableDetailsByFQN } from '../../rest/tableAPI';
import { showErrorToast } from '../../utils/ToastUtils';
import AddDataQualityTestPage from './AddDataQualityTestPage';
const mockTable = {
displayName: 'Test Table',
name: 'test-table',
};
const mockParams = {
fqn: 'sample_data.ecommerce_db.shopify.dim_address',
dashboardType: ProfilerDashboardType.TABLE,
};
jest.mock('react-router-dom', () => ({
useHistory: jest.fn(),
useParams: jest.fn().mockImplementation(() => mockParams),
}));
jest.mock('../../rest/tableAPI', () => ({
getTableDetailsByFQN: jest
.fn()
.mockImplementation(() => Promise.resolve(mockTable)),
}));
jest.mock('../../hooks/useFqn', () => ({
useFqn: jest.fn().mockReturnValue({ fqn: 'test-fqn' }),
}));
jest.mock('../../components/AddDataQualityTest/AddDataQualityTestV1', () => ({
__esModule: true,
default: jest
.fn()
.mockImplementation(() => (
<div data-testid="testv1-container">AddDataQualityTestV1</div>
)),
}));
describe('AddDataQualityTestPage', () => {
it('renders Add DataQuality Test Page', async () => {
await act(async () => {
render(<AddDataQualityTestPage />);
});
const testContainer = screen.getByTestId('testv1-container');
expect(testContainer).toBeInTheDocument();
});
it('should fetch table data on mount', () => {
render(<AddDataQualityTestPage />);
expect(getTableDetailsByFQN).toHaveBeenCalledWith('test-fqn', {
fields: 'testSuite,customMetrics,columns',
});
});
it('should display error toast when fetch fails', async () => {
(getTableDetailsByFQN as jest.Mock).mockRejectedValue(
new Error('Fetch failed')
);
await act(async () => {
render(<AddDataQualityTestPage />);
});
expect(showErrorToast).toHaveBeenCalled();
});
});

View File

@ -48,7 +48,7 @@ const AddDataQualityTestPage = () => {
}
return (
<div className="self-center">
<div className="self-center" data-testid="add-data-quality-test-page">
<AddDataQualityTestV1 table={table} />
</div>
);

View File

@ -0,0 +1,136 @@
/*
* 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,
waitForElementToBeRemoved,
} from '@testing-library/react';
import React from 'react';
import { MemoryRouter, Route } from 'react-router-dom';
import { useAirflowStatus } from '../../hooks/useAirflowStatus';
import { useFqn } from '../../hooks/useFqn';
import AddIngestionPage from './AddIngestionPage.component';
const mockShowErrorToast = jest.fn();
jest.mock('react-router-dom', () => ({
...jest.requireActual('react-router-dom'),
useParams: jest.fn().mockImplementation(() => ({
ingestionType: 'fqn',
serviceCategory: 'databaseServices',
})),
}));
jest.mock('../../hooks/useFqn', () => ({
useFqn: jest.fn().mockImplementation(() => ({ fqn: 'testFqn' })),
}));
jest.mock('../../hooks/useAirflowStatus', () => ({
useAirflowStatus: jest.fn().mockImplementation(() => ({
fetchAirflowStatus: jest.fn().mockImplementation(() => Promise.resolve()),
})),
}));
jest.mock('../../rest/serviceAPI', () => ({
getServiceByFQN: jest.fn().mockImplementation(() =>
Promise.resolve({
deleted: false,
fullyQualifiedName: 'sample_data',
href: 'http://localhost:8585/api/v1/services/databaseServices/0f74bba0-b34b-48e9-a68e-19f165adbeb6',
id: '0f74bba0-b34b-48e9-a68e-19f165adbeb6',
name: 'sample_data',
serviceType: 'BigQuery',
updatedAt: 1706852930787,
updatedBy: 'admin',
version: 0.1,
})
),
}));
jest.mock('../../components/common/ServiceDocPanel/ServiceDocPanel', () =>
jest.fn().mockImplementation(() => <div>ServiceDocPanel</div>)
);
jest.mock('../../utils/ServiceUtils', () => ({
getServiceType: jest.fn(),
}));
jest.mock(
'../../components/common/TitleBreadcrumb/TitleBreadcrumb.component',
() => jest.fn().mockImplementation(() => <div>TitleBreadcrumb</div>)
);
jest.mock('../../components/AddIngestion/AddIngestion.component', () =>
jest.fn().mockImplementation(() => <div>AddIngestion</div>)
);
jest.mock('../../rest/ingestionPipelineAPI', () => ({
addIngestionPipeline: jest.fn().mockReturnValue(() => Promise.resolve({})),
deployIngestionPipelineById: jest
.fn()
.mockReturnValue(() => Promise.resolve({})),
getIngestionPipelineByFqn: jest
.fn()
.mockReturnValue(() => Promise.resolve({})),
}));
jest.mock('../../utils/IngestionUtils', () => ({
getBreadCrumbsArray: jest.fn().mockImplementation(() => [{ name: '' }]),
getIngestionHeadingName: jest.fn().mockImplementation(() => 'Ingestion'),
getSettingsPathFromPipelineType: jest.fn().mockImplementation(() => ''),
}));
jest.mock('../../utils/CommonUtils', () => ({
getEntityMissingError: jest.fn().mockImplementation(() => <div>Error</div>),
}));
jest.mock('../../components/common/ResizablePanels/ResizablePanels', () =>
jest.fn().mockImplementation(({ firstPanel, secondPanel }) => (
<>
<div>{firstPanel.children}</div>
<div>{secondPanel.children}</div>
</>
))
);
jest.mock('../../utils/ToastUtils', () => ({
showErrorToast: jest.fn().mockImplementation(() => mockShowErrorToast),
}));
describe('Test AddIngestionPage component', () => {
beforeEach(() => {
(useAirflowStatus as jest.Mock).mockReturnValue({
fetchAirflowStatus: jest
.fn()
.mockImplementation(() => Promise.resolve({})),
});
(useFqn as jest.Mock).mockReturnValue({
fqn: 'testFqn',
});
});
it('AddIngestionPage component should render', async () => {
render(
<MemoryRouter
initialEntries={['/addIngestion/databaseServices/testIngestionType']}>
<Route path="/addIngestion/:serviceCategory/:ingestionType">
<AddIngestionPage />
</Route>
</MemoryRouter>
);
await waitForElementToBeRemoved(() => screen.getByTestId('loader'));
expect(screen.getByText('TitleBreadcrumb')).toBeInTheDocument();
expect(screen.getByText('AddIngestion')).toBeInTheDocument();
expect(screen.getByText('ServiceDocPanel')).toBeInTheDocument();
});
});