Test suit for Service Page and its component (#610)

* Adding test-suits for UI

* fixed broken tests

* fixed all test fail files

* removed parsing errors from files

* resolved test-suits error

* fiexed all the failing test

* fixed tabledatacard title padding

* fixed popOver test

* fixed eslint issue in file

* added eslint disable on top of file

* add test for searchData and MyDataHeader

* add addtional test for teams page

* test suits for teams page and its components

* added test cases for tags page

* added test for services page

* add test for service page and its component

* fixed typo

Co-authored-by: darth-coder00 <aashit@getcollate.io>
This commit is contained in:
Shailesh Parmar 2021-09-29 15:04:21 +05:30 committed by GitHub
parent 91d3ded578
commit a275b1fee3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 279 additions and 70 deletions

View File

@ -5,12 +5,10 @@ import {
render, render,
} from '@testing-library/react'; } from '@testing-library/react';
import React from 'react'; import React from 'react';
import { AddServiceModal } from './AddServiceModal'; import { AddServiceModal, ServiceDataObj } from './AddServiceModal';
const mockData = { const mockData = {
connectionUrl: 'string',
description: 'string', description: 'string',
driverClass: 'string',
href: 'string', href: 'string',
id: 'string', id: 'string',
jdbc: { driverClass: 'string', connectionUrl: 'string' }, jdbc: { driverClass: 'string', connectionUrl: 'string' },
@ -22,7 +20,7 @@ const mockData = {
const mockOnSave = jest.fn(); const mockOnSave = jest.fn();
const mockOnCancel = jest.fn(); const mockOnCancel = jest.fn();
const mockServiceList = [mockData, mockData, mockData]; const mockServiceList: Array<ServiceDataObj> = [{ name: mockData.name }];
jest.mock('../../common/editor/MarkdownWithPreview', () => { jest.mock('../../common/editor/MarkdownWithPreview', () => {
return jest return jest
@ -68,29 +66,7 @@ describe('Test AddServiceModal Component', () => {
expect(mockOnCancel).toBeCalledTimes(1); expect(mockOnCancel).toBeCalledTimes(1);
}); });
it('on click of cancel onCancel should be call', async () => { it('form with all the Field should render for databaseService', async () => {
const { container } = render(
<AddServiceModal
header="Test"
serviceList={mockServiceList}
serviceName="dashboardServices"
onCancel={mockOnCancel}
onSave={mockOnSave}
/>
);
const cancel = await findByTestId(container, 'cancel');
fireEvent.click(
cancel,
new MouseEvent('click', {
bubbles: true,
cancelable: true,
})
);
expect(mockOnCancel).toBeCalledTimes(1);
});
it('form with all the fild should render', async () => {
const { container } = render( const { container } = render(
<AddServiceModal <AddServiceModal
header="Test" header="Test"
@ -104,9 +80,6 @@ describe('Test AddServiceModal Component', () => {
const selectService = await findByTestId(container, 'selectService'); const selectService = await findByTestId(container, 'selectService');
const name = await findByTestId(container, 'name'); const name = await findByTestId(container, 'name');
const url = await findByTestId(container, 'url'); const url = await findByTestId(container, 'url');
// const port = await findByTestId(container, 'port');
// const userName = await findByTestId(container, 'userName');
// const password = await findByTestId(container, 'password');
const database = await findByTestId(container, 'database'); const database = await findByTestId(container, 'database');
const driverClass = await findByTestId(container, 'driverClass'); const driverClass = await findByTestId(container, 'driverClass');
const description = await findByTestId(container, 'description'); const description = await findByTestId(container, 'description');
@ -116,9 +89,6 @@ describe('Test AddServiceModal Component', () => {
expect(selectService).toBeInTheDocument(); expect(selectService).toBeInTheDocument();
expect(name).toBeInTheDocument(); expect(name).toBeInTheDocument();
expect(url).toBeInTheDocument(); expect(url).toBeInTheDocument();
// expect(port).toBeInTheDocument();
// expect(userName).toBeInTheDocument();
// expect(password).toBeInTheDocument();
expect(database).toBeInTheDocument(); expect(database).toBeInTheDocument();
expect(driverClass).toBeInTheDocument(); expect(driverClass).toBeInTheDocument();
expect(description).toBeInTheDocument(); expect(description).toBeInTheDocument();
@ -128,6 +98,68 @@ describe('Test AddServiceModal Component', () => {
expect(queryByText(container, /minute/i)).not.toBeInTheDocument(); expect(queryByText(container, /minute/i)).not.toBeInTheDocument();
}); });
it('form with all the Field should render for dashboardServices', async () => {
const { container } = render(
<AddServiceModal
header="Test"
serviceList={mockServiceList}
serviceName="dashboardServices"
onCancel={mockOnCancel}
onSave={mockOnSave}
/>
);
const form = await findByTestId(container, 'form');
const selectService = await findByTestId(container, 'selectService');
const name = await findByTestId(container, 'name');
const url = await findByTestId(container, 'dashboard-url');
const userName = await findByTestId(container, 'username');
const password = await findByTestId(container, 'password');
const description = await findByTestId(container, 'description');
const ingestionSwitch = await findByTestId(container, 'ingestion-switch');
expect(form).toBeInTheDocument();
expect(selectService).toBeInTheDocument();
expect(name).toBeInTheDocument();
expect(url).toBeInTheDocument();
expect(userName).toBeInTheDocument();
expect(password).toBeInTheDocument();
expect(description).toBeInTheDocument();
expect(ingestionSwitch).toBeInTheDocument();
expect(queryByText(container, /day/i)).not.toBeInTheDocument();
expect(queryByText(container, /hour/i)).not.toBeInTheDocument();
expect(queryByText(container, /minute/i)).not.toBeInTheDocument();
});
it('form with all the Field should render for messagingServices', async () => {
const { container } = render(
<AddServiceModal
header="Test"
serviceList={mockServiceList}
serviceName="messagingServices"
onCancel={mockOnCancel}
onSave={mockOnSave}
/>
);
const form = await findByTestId(container, 'form');
const selectService = await findByTestId(container, 'selectService');
const name = await findByTestId(container, 'name');
const url = await findByTestId(container, 'broker-url');
const schemaRegistry = await findByTestId(container, 'schema-registry');
const description = await findByTestId(container, 'description');
const ingestionSwitch = await findByTestId(container, 'ingestion-switch');
expect(form).toBeInTheDocument();
expect(selectService).toBeInTheDocument();
expect(name).toBeInTheDocument();
expect(url).toBeInTheDocument();
expect(schemaRegistry).toBeInTheDocument();
expect(description).toBeInTheDocument();
expect(ingestionSwitch).toBeInTheDocument();
expect(queryByText(container, /day/i)).not.toBeInTheDocument();
expect(queryByText(container, /hour/i)).not.toBeInTheDocument();
expect(queryByText(container, /minute/i)).not.toBeInTheDocument();
});
it('frequency fileds should be visible when ingestionSwitch is on', async () => { it('frequency fileds should be visible when ingestionSwitch is on', async () => {
const { container } = render( const { container } = render(
<AddServiceModal <AddServiceModal
@ -209,24 +241,6 @@ describe('Test AddServiceModal Component', () => {
target: { value: 'test.123' }, target: { value: 'test.123' },
}); });
// const port = await findByTestId(container, 'port');
// fireEvent.change(port, {
// target: { value: 123 },
// });
// const userName = await findByTestId(container, 'userName');
// fireEvent.change(userName, {
// target: { value: 'testUser' },
// });
// const password = await findByTestId(container, 'password');
// fireEvent.change(password, {
// target: { value: 'testPwd' },
// });
const database = await findByTestId(container, 'database'); const database = await findByTestId(container, 'database');
fireEvent.change(database, { fireEvent.change(database, {
@ -270,9 +284,6 @@ describe('Test AddServiceModal Component', () => {
expect(selectService).toHaveValue('MySQL'); expect(selectService).toHaveValue('MySQL');
expect(name).toHaveValue('test'); expect(name).toHaveValue('test');
expect(url).toHaveValue('test.123'); expect(url).toHaveValue('test.123');
// expect(port).toHaveValue(123);
// expect(userName).toHaveValue('testUser');
// expect(password).toHaveValue('testPwd');
expect(database).toHaveValue('testdb'); expect(database).toHaveValue('testdb');
expect(driverClass).toHaveValue('jdbc'); expect(driverClass).toHaveValue('jdbc');
expect(frequency).toHaveValue('1'); expect(frequency).toHaveValue('1');

View File

@ -568,6 +568,7 @@ export const AddServiceModal: FunctionComponent<Props> = ({
</label> </label>
<input <input
className="tw-form-inputs tw-px-3 tw-py-1" className="tw-form-inputs tw-px-3 tw-py-1"
data-testid="broker-url"
id="broker" id="broker"
name="broker" name="broker"
placeholder={getBrokerUrlPlaceholder()} placeholder={getBrokerUrlPlaceholder()}
@ -583,6 +584,7 @@ export const AddServiceModal: FunctionComponent<Props> = ({
</label> </label>
<input <input
className="tw-form-inputs tw-px-3 tw-py-1" className="tw-form-inputs tw-px-3 tw-py-1"
data-testid="schema-registry"
id="schema-registry" id="schema-registry"
name="schema-registry" name="schema-registry"
placeholder="http(s)://hostname:port" placeholder="http(s)://hostname:port"
@ -757,6 +759,7 @@ export const AddServiceModal: FunctionComponent<Props> = ({
</label> </label>
<input <input
className="tw-form-inputs tw-px-3 tw-py-1" className="tw-form-inputs tw-px-3 tw-py-1"
data-testid="dashboard-url"
id="dashboard-url" id="dashboard-url"
name="dashboard-url" name="dashboard-url"
placeholder="http(s)://hostname:port" placeholder="http(s)://hostname:port"
@ -773,6 +776,7 @@ export const AddServiceModal: FunctionComponent<Props> = ({
</label> </label>
<input <input
className="tw-form-inputs tw-px-3 tw-py-1" className="tw-form-inputs tw-px-3 tw-py-1"
data-testid="username"
id="username" id="username"
name="username" name="username"
placeholder="username" placeholder="username"
@ -788,6 +792,7 @@ export const AddServiceModal: FunctionComponent<Props> = ({
</label> </label>
<input <input
className="tw-form-inputs tw-px-3 tw-py-1" className="tw-form-inputs tw-px-3 tw-py-1"
data-testid="password"
id="password" id="password"
name="password" name="password"
placeholder="password" placeholder="password"

View File

@ -15,8 +15,13 @@
* limitations under the License. * limitations under the License.
*/ */
import { findByTestId, render } from '@testing-library/react'; import {
import React from 'react'; findAllByTestId,
findByTestId,
fireEvent,
render,
} from '@testing-library/react';
import React, { ReactNode } from 'react';
import { MemoryRouter } from 'react-router-dom'; import { MemoryRouter } from 'react-router-dom';
import ServicesPage from './index'; import ServicesPage from './index';
@ -24,14 +29,29 @@ const mockServiceDetails = {
data: [ data: [
{ {
collection: { collection: {
name: 'databaseServices', documentation: 'Messaging service collection',
href: 'http://messagingServices',
name: 'messagingServices',
},
},
{
collection: {
documentation: 'Database service collection', documentation: 'Database service collection',
href: 'http://test', href: 'http://databaseServices',
name: 'databaseServices',
},
},
{
collection: {
documentation: 'Dashboard service collection',
href: 'http://dashboardServices',
name: 'dashboardServices',
}, },
}, },
], ],
}; };
const mockService = {
const mockDatabaseService = {
data: { data: {
data: [ data: [
{ {
@ -45,6 +65,50 @@ const mockService = {
connectionUrl: 'jdbc://localhost', connectionUrl: 'jdbc://localhost',
}, },
}, },
{
id: '847deda6-5342-42ed-b392-f0178a502c13',
name: 'mysql',
serviceType: 'MySql',
description: 'MySql service used for shopify data',
href: 'http://localhost:8585/api/v1/services/databaseServices/847deda6-5342-42ed-b392-f0178a502c13',
jdbc: {
driverClass: 'jdbc',
connectionUrl: 'jdbc://localhost',
},
},
],
},
};
const mockMessagingService = {
data: {
data: [
{
brokers: ['localhost:9092'],
description: 'Kafka messaging queue service',
href: 'http://localhost:8585/api/v1/services/messagingServices/473e2a9b-7555-42d3-904a-4c773c4dcd33',
id: '473e2a9b-7555-42d3-904a-4c773c4dcd33',
name: 'sample_kafka',
schemaRegistry: 'http://localhost:8081',
serviceType: 'Kafka',
},
],
},
};
const mockDashboardService = {
data: {
data: [
{
dashboardUrl: 'http://localhost:8088',
description: 'Supset Service',
href: 'http://localhost:8585/api/v1/services/dashboardServices/627a0545-39bc-47d1-bde8-df8bf19b4616',
id: '627a0545-39bc-47d1-bde8-df8bf19b4616',
name: 'sample_superset',
password: 'admin',
serviceType: 'Superset',
username: 'admin',
},
], ],
}, },
}; };
@ -54,7 +118,18 @@ jest.mock('../../axiosAPIs/serviceAPI', () => ({
getServiceDetails: jest getServiceDetails: jest
.fn() .fn()
.mockImplementation(() => Promise.resolve({ data: mockServiceDetails })), .mockImplementation(() => Promise.resolve({ data: mockServiceDetails })),
getServices: jest.fn().mockImplementation(() => Promise.resolve(mockService)), getServices: jest.fn().mockImplementation((type) => {
switch (type) {
case 'databaseServices':
return Promise.resolve(mockDatabaseService);
case 'messagingServices':
return Promise.resolve(mockMessagingService);
default:
return Promise.resolve(mockDashboardService);
}
}),
postService: jest.fn(), postService: jest.fn(),
updateService: jest.fn(), updateService: jest.fn(),
})); }));
@ -66,13 +141,122 @@ jest.mock(
} }
); );
jest.mock('../../components/common/non-admin-action/NonAdminAction', () => {
return jest
.fn()
.mockImplementation(({ children }: { children: ReactNode }) => (
<div>{children}</div>
));
});
jest.mock('../../components/Modals/AddServiceModal/AddServiceModal', () => ({
AddServiceModal: jest
.fn()
.mockReturnValue(<p data-testid="add-service-modal">AddServiceModal</p>),
}));
describe('Test Service page', () => { describe('Test Service page', () => {
it('Check if there is an element in the page', async () => { it('Check if there is an element in the page', async () => {
const { container } = render(<ServicesPage />, { const { container } = render(<ServicesPage />, {
wrapper: MemoryRouter, wrapper: MemoryRouter,
}); });
const services = await findByTestId(container, 'services-container'); const services = await findByTestId(container, 'services-container');
const tabs = await findAllByTestId(container, 'tab');
const dataContainer = await findByTestId(container, 'data-container');
expect(services).toBeInTheDocument(); expect(services).toBeInTheDocument();
expect(tabs.length).toBe(mockServiceDetails.data.length);
expect(dataContainer).toBeInTheDocument();
// mockService.data.data.length + 1 because it has add service card as well
expect(dataContainer.childElementCount).toBe(
mockDatabaseService.data.data.length + 1
);
});
it('On page load database service should be active tab with corresponding data', async () => {
const { container } = render(<ServicesPage />, {
wrapper: MemoryRouter,
});
const tabs = await findAllByTestId(container, 'tab');
const serviceNames = await findAllByTestId(container, 'service-name');
expect(tabs[0]).toHaveClass('active');
expect(serviceNames.map((s) => s.textContent)).toEqual(
mockDatabaseService.data.data.map((d) => d.name)
);
});
it('OnClick tab and data should change', async () => {
const { container } = render(<ServicesPage />, {
wrapper: MemoryRouter,
});
let tabs = await findAllByTestId(container, 'tab');
expect(tabs[0]).toHaveClass('active');
fireEvent.click(tabs[1]);
tabs = await findAllByTestId(container, 'tab');
const serviceNames = await findAllByTestId(container, 'service-name');
expect(tabs[1]).toHaveClass('active');
expect(serviceNames.map((s) => s.textContent)).toEqual(
mockMessagingService.data.data.map((d) => d.name)
);
});
it('OnClick of add service, AddServiceModal should open', async () => {
const { container } = render(<ServicesPage />, {
wrapper: MemoryRouter,
});
const addService = await findByTestId(container, 'add-services');
fireEvent.click(addService);
expect(
await findByTestId(container, 'add-service-modal')
).toBeInTheDocument();
});
it('OnClick of edit service, AddServiceModal should open', async () => {
const { container } = render(<ServicesPage />, {
wrapper: MemoryRouter,
});
const editService = await findAllByTestId(container, 'edit-service');
fireEvent.click(editService[0]);
expect(
await findByTestId(container, 'add-service-modal')
).toBeInTheDocument();
});
it('Card details should be display properly', async () => {
const { container } = render(<ServicesPage />, {
wrapper: MemoryRouter,
});
const serviceName = await findAllByTestId(container, 'service-name');
const serviceDescription = await findAllByTestId(
container,
'service-description'
);
const additionalField = await findAllByTestId(
container,
'additional-field'
);
const ingestion = await findAllByTestId(container, 'service-ingestion');
const type = await findAllByTestId(container, 'service-type');
const edit = await findAllByTestId(container, 'edit-service');
const deleteIcon = await findAllByTestId(container, 'delete-service');
const icon = await findAllByTestId(container, 'service-icon');
expect(serviceName.length).toBe(mockDatabaseService.data.data.length);
expect(serviceDescription.length).toBe(
mockDatabaseService.data.data.length
);
expect(additionalField.length).toBe(mockDatabaseService.data.data.length);
expect(ingestion.length).toBe(mockDatabaseService.data.data.length);
expect(type.length).toBe(mockDatabaseService.data.data.length);
expect(edit.length).toBe(mockDatabaseService.data.data.length);
expect(deleteIcon.length).toBe(mockDatabaseService.data.data.length);
expect(icon.length).toBe(mockDatabaseService.data.data.length);
}); });
}); });

View File

@ -226,7 +226,7 @@ const ServicesPage = () => {
return ( return (
<> <>
<div className="tw-mb-1"> <div className="tw-mb-1" data-testid="additional-field">
<label className="tw-mb-0">Driver Class:</label> <label className="tw-mb-0">Driver Class:</label>
<span className=" tw-ml-1 tw-font-normal tw-text-grey-body"> <span className=" tw-ml-1 tw-font-normal tw-text-grey-body">
{databaseService.jdbc.driverClass} {databaseService.jdbc.driverClass}
@ -240,7 +240,7 @@ const ServicesPage = () => {
return ( return (
<> <>
<div className="tw-mb-1"> <div className="tw-mb-1" data-testid="additional-field">
<label className="tw-mb-0">Brokers:</label> <label className="tw-mb-0">Brokers:</label>
<span className=" tw-ml-1 tw-font-normal tw-text-grey-body"> <span className=" tw-ml-1 tw-font-normal tw-text-grey-body">
{messagingService.brokers.join(', ')} {messagingService.brokers.join(', ')}
@ -254,7 +254,7 @@ const ServicesPage = () => {
return ( return (
<> <>
<div className="tw-mb-1"> <div className="tw-mb-1" data-testid="additional-field">
<label className="tw-mb-0"> <label className="tw-mb-0">
{dashboardService.serviceType === DashboardServiceType.Tableau {dashboardService.serviceType === DashboardServiceType.Tableau
? 'Site URL:' ? 'Site URL:'
@ -297,7 +297,7 @@ const ServicesPage = () => {
<> <>
{!isLoading ? ( {!isLoading ? (
<PageContainer> <PageContainer>
<div className="container-fluid"> <div className="container-fluid" data-testid="services-container">
<div className="tw-bg-transparent tw-mb-4"> <div className="tw-bg-transparent tw-mb-4">
<nav className="tw-flex tw-flex-row tw-gh-tabs-container tw-px-4"> <nav className="tw-flex tw-flex-row tw-gh-tabs-container tw-px-4">
{getServiceTabs().map((tab, index) => ( {getServiceTabs().map((tab, index) => (
@ -320,7 +320,7 @@ const ServicesPage = () => {
{serviceList.length ? ( {serviceList.length ? (
<div <div
className="tw-grid tw-grid-cols-4 tw-gap-4" className="tw-grid tw-grid-cols-4 tw-gap-4"
data-testid="services-container"> data-testid="data-container">
{serviceList.map((service, index) => ( {serviceList.map((service, index) => (
<div <div
className="tw-card tw-flex tw-py-2 tw-px-3 tw-justify-between tw-text-grey-muted" className="tw-card tw-flex tw-py-2 tw-px-3 tw-justify-between tw-text-grey-muted"
@ -332,12 +332,16 @@ const ServicesPage = () => {
service.serviceType || '' service.serviceType || ''
)}> )}>
<button> <button>
<h6 className="tw-text-base tw-text-grey-body tw-font-medium"> <h6
className="tw-text-base tw-text-grey-body tw-font-medium"
data-testid="service-name">
{service.name} {service.name}
</h6> </h6>
</button> </button>
</Link> </Link>
<div className="tw-text-grey-body tw-pb-1"> <div
className="tw-text-grey-body tw-pb-1"
data-testid="service-description">
{service.description ? ( {service.description ? (
<RichTextEditorPreviewer <RichTextEditorPreviewer
markdown={service.description} markdown={service.description}
@ -349,7 +353,7 @@ const ServicesPage = () => {
)} )}
</div> </div>
{getOptionalFields(service)} {getOptionalFields(service)}
<div className="tw-mb-1"> <div className="tw-mb-1" data-testid="service-ingestion">
<label className="tw-mb-0">Ingestion:</label> <label className="tw-mb-0">Ingestion:</label>
<span className=" tw-ml-1 tw-font-normal tw-text-grey-body"> <span className=" tw-ml-1 tw-font-normal tw-text-grey-body">
{service.ingestionSchedule?.repeatFrequency {service.ingestionSchedule?.repeatFrequency
@ -359,7 +363,7 @@ const ServicesPage = () => {
: '--'} : '--'}
</span> </span>
</div> </div>
<div className=""> <div className="" data-testid="service-type">
<label className="tw-mb-0">Type:</label> <label className="tw-mb-0">Type:</label>
<span className=" tw-ml-1 tw-font-normal tw-text-grey-body"> <span className=" tw-ml-1 tw-font-normal tw-text-grey-body">
{service.serviceType} {service.serviceType}
@ -373,6 +377,7 @@ const ServicesPage = () => {
title={TITLE_FOR_NON_ADMIN_ACTION}> title={TITLE_FOR_NON_ADMIN_ACTION}>
<button <button
className="tw-pr-3 focus:tw-outline-none" className="tw-pr-3 focus:tw-outline-none"
data-testid="edit-service"
onClick={() => handleEdit(service)}> onClick={() => handleEdit(service)}>
<SVGIcons <SVGIcons
alt="edit" alt="edit"
@ -387,6 +392,7 @@ const ServicesPage = () => {
title={TITLE_FOR_NON_ADMIN_ACTION}> title={TITLE_FOR_NON_ADMIN_ACTION}>
<button <button
className="focus:tw-outline-none" className="focus:tw-outline-none"
data-testid="delete-service"
onClick={() => handleDelete(service.id || '')}> onClick={() => handleDelete(service.id || '')}>
<SVGIcons <SVGIcons
alt="delete" alt="delete"
@ -397,7 +403,9 @@ const ServicesPage = () => {
</button> </button>
</NonAdminAction> </NonAdminAction>
</div> </div>
<div className="tw-flex tw-justify-end"> <div
className="tw-flex tw-justify-end"
data-testid="service-icon">
{/* {!isNull(serviceTypeLogo(service.serviceType)) && ( {/* {!isNull(serviceTypeLogo(service.serviceType)) && (
<img <img
alt="" alt=""
@ -417,6 +425,7 @@ const ServicesPage = () => {
<div className="tw-inline-block" style={{ width: '100%' }}> <div className="tw-inline-block" style={{ width: '100%' }}>
<div <div
className="tw-cursor-pointer tw-flex tw-flex-col tw-justify-center tw-items-center tw-py-6" className="tw-cursor-pointer tw-flex tw-flex-col tw-justify-center tw-items-center tw-py-6"
data-testid="add-services"
onClick={() => handleAddService()}> onClick={() => handleAddService()}>
<img alt="Add service" src={PLUS} /> <img alt="Add service" src={PLUS} />
<p className="tw-text-base tw-font-normal tw-mt-4"> <p className="tw-text-base tw-font-normal tw-mt-4">