mirror of
https://github.com/open-metadata/OpenMetadata.git
synced 2025-11-14 09:51:13 +00:00
Minor: improve unit test coverage (#15061)
* Minor: improve unit test coverage * added unit test for persona page component * remove unwanted code * added unit test for reset password component * added test for tour page * added unit test for quillLink * re-name the testUtils to jestTestUtils * miner fix * miner fix
This commit is contained in:
parent
24bbed8496
commit
2d24930f12
@ -0,0 +1,187 @@
|
|||||||
|
/*
|
||||||
|
* 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, screen } from '@testing-library/react';
|
||||||
|
import React from 'react';
|
||||||
|
import { getPersonaByName, updatePersona } from '../../../rest/PersonaAPI';
|
||||||
|
import { PersonaDetailsPage } from './PersonaDetailsPage';
|
||||||
|
|
||||||
|
jest.mock('../../../components/PageLayoutV1/PageLayoutV1', () => {
|
||||||
|
return jest.fn().mockImplementation(({ children }) => <div>{children}</div>);
|
||||||
|
});
|
||||||
|
jest.mock('../../../components/PageHeader/PageHeader.component', () => {
|
||||||
|
return jest.fn().mockImplementation(() => <div>PageHeader.component</div>);
|
||||||
|
});
|
||||||
|
jest.mock('../../../components/common/EntityDescription/DescriptionV1', () => {
|
||||||
|
return jest.fn().mockImplementation(() => <div>DescriptionV1.component</div>);
|
||||||
|
});
|
||||||
|
jest.mock(
|
||||||
|
'../../../components/common/EntityPageInfos/ManageButton/ManageButton',
|
||||||
|
() => {
|
||||||
|
return jest
|
||||||
|
.fn()
|
||||||
|
.mockImplementation(({ afterDeleteAction, onEditDisplayName }) => (
|
||||||
|
<div>
|
||||||
|
ManageButton.component
|
||||||
|
<button data-testid="delete-btn" onClick={afterDeleteAction}>
|
||||||
|
Delete
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
data-testid="display-name-btn"
|
||||||
|
onClick={() => onEditDisplayName({ displayName: 'Updated Name' })}>
|
||||||
|
Update Display Name
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
));
|
||||||
|
}
|
||||||
|
);
|
||||||
|
jest.mock(
|
||||||
|
'../../../components/common/UserSelectableList/UserSelectableList.component',
|
||||||
|
() => {
|
||||||
|
return {
|
||||||
|
UserSelectableList: jest
|
||||||
|
.fn()
|
||||||
|
.mockImplementation(({ children, onUpdate }) => (
|
||||||
|
<div
|
||||||
|
data-testid="user-selectable-list"
|
||||||
|
onClick={() => onUpdate({ id: 'ID', type: 'user' })}>
|
||||||
|
{children}
|
||||||
|
</div>
|
||||||
|
)),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
);
|
||||||
|
const mockPersona = {
|
||||||
|
id: '3cd223f3-fe1f-4ed8-9d74-dc80f5f91838',
|
||||||
|
name: 'testPersona',
|
||||||
|
fullyQualifiedName: 'testPersona',
|
||||||
|
displayName: 'Test Persona',
|
||||||
|
users: [
|
||||||
|
{
|
||||||
|
id: '1496d0c6-ebb2-453c-a8cc-b275c553f61f',
|
||||||
|
type: 'user',
|
||||||
|
name: 'admin',
|
||||||
|
fullyQualifiedName: 'admin',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
jest.mock('../../../rest/PersonaAPI', () => {
|
||||||
|
return {
|
||||||
|
getPersonaByName: jest
|
||||||
|
.fn()
|
||||||
|
.mockImplementation(() => Promise.resolve(mockPersona)),
|
||||||
|
updatePersona: jest.fn().mockImplementation(() => Promise.resolve()),
|
||||||
|
};
|
||||||
|
});
|
||||||
|
jest.mock('../../../hooks/useFqn', () => {
|
||||||
|
return { useFqn: jest.fn().mockReturnValue({ fqn: 'fqn' }) };
|
||||||
|
});
|
||||||
|
const mockUseHistory = {
|
||||||
|
push: jest.fn(),
|
||||||
|
};
|
||||||
|
jest.mock('react-router-dom', () => {
|
||||||
|
return {
|
||||||
|
useHistory: jest.fn().mockImplementation(() => mockUseHistory),
|
||||||
|
};
|
||||||
|
});
|
||||||
|
jest.mock(
|
||||||
|
'../../../components/common/ErrorWithPlaceholder/NoDataPlaceholder',
|
||||||
|
() => {
|
||||||
|
return jest
|
||||||
|
.fn()
|
||||||
|
.mockImplementation(() => <div>NoDataPlaceholder.component</div>);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
jest.mock('../../../components/PermissionProvider/PermissionProvider', () => ({
|
||||||
|
usePermissionProvider: jest.fn().mockReturnValue({
|
||||||
|
getEntityPermissionByFqn: jest.fn().mockResolvedValue({
|
||||||
|
Create: true,
|
||||||
|
Delete: true,
|
||||||
|
ViewAll: true,
|
||||||
|
EditAll: true,
|
||||||
|
EditDescription: true,
|
||||||
|
EditDisplayName: true,
|
||||||
|
EditCustomFields: true,
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
}));
|
||||||
|
|
||||||
|
describe('PersonaDetailsPage', () => {
|
||||||
|
it('Component should render', async () => {
|
||||||
|
render(<PersonaDetailsPage />);
|
||||||
|
|
||||||
|
expect(await screen.findByText('PageHeader.component')).toBeInTheDocument();
|
||||||
|
expect(
|
||||||
|
await screen.findByText('ManageButton.component')
|
||||||
|
).toBeInTheDocument();
|
||||||
|
expect(
|
||||||
|
await screen.findByText('DescriptionV1.component')
|
||||||
|
).toBeInTheDocument();
|
||||||
|
expect(await screen.findByTestId('add-user-button')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('NoDataPlaceholder', async () => {
|
||||||
|
(getPersonaByName as jest.Mock).mockImplementationOnce(() =>
|
||||||
|
Promise.reject()
|
||||||
|
);
|
||||||
|
render(<PersonaDetailsPage />);
|
||||||
|
|
||||||
|
expect(
|
||||||
|
await screen.findByText('NoDataPlaceholder.component')
|
||||||
|
).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('handleAfterDeleteAction should call after delete', async () => {
|
||||||
|
render(<PersonaDetailsPage />);
|
||||||
|
|
||||||
|
const deleteBtn = await screen.findByTestId('delete-btn');
|
||||||
|
|
||||||
|
fireEvent.click(deleteBtn);
|
||||||
|
|
||||||
|
expect(mockUseHistory.push).toHaveBeenCalledWith(
|
||||||
|
'/settings/members/persona'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('handleDisplayNameUpdate should call after updating displayName', async () => {
|
||||||
|
const mockUpdatePersona = updatePersona as jest.Mock;
|
||||||
|
render(<PersonaDetailsPage />);
|
||||||
|
|
||||||
|
const updateName = await screen.findByTestId('display-name-btn');
|
||||||
|
|
||||||
|
fireEvent.click(updateName);
|
||||||
|
|
||||||
|
expect(mockUpdatePersona).toHaveBeenCalledWith(mockPersona.id, [
|
||||||
|
{ op: 'replace', path: '/displayName', value: 'Updated Name' },
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('add user should work', async () => {
|
||||||
|
const mockUpdatePersona = updatePersona as jest.Mock;
|
||||||
|
render(<PersonaDetailsPage />);
|
||||||
|
|
||||||
|
const addUser = await screen.findByTestId('user-selectable-list');
|
||||||
|
|
||||||
|
fireEvent.click(addUser);
|
||||||
|
|
||||||
|
expect(mockUpdatePersona).toHaveBeenCalledWith(mockPersona.id, [
|
||||||
|
{
|
||||||
|
op: 'replace',
|
||||||
|
path: '/users',
|
||||||
|
value: {
|
||||||
|
id: 'ID',
|
||||||
|
type: 'user',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
});
|
||||||
@ -10,15 +10,16 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
import { Button, Row, Tabs } from 'antd';
|
import { Button, Col, Row, Tabs } from 'antd';
|
||||||
import Col from 'antd/es/grid/col';
|
|
||||||
import { AxiosError } from 'axios';
|
import { AxiosError } from 'axios';
|
||||||
import { compare } from 'fast-json-patch';
|
import { compare } from 'fast-json-patch';
|
||||||
|
import { isUndefined } from 'lodash';
|
||||||
import React, { useCallback, useEffect, useState } from 'react';
|
import React, { useCallback, useEffect, useState } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { useHistory } from 'react-router-dom';
|
import { useHistory } from 'react-router-dom';
|
||||||
import DescriptionV1 from '../../../components/common/EntityDescription/DescriptionV1';
|
import DescriptionV1 from '../../../components/common/EntityDescription/DescriptionV1';
|
||||||
import ManageButton from '../../../components/common/EntityPageInfos/ManageButton/ManageButton';
|
import ManageButton from '../../../components/common/EntityPageInfos/ManageButton/ManageButton';
|
||||||
|
import NoDataPlaceholder from '../../../components/common/ErrorWithPlaceholder/NoDataPlaceholder';
|
||||||
import { UserSelectableList } from '../../../components/common/UserSelectableList/UserSelectableList.component';
|
import { UserSelectableList } from '../../../components/common/UserSelectableList/UserSelectableList.component';
|
||||||
import Loader from '../../../components/Loader/Loader';
|
import Loader from '../../../components/Loader/Loader';
|
||||||
import { EntityName } from '../../../components/Modals/EntityNameModal/EntityNameModal.interface';
|
import { EntityName } from '../../../components/Modals/EntityNameModal/EntityNameModal.interface';
|
||||||
@ -31,6 +32,7 @@ import {
|
|||||||
GlobalSettingOptions,
|
GlobalSettingOptions,
|
||||||
GlobalSettingsMenuCategory,
|
GlobalSettingsMenuCategory,
|
||||||
} from '../../../constants/GlobalSettings.constants';
|
} from '../../../constants/GlobalSettings.constants';
|
||||||
|
import { SIZE } from '../../../enums/common.enum';
|
||||||
import { EntityType } from '../../../enums/entity.enum';
|
import { EntityType } from '../../../enums/entity.enum';
|
||||||
import { Persona } from '../../../generated/entity/teams/persona';
|
import { Persona } from '../../../generated/entity/teams/persona';
|
||||||
import { useFqn } from '../../../hooks/useFqn';
|
import { useFqn } from '../../../hooks/useFqn';
|
||||||
@ -111,23 +113,6 @@ export const PersonaDetailsPage = () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleRestorePersona = async () => {
|
|
||||||
if (!personaDetails) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const updatedData = { ...personaDetails };
|
|
||||||
const diff = compare(personaDetails, updatedData);
|
|
||||||
|
|
||||||
try {
|
|
||||||
const response = await updatePersona(personaDetails?.id, diff);
|
|
||||||
setPersonaDetails(response);
|
|
||||||
} catch (error) {
|
|
||||||
showErrorToast(error as AxiosError);
|
|
||||||
} finally {
|
|
||||||
setIsEdit(false);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const handlePersonaUpdate = useCallback(
|
const handlePersonaUpdate = useCallback(
|
||||||
async (data: Partial<Persona>) => {
|
async (data: Partial<Persona>) => {
|
||||||
if (!personaDetails) {
|
if (!personaDetails) {
|
||||||
@ -167,10 +152,14 @@ export const PersonaDetailsPage = () => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
if (isLoading || !personaDetails) {
|
if (isLoading) {
|
||||||
return <Loader />;
|
return <Loader />;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isUndefined(personaDetails)) {
|
||||||
|
return <NoDataPlaceholder size={SIZE.LARGE} />;
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PageLayoutV1 pageTitle={personaDetails.name}>
|
<PageLayoutV1 pageTitle={personaDetails.name}>
|
||||||
<Row className="m-b-md page-container" gutter={[0, 16]}>
|
<Row className="m-b-md page-container" gutter={[0, 16]}>
|
||||||
@ -196,7 +185,6 @@ export const PersonaDetailsPage = () => {
|
|||||||
entityName={personaDetails.name}
|
entityName={personaDetails.name}
|
||||||
entityType={EntityType.PERSONA}
|
entityType={EntityType.PERSONA}
|
||||||
onEditDisplayName={handleDisplayNameUpdate}
|
onEditDisplayName={handleDisplayNameUpdate}
|
||||||
onRestoreEntity={handleRestorePersona}
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</Col>
|
</Col>
|
||||||
|
|||||||
@ -0,0 +1,175 @@
|
|||||||
|
/*
|
||||||
|
* 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 { getAllPersonas } from '../../../rest/PersonaAPI';
|
||||||
|
import { PersonaPage } from './PersonaPage';
|
||||||
|
jest.mock('../../../components/PageLayoutV1/PageLayoutV1', () => {
|
||||||
|
return jest.fn().mockImplementation(({ children }) => <div>{children}</div>);
|
||||||
|
});
|
||||||
|
jest.mock('../../../components/PageHeader/PageHeader.component', () => {
|
||||||
|
return jest.fn().mockImplementation(() => <div>PageHeader.component</div>);
|
||||||
|
});
|
||||||
|
jest.mock(
|
||||||
|
'../../../components/common/TitleBreadcrumb/TitleBreadcrumb.component',
|
||||||
|
() => {
|
||||||
|
return jest
|
||||||
|
.fn()
|
||||||
|
.mockImplementation(() => <div>TitleBreadcrumb.component</div>);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
jest.mock('../../../components/common/NextPrevious/NextPrevious', () => {
|
||||||
|
return jest.fn().mockImplementation(() => <div>NextPrevious.component</div>);
|
||||||
|
});
|
||||||
|
jest.mock(
|
||||||
|
'../../../components/common/ErrorWithPlaceholder/ErrorPlaceHolder',
|
||||||
|
() => {
|
||||||
|
return jest
|
||||||
|
.fn()
|
||||||
|
.mockImplementation(() => <div>ErrorPlaceHolder.component</div>);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
jest.mock('../../../components/common/DeleteWidget/DeleteWidgetModal', () => {
|
||||||
|
return jest
|
||||||
|
.fn()
|
||||||
|
.mockImplementation(() => <div>DeleteWidgetModal.component</div>);
|
||||||
|
});
|
||||||
|
jest.mock(
|
||||||
|
'../../../components/Persona/PersonaDetailsCard/PersonaDetailsCard',
|
||||||
|
() => {
|
||||||
|
return {
|
||||||
|
PersonaDetailsCard: jest
|
||||||
|
.fn()
|
||||||
|
.mockImplementation(() => <div>PersonaDetailsCard.component</div>),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
);
|
||||||
|
jest.mock(
|
||||||
|
'../../../components/Persona/AddEditPersona/AddEditPersona.component',
|
||||||
|
() => {
|
||||||
|
return {
|
||||||
|
AddEditPersonaForm: jest.fn().mockImplementation(({ onSave }) => (
|
||||||
|
<div>
|
||||||
|
AddEditPersonaForm.component
|
||||||
|
<button data-testid="save-edit-persona-save" onClick={onSave}>
|
||||||
|
Save
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
)),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
);
|
||||||
|
jest.mock('../../../hooks/paging/usePaging', () => ({
|
||||||
|
usePaging: jest.fn().mockReturnValue({
|
||||||
|
currentPage: 1,
|
||||||
|
showPagination: true,
|
||||||
|
pageSize: 10,
|
||||||
|
handlePageChange: jest.fn(),
|
||||||
|
handlePagingChange: jest.fn(),
|
||||||
|
handlePageSizeChange: jest.fn(),
|
||||||
|
}),
|
||||||
|
}));
|
||||||
|
jest.mock('../../../rest/PersonaAPI', () => {
|
||||||
|
return {
|
||||||
|
getAllPersonas: jest
|
||||||
|
.fn()
|
||||||
|
.mockImplementation(() => Promise.resolve({ data: [] })),
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('PersonaPage', () => {
|
||||||
|
it('Component should render', async () => {
|
||||||
|
act(() => {
|
||||||
|
render(<PersonaPage />);
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(
|
||||||
|
await screen.findByTestId('user-list-v1-component')
|
||||||
|
).toBeInTheDocument();
|
||||||
|
expect(await screen.findByTestId('add-persona-button')).toBeInTheDocument();
|
||||||
|
expect(
|
||||||
|
await screen.findByText('TitleBreadcrumb.component')
|
||||||
|
).toBeInTheDocument();
|
||||||
|
expect(await screen.findByText('PageHeader.component')).toBeInTheDocument();
|
||||||
|
expect(
|
||||||
|
await screen.findByText('ErrorPlaceHolder.component')
|
||||||
|
).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('AddEditPersonaForm should render onclick of add persona', async () => {
|
||||||
|
act(() => {
|
||||||
|
render(<PersonaPage />);
|
||||||
|
});
|
||||||
|
const addPersonaButton = await screen.findByTestId('add-persona-button');
|
||||||
|
await act(async () => {
|
||||||
|
fireEvent.click(addPersonaButton);
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(
|
||||||
|
await screen.findByText('AddEditPersonaForm.component')
|
||||||
|
).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('handlePersonaAddEditSave should be called onClick of save button', async () => {
|
||||||
|
const mockGetAllPersonas = getAllPersonas as jest.Mock;
|
||||||
|
act(() => {
|
||||||
|
render(<PersonaPage />);
|
||||||
|
});
|
||||||
|
const addPersonaButton = await screen.findByTestId('add-persona-button');
|
||||||
|
fireEvent.click(addPersonaButton);
|
||||||
|
|
||||||
|
expect(
|
||||||
|
await screen.findByText('AddEditPersonaForm.component')
|
||||||
|
).toBeInTheDocument();
|
||||||
|
|
||||||
|
await act(async () => {
|
||||||
|
fireEvent.click(await screen.findByTestId('save-edit-persona-save'));
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(mockGetAllPersonas).toHaveBeenCalledWith({
|
||||||
|
after: undefined,
|
||||||
|
before: undefined,
|
||||||
|
fields: 'users',
|
||||||
|
limit: 10,
|
||||||
|
});
|
||||||
|
expect(mockGetAllPersonas).toHaveBeenCalledTimes(2);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render PersonaDetailsCard when data is available', async () => {
|
||||||
|
(getAllPersonas as jest.Mock).mockImplementationOnce(() =>
|
||||||
|
Promise.resolve({
|
||||||
|
data: [
|
||||||
|
{
|
||||||
|
id: 'id1',
|
||||||
|
name: 'sales',
|
||||||
|
fullyQualifiedName: 'sales',
|
||||||
|
displayName: 'Sales',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'id2',
|
||||||
|
name: 'purchase',
|
||||||
|
fullyQualifiedName: 'purchase',
|
||||||
|
displayName: 'purchase',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
})
|
||||||
|
);
|
||||||
|
act(() => {
|
||||||
|
render(<PersonaPage />);
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(
|
||||||
|
await screen.findAllByText('PersonaDetailsCard.component')
|
||||||
|
).toHaveLength(2);
|
||||||
|
});
|
||||||
|
});
|
||||||
@ -15,7 +15,6 @@ import Card from 'antd/lib/card/Card';
|
|||||||
import { isEmpty } from 'lodash';
|
import { isEmpty } from 'lodash';
|
||||||
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import DeleteWidgetModal from '../../../components/common/DeleteWidget/DeleteWidgetModal';
|
|
||||||
import ErrorPlaceHolder from '../../../components/common/ErrorWithPlaceholder/ErrorPlaceHolder';
|
import ErrorPlaceHolder from '../../../components/common/ErrorWithPlaceholder/ErrorPlaceHolder';
|
||||||
import NextPrevious from '../../../components/common/NextPrevious/NextPrevious';
|
import NextPrevious from '../../../components/common/NextPrevious/NextPrevious';
|
||||||
import { PagingHandlerParams } from '../../../components/common/NextPrevious/NextPrevious.interface';
|
import { PagingHandlerParams } from '../../../components/common/NextPrevious/NextPrevious.interface';
|
||||||
@ -28,13 +27,11 @@ import { PersonaDetailsCard } from '../../../components/Persona/PersonaDetailsCa
|
|||||||
import { GlobalSettingsMenuCategory } from '../../../constants/GlobalSettings.constants';
|
import { GlobalSettingsMenuCategory } from '../../../constants/GlobalSettings.constants';
|
||||||
import { PAGE_HEADERS } from '../../../constants/PageHeaders.constant';
|
import { PAGE_HEADERS } from '../../../constants/PageHeaders.constant';
|
||||||
import { ERROR_PLACEHOLDER_TYPE } from '../../../enums/common.enum';
|
import { ERROR_PLACEHOLDER_TYPE } from '../../../enums/common.enum';
|
||||||
import { EntityType } from '../../../enums/entity.enum';
|
|
||||||
import { Persona } from '../../../generated/entity/teams/persona';
|
import { Persona } from '../../../generated/entity/teams/persona';
|
||||||
import { Paging } from '../../../generated/type/paging';
|
import { Paging } from '../../../generated/type/paging';
|
||||||
import { useAuth } from '../../../hooks/authHooks';
|
import { useAuth } from '../../../hooks/authHooks';
|
||||||
import { usePaging } from '../../../hooks/paging/usePaging';
|
import { usePaging } from '../../../hooks/paging/usePaging';
|
||||||
import { getAllPersonas } from '../../../rest/PersonaAPI';
|
import { getAllPersonas } from '../../../rest/PersonaAPI';
|
||||||
import { getEntityName } from '../../../utils/EntityUtils';
|
|
||||||
import { getSettingPageEntityBreadCrumb } from '../../../utils/GlobalSettingsUtils';
|
import { getSettingPageEntityBreadCrumb } from '../../../utils/GlobalSettingsUtils';
|
||||||
|
|
||||||
export const PersonaPage = () => {
|
export const PersonaPage = () => {
|
||||||
@ -46,8 +43,6 @@ export const PersonaPage = () => {
|
|||||||
const [addEditPersona, setAddEditPersona] = useState<Persona>();
|
const [addEditPersona, setAddEditPersona] = useState<Persona>();
|
||||||
|
|
||||||
const [isLoading, setIsLoading] = useState(false);
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
|
|
||||||
const [personaDeleting, setPersonaDeleting] = useState<Persona>();
|
|
||||||
const {
|
const {
|
||||||
currentPage,
|
currentPage,
|
||||||
handlePageChange,
|
handlePageChange,
|
||||||
@ -132,7 +127,7 @@ export const PersonaPage = () => {
|
|||||||
<Row
|
<Row
|
||||||
className="user-listing page-container p-b-md"
|
className="user-listing page-container p-b-md"
|
||||||
data-testid="user-list-v1-component"
|
data-testid="user-list-v1-component"
|
||||||
gutter={[0, 16]}>
|
gutter={[16, 16]}>
|
||||||
<Col span={24}>
|
<Col span={24}>
|
||||||
<TitleBreadcrumb titleLinks={breadcrumbs} />
|
<TitleBreadcrumb titleLinks={breadcrumbs} />
|
||||||
</Col>
|
</Col>
|
||||||
@ -185,18 +180,6 @@ export const PersonaPage = () => {
|
|||||||
onSave={handlePersonaAddEditSave}
|
onSave={handlePersonaAddEditSave}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<DeleteWidgetModal
|
|
||||||
afterDeleteAction={() => fetchPersonas()}
|
|
||||||
allowSoftDelete={false}
|
|
||||||
entityId={personaDeleting?.id ?? ''}
|
|
||||||
entityName={getEntityName(personaDeleting)}
|
|
||||||
entityType={EntityType.PERSONA}
|
|
||||||
visible={Boolean(personaDeleting)}
|
|
||||||
onCancel={() => {
|
|
||||||
setPersonaDeleting(undefined);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</Row>
|
</Row>
|
||||||
</PageLayoutV1>
|
</PageLayoutV1>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -11,9 +11,10 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Alert, Button, Card, Col, Form, Input, Row, Typography } from 'antd';
|
import { Button, Card, Col, Form, Input, Row, Typography } from 'antd';
|
||||||
import { AxiosError } from 'axios';
|
import { AxiosError } from 'axios';
|
||||||
import React, { useEffect, useMemo } from 'react';
|
import QueryString from 'qs';
|
||||||
|
import React, { useMemo } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { useHistory, useLocation } from 'react-router-dom';
|
import { useHistory, useLocation } from 'react-router-dom';
|
||||||
import { useBasicAuth } from '../../components/Auth/AuthProviders/BasicAuthProvider';
|
import { useBasicAuth } from '../../components/Auth/AuthProviders/BasicAuthProvider';
|
||||||
@ -21,7 +22,6 @@ import BrandImage from '../../components/common/BrandImage/BrandImage';
|
|||||||
import { ROUTES, VALIDATION_MESSAGES } from '../../constants/constants';
|
import { ROUTES, VALIDATION_MESSAGES } from '../../constants/constants';
|
||||||
import { passwordRegex } from '../../constants/regex.constants';
|
import { passwordRegex } from '../../constants/regex.constants';
|
||||||
import { PasswordResetRequest } from '../../generated/auth/passwordResetRequest';
|
import { PasswordResetRequest } from '../../generated/auth/passwordResetRequest';
|
||||||
import { getUserNameAndToken } from '../../utils/ResetPassword.utils';
|
|
||||||
import { showErrorToast } from '../../utils/ToastUtils';
|
import { showErrorToast } from '../../utils/ToastUtils';
|
||||||
import './reset-password.style.less';
|
import './reset-password.style.less';
|
||||||
|
|
||||||
@ -36,24 +36,24 @@ const ResetPassword = () => {
|
|||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
|
|
||||||
const { handleResetPassword } = useBasicAuth();
|
const { handleResetPassword } = useBasicAuth();
|
||||||
const tokenValid = false;
|
|
||||||
useEffect(() => {
|
|
||||||
// check for token validity
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const history = useHistory();
|
const history = useHistory();
|
||||||
|
|
||||||
const params = useMemo(
|
const params = useMemo(() => {
|
||||||
() => getUserNameAndToken(location.search),
|
const search = location.search;
|
||||||
[location]
|
const data = QueryString.parse(
|
||||||
);
|
search.startsWith('?') ? search.substring(1) : search
|
||||||
|
);
|
||||||
|
|
||||||
|
return data as { token: string; user: string };
|
||||||
|
}, [location]);
|
||||||
|
|
||||||
const password = Form.useWatch('password', form);
|
const password = Form.useWatch('password', form);
|
||||||
|
|
||||||
const handleSubmit = async (data: ResetFormData) => {
|
const handleSubmit = async (data: ResetFormData) => {
|
||||||
const ResetRequest = {
|
const ResetRequest = {
|
||||||
token: params?.token,
|
token: params?.token,
|
||||||
username: params?.userName,
|
username: params?.user,
|
||||||
password: data.password,
|
password: data.password,
|
||||||
confirmPassword: data.confirmPassword,
|
confirmPassword: data.confirmPassword,
|
||||||
} as PasswordResetRequest;
|
} as PasswordResetRequest;
|
||||||
@ -66,114 +66,93 @@ const ResetPassword = () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleReVerify = () => history.push(ROUTES.FORGOT_PASSWORD);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="h-full p-y-36">
|
<div className="h-full p-y-36" data-testid="reset-password-container">
|
||||||
{tokenValid ? (
|
<Card
|
||||||
<Card
|
bodyStyle={{ padding: '48px' }}
|
||||||
bodyStyle={{ padding: '48px' }}
|
className="m-auto p-x-lg"
|
||||||
className="m-auto p-x-lg"
|
style={{ maxWidth: '450px' }}>
|
||||||
style={{ maxWidth: '450px' }}>
|
<Row gutter={[16, 24]}>
|
||||||
<div className="mt-24">
|
<Col className="text-center" data-testid="brand-image" span={24}>
|
||||||
<Alert
|
<BrandImage className="m-auto" height="auto" width={200} />
|
||||||
showIcon
|
</Col>
|
||||||
description="Please re-initiate email verification process"
|
|
||||||
message={t('message.email-verification-token-expired')}
|
|
||||||
type="error"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="mt-20 flex-center">
|
<Col className="mt-12 text-center" span={24}>
|
||||||
<Typography.Link underline onClick={handleReVerify}>
|
<Typography.Text className="text-xl font-medium text-grey-muted">
|
||||||
{t('label.re-verify')}
|
{t('label.reset-your-password')}
|
||||||
</Typography.Link>
|
</Typography.Text>
|
||||||
</div>
|
</Col>
|
||||||
</Card>
|
|
||||||
) : (
|
|
||||||
<Card
|
|
||||||
bodyStyle={{ padding: '48px' }}
|
|
||||||
className="m-auto p-x-lg"
|
|
||||||
style={{ maxWidth: '450px' }}>
|
|
||||||
<Row gutter={[16, 24]}>
|
|
||||||
<Col className="text-center" span={24}>
|
|
||||||
<BrandImage className="m-auto" height="auto" width={200} />
|
|
||||||
</Col>
|
|
||||||
|
|
||||||
<Col className="mt-12 text-center" span={24}>
|
<Col span={24}>
|
||||||
<Typography.Text className="text-xl font-medium text-grey-muted">
|
<Form
|
||||||
{t('label.reset-your-password')}
|
className="w-full"
|
||||||
</Typography.Text>
|
form={form}
|
||||||
</Col>
|
layout="vertical"
|
||||||
|
validateMessages={VALIDATION_MESSAGES}
|
||||||
|
onFinish={handleSubmit}>
|
||||||
|
<Form.Item
|
||||||
|
label={t('label.new-password')}
|
||||||
|
name="password"
|
||||||
|
rules={[
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
message: t('message.field-text-is-required', {
|
||||||
|
fieldText: t('label.password'),
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
pattern: passwordRegex,
|
||||||
|
message: t('message.password-pattern-error'),
|
||||||
|
},
|
||||||
|
]}>
|
||||||
|
<Input.Password
|
||||||
|
autoComplete="off"
|
||||||
|
className="w-full"
|
||||||
|
data-testid="password"
|
||||||
|
placeholder={t('label.enter-entity', {
|
||||||
|
entity: t('label.new-password'),
|
||||||
|
})}
|
||||||
|
/>
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item
|
||||||
|
label={t('label.confirm-new-password')}
|
||||||
|
name="confirmPassword"
|
||||||
|
rules={[
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
message: t('message.field-text-is-required', {
|
||||||
|
fieldText: t('label.confirm-new-password'),
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
validator: (_, value) => {
|
||||||
|
if (password === value) {
|
||||||
|
return Promise.resolve();
|
||||||
|
}
|
||||||
|
|
||||||
<Col span={24}>
|
return Promise.reject(t('label.password-not-match'));
|
||||||
<Form
|
|
||||||
className="w-full"
|
|
||||||
form={form}
|
|
||||||
layout="vertical"
|
|
||||||
validateMessages={VALIDATION_MESSAGES}
|
|
||||||
onFinish={handleSubmit}>
|
|
||||||
<Form.Item
|
|
||||||
label={t('label.new-password')}
|
|
||||||
name="password"
|
|
||||||
rules={[
|
|
||||||
{
|
|
||||||
required: true,
|
|
||||||
message: t('message.field-text-is-required', {
|
|
||||||
fieldText: t('label.password'),
|
|
||||||
}),
|
|
||||||
},
|
},
|
||||||
{
|
},
|
||||||
pattern: passwordRegex,
|
]}>
|
||||||
message: t('message.password-pattern-error'),
|
<Input.Password
|
||||||
},
|
autoComplete="off"
|
||||||
]}>
|
className="w-full"
|
||||||
<Input.Password
|
data-testid="confirm-password"
|
||||||
autoComplete="off"
|
placeholder={t('label.re-enter-new-password')}
|
||||||
className="w-full"
|
/>
|
||||||
placeholder={t('label.enter-entity', {
|
</Form.Item>
|
||||||
entity: t('label.new-password'),
|
|
||||||
})}
|
|
||||||
/>
|
|
||||||
</Form.Item>
|
|
||||||
<Form.Item
|
|
||||||
label={t('label.confirm-new-password')}
|
|
||||||
name="confirmPassword"
|
|
||||||
rules={[
|
|
||||||
{
|
|
||||||
required: true,
|
|
||||||
message: t('message.field-text-is-required', {
|
|
||||||
fieldText: t('label.confirm-new-password'),
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
validator: (_, value) => {
|
|
||||||
if (password === value) {
|
|
||||||
return Promise.resolve();
|
|
||||||
}
|
|
||||||
|
|
||||||
return Promise.reject(t('label.password-not-match'));
|
<Button
|
||||||
},
|
className="w-full m-t-lg"
|
||||||
},
|
data-testid="submit-button"
|
||||||
]}>
|
htmlType="submit"
|
||||||
<Input.Password
|
type="primary">
|
||||||
autoComplete="off"
|
{t('label.submit')}
|
||||||
className="w-full"
|
</Button>
|
||||||
placeholder={t('label.re-enter-new-password')}
|
</Form>
|
||||||
/>
|
</Col>
|
||||||
</Form.Item>
|
</Row>
|
||||||
|
</Card>
|
||||||
<Button
|
|
||||||
className="w-full m-t-lg"
|
|
||||||
htmlType="submit"
|
|
||||||
type="primary">
|
|
||||||
{t('label.submit')}
|
|
||||||
</Button>
|
|
||||||
</Form>
|
|
||||||
</Col>
|
|
||||||
</Row>
|
|
||||||
</Card>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -0,0 +1,107 @@
|
|||||||
|
/*
|
||||||
|
* 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 ResetPassword from './ResetPassword.component';
|
||||||
|
|
||||||
|
jest.mock('react-router-dom', () => {
|
||||||
|
return {
|
||||||
|
useHistory: jest.fn(),
|
||||||
|
useLocation: jest
|
||||||
|
.fn()
|
||||||
|
.mockImplementation(() => ({ search: '?user=admin&token=token' })),
|
||||||
|
};
|
||||||
|
});
|
||||||
|
const mockHandleResetPassword = jest.fn();
|
||||||
|
jest.mock('../../components/Auth/AuthProviders/BasicAuthProvider', () => {
|
||||||
|
return {
|
||||||
|
useBasicAuth: jest.fn().mockImplementation(() => ({
|
||||||
|
handleResetPassword: mockHandleResetPassword,
|
||||||
|
})),
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('ResetPassword', () => {
|
||||||
|
it('should render correctly', async () => {
|
||||||
|
render(<ResetPassword />);
|
||||||
|
|
||||||
|
expect(
|
||||||
|
await screen.findByTestId('reset-password-container')
|
||||||
|
).toBeInTheDocument();
|
||||||
|
expect(await screen.findByTestId('brand-image')).toBeInTheDocument();
|
||||||
|
expect(await screen.findByTestId('password')).toBeInTheDocument();
|
||||||
|
expect(await screen.findByTestId('confirm-password')).toBeInTheDocument();
|
||||||
|
expect(await screen.findByTestId('submit-button')).toBeInTheDocument();
|
||||||
|
expect(
|
||||||
|
await screen.findByText('label.reset-your-password')
|
||||||
|
).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('form submit should work', async () => {
|
||||||
|
jest.useFakeTimers();
|
||||||
|
render(<ResetPassword />);
|
||||||
|
|
||||||
|
const submitButton = await screen.findByTestId('submit-button');
|
||||||
|
const password = await screen.findByTestId('password');
|
||||||
|
const confirmPwd = await screen.findByTestId('confirm-password');
|
||||||
|
|
||||||
|
await act(async () => {
|
||||||
|
fireEvent.change(password, { target: { value: 'Password@123' } });
|
||||||
|
fireEvent.change(confirmPwd, { target: { value: 'Password@123' } });
|
||||||
|
fireEvent.click(submitButton);
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(mockHandleResetPassword).toHaveBeenCalledWith({
|
||||||
|
confirmPassword: 'Password@123',
|
||||||
|
password: 'Password@123',
|
||||||
|
token: 'token',
|
||||||
|
username: 'admin',
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('confirm password alert should be visible', async () => {
|
||||||
|
jest.useFakeTimers();
|
||||||
|
render(<ResetPassword />);
|
||||||
|
|
||||||
|
const submitButton = await screen.findByTestId('submit-button');
|
||||||
|
const password = await screen.findByTestId('password');
|
||||||
|
const confirmPwd = await screen.findByTestId('confirm-password');
|
||||||
|
|
||||||
|
await act(async () => {
|
||||||
|
fireEvent.change(password, { target: { value: 'Password@123' } });
|
||||||
|
fireEvent.change(confirmPwd, { target: { value: 'Password@1234' } });
|
||||||
|
fireEvent.click(submitButton);
|
||||||
|
});
|
||||||
|
jest.advanceTimersByTime(20);
|
||||||
|
|
||||||
|
expect(
|
||||||
|
await screen.findByText('label.password-not-match')
|
||||||
|
).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('required field validation should work', async () => {
|
||||||
|
jest.useFakeTimers();
|
||||||
|
render(<ResetPassword />);
|
||||||
|
|
||||||
|
const submitButton = await screen.findByTestId('submit-button');
|
||||||
|
|
||||||
|
await act(async () => {
|
||||||
|
fireEvent.click(submitButton);
|
||||||
|
});
|
||||||
|
jest.advanceTimersByTime(20);
|
||||||
|
|
||||||
|
expect(
|
||||||
|
await screen.findAllByText('message.field-text-is-required')
|
||||||
|
).toHaveLength(2);
|
||||||
|
});
|
||||||
|
});
|
||||||
@ -0,0 +1,105 @@
|
|||||||
|
/*
|
||||||
|
* 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, screen } from '@testing-library/react';
|
||||||
|
import React from 'react';
|
||||||
|
import { useTourProvider } from '../../components/TourProvider/TourProvider';
|
||||||
|
import { CurrentTourPageType } from '../../enums/tour.enum';
|
||||||
|
import TourPage from './TourPage.component';
|
||||||
|
|
||||||
|
const mockUseTourProvider = {
|
||||||
|
updateIsTourOpen: jest.fn(),
|
||||||
|
currentTourPage: '',
|
||||||
|
updateActiveTab: jest.fn(),
|
||||||
|
updateTourPage: jest.fn(),
|
||||||
|
updateTourSearch: jest.fn(),
|
||||||
|
};
|
||||||
|
jest.mock('../../components/TourProvider/TourProvider', () => ({
|
||||||
|
useTourProvider: jest.fn().mockImplementation(() => mockUseTourProvider),
|
||||||
|
}));
|
||||||
|
jest.mock('../../components/AppTour/Tour', () => {
|
||||||
|
return jest.fn().mockImplementation(({ steps }) => (
|
||||||
|
<div>
|
||||||
|
Tour.component{' '}
|
||||||
|
<button data-testid="clear-btn" onClick={steps.clearSearchTerm}>
|
||||||
|
clear
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
));
|
||||||
|
});
|
||||||
|
jest.mock('../MyDataPage/MyDataPage.component', () => {
|
||||||
|
return jest.fn().mockImplementation(() => <div>MyDataPage.component</div>);
|
||||||
|
});
|
||||||
|
jest.mock('../ExplorePage/ExplorePageV1.component', () => {
|
||||||
|
return jest
|
||||||
|
.fn()
|
||||||
|
.mockImplementation(() => <div>ExplorePageV1Component.component</div>);
|
||||||
|
});
|
||||||
|
jest.mock('../TableDetailsPageV1/TableDetailsPageV1', () => {
|
||||||
|
return jest
|
||||||
|
.fn()
|
||||||
|
.mockImplementation(() => <div>TableDetailsPageV1.component</div>);
|
||||||
|
});
|
||||||
|
jest.mock('../../utils/TourUtils', () => ({
|
||||||
|
getTourSteps: jest.fn().mockImplementation((props) => props),
|
||||||
|
}));
|
||||||
|
|
||||||
|
describe('TourPage component', () => {
|
||||||
|
it('should render correctly', async () => {
|
||||||
|
render(<TourPage />);
|
||||||
|
|
||||||
|
expect(await screen.findByText('Tour.component')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('clear search term should work correctly', async () => {
|
||||||
|
render(<TourPage />);
|
||||||
|
|
||||||
|
const clearBtn = await screen.findByTestId('clear-btn');
|
||||||
|
fireEvent.click(clearBtn);
|
||||||
|
|
||||||
|
expect(mockUseTourProvider.updateTourSearch).toHaveBeenCalledWith('');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('MyDataPage Component should be visible, if currentTourPage is myDataPage', async () => {
|
||||||
|
(useTourProvider as jest.Mock).mockImplementationOnce(() => ({
|
||||||
|
...mockUseTourProvider,
|
||||||
|
currentTourPage: CurrentTourPageType.MY_DATA_PAGE,
|
||||||
|
}));
|
||||||
|
render(<TourPage />);
|
||||||
|
|
||||||
|
expect(await screen.findByText('MyDataPage.component')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('ExplorePage Component should be visible, if currentTourPage is explorePage', async () => {
|
||||||
|
(useTourProvider as jest.Mock).mockImplementationOnce(() => ({
|
||||||
|
...mockUseTourProvider,
|
||||||
|
currentTourPage: CurrentTourPageType.EXPLORE_PAGE,
|
||||||
|
}));
|
||||||
|
render(<TourPage />);
|
||||||
|
|
||||||
|
expect(
|
||||||
|
await screen.findByText('ExplorePageV1Component.component')
|
||||||
|
).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('TableDetailsPage Component should be visible, if currentTourPage is datasetPage', async () => {
|
||||||
|
(useTourProvider as jest.Mock).mockImplementationOnce(() => ({
|
||||||
|
...mockUseTourProvider,
|
||||||
|
currentTourPage: CurrentTourPageType.DATASET_PAGE,
|
||||||
|
}));
|
||||||
|
render(<TourPage />);
|
||||||
|
|
||||||
|
expect(
|
||||||
|
await screen.findByText('TableDetailsPageV1.component')
|
||||||
|
).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
});
|
||||||
@ -0,0 +1,55 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
// Mock MentionBlot as a class
|
||||||
|
class MentionBlot {
|
||||||
|
static create(data: { value: string; link: string; id: string }) {
|
||||||
|
const element = document.createElement('a');
|
||||||
|
element.innerText = data.value;
|
||||||
|
element.href = data.link;
|
||||||
|
element.id = data.id;
|
||||||
|
|
||||||
|
return element;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mock the Quill.import function
|
||||||
|
jest.mock('react-quill', () => ({
|
||||||
|
Quill: {
|
||||||
|
import: jest.fn().mockImplementation(() => {
|
||||||
|
return MentionBlot;
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
|
import { LinkBlot } from './QuillLink';
|
||||||
|
|
||||||
|
describe('LinkBlot', () => {
|
||||||
|
it('should create a link element with correct properties', () => {
|
||||||
|
const data = {
|
||||||
|
value: 'Link Text',
|
||||||
|
link: 'https://example.com/',
|
||||||
|
id: 'linkId',
|
||||||
|
};
|
||||||
|
|
||||||
|
const linkElement = LinkBlot.render(data);
|
||||||
|
|
||||||
|
expect(linkElement.tagName).toBe('A');
|
||||||
|
expect(linkElement.innerText).toBe(data.value);
|
||||||
|
expect(linkElement.href).toBe(data.link);
|
||||||
|
expect(linkElement.id).toBe(data.id);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have correct blotName', () => {
|
||||||
|
expect(LinkBlot.blotName).toBe('link-mention');
|
||||||
|
});
|
||||||
|
});
|
||||||
@ -1,28 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2022 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
export const getUserNameAndToken = (searchParam: string) => {
|
|
||||||
const searchParams = new URLSearchParams(searchParam);
|
|
||||||
|
|
||||||
if (searchParams) {
|
|
||||||
const userName = searchParams.get('user');
|
|
||||||
const token = searchParams.get('token');
|
|
||||||
|
|
||||||
return {
|
|
||||||
userName,
|
|
||||||
token,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
Loading…
x
Reference in New Issue
Block a user