From f1ddbbea679e6608c8cada9e5e3c7940b2611ddd Mon Sep 17 00:00:00 2001 From: Eric Musyoka Date: Wed, 5 Jun 2024 13:11:17 +0300 Subject: [PATCH] Update tests (#1427) * Update and fix failing tests * Fix Linting error --- .../CreateEditCareTeam/tests/form.test.tsx | 3 + .../PatientDetails/ResourceSchema/Patient.tsx | 1 + .../PatientDetailsOverview/index.tsx | 2 +- .../tests/index.test.tsx | 241 +++++++------ .../tests/__snapshots__/index.test.tsx.snap | 52 ++- .../PatientsList/tests/index.test.tsx | 341 ++++++++++++------ .../ResourceDetails/tests/index.test.tsx | 2 +- 7 files changed, 416 insertions(+), 226 deletions(-) diff --git a/packages/fhir-care-team/src/components/CreateEditCareTeam/tests/form.test.tsx b/packages/fhir-care-team/src/components/CreateEditCareTeam/tests/form.test.tsx index 94067e472..4f49028d0 100644 --- a/packages/fhir-care-team/src/components/CreateEditCareTeam/tests/form.test.tsx +++ b/packages/fhir-care-team/src/components/CreateEditCareTeam/tests/form.test.tsx @@ -66,6 +66,9 @@ describe('components/forms/CreateTeamForm', () => { }); wrapper.update(); + await act(async () => { + await flushPromises(); + }); // name is required and has no default expect(wrapper.find('#name .ant-form-item').text()).toMatchInlineSnapshot( `"NameName is Required"` diff --git a/packages/fhir-client/src/components/PatientDetails/ResourceSchema/Patient.tsx b/packages/fhir-client/src/components/PatientDetails/ResourceSchema/Patient.tsx index 450ebda0e..707688188 100644 --- a/packages/fhir-client/src/components/PatientDetails/ResourceSchema/Patient.tsx +++ b/packages/fhir-client/src/components/PatientDetails/ResourceSchema/Patient.tsx @@ -74,6 +74,7 @@ export const columns = (t: TFunction, showPatientOverview: ShowPatientOverview) render: (record: PatientTableData) => ( `; @@ -123,12 +126,15 @@ exports[`renders correctly in list view: table row 2 page 1 5`] = ` - - View - + + View + + `; @@ -179,12 +185,15 @@ exports[`renders correctly in list view: table row 3 page 1 5`] = ` - - View - + + View + + `; @@ -240,12 +249,15 @@ exports[`renders correctly in list view: table row 4 page 1 5`] = ` - - View - + + View + + `; diff --git a/packages/fhir-client/src/components/PatientsList/tests/index.test.tsx b/packages/fhir-client/src/components/PatientsList/tests/index.test.tsx index 42b7e9a96..af7d57b39 100644 --- a/packages/fhir-client/src/components/PatientsList/tests/index.test.tsx +++ b/packages/fhir-client/src/components/PatientsList/tests/index.test.tsx @@ -1,124 +1,259 @@ -import React from 'react'; -import { render, screen, waitFor } from '@testing-library/react'; -import '@testing-library/jest-dom'; import { PatientsList } from '..'; -import * as reactUtils from '@opensrp/react-utils'; -import { useTranslation } from '../../../mls'; -import { useSearchParams } from '@opensrp/react-utils'; -import { IPatient } from '@smile-cdr/fhirts/dist/FHIR-R4/interfaces/IPatient'; -import { serverSideSortedColumns, parsePatient } from '../../PatientDetails/ResourceSchema/Patient'; - -// Mock the dependencies -jest.mock('@opensrp/react-utils', () => ({ - useSimpleTabularView: jest.fn(), - useSearchParams: jest.fn(), - BrokenPage: jest.fn(), - TableLayout: jest.fn(), -})); - -jest.mock('../../mls', () => ({ - useTranslation: jest.fn(), -})); - -jest.mock('../PatientDetails/ResourceSchema/Patient', () => ({ - serverSideSortedColumns: jest.fn(), - parsePatient: jest.fn(), -})); - -describe('PatientsList', () => { - const mockFhirBaseURL = 'https://fhir.server'; - - beforeEach(() => { - jest.clearAllMocks(); - - (useTranslation as jest.Mock).mockReturnValue({ - t: (key: string) => key, - }); +import React from 'react'; +import { store } from '@opensrp/store'; +import { createMemoryHistory } from 'history'; +import { Route, Router, Switch } from 'react-router'; +import { Provider } from 'react-redux'; +import { authenticateUser } from '@onaio/session-reducer'; +import { QueryClient, QueryClientProvider } from 'react-query'; +import nock from 'nock'; +import { fireEvent, waitForElementToBeRemoved, waitFor } from '@testing-library/dom'; +import { cleanup, render, screen } from '@testing-library/react'; +import { patients, sortedAscPatients, sortedDescPatients } from './fixtures'; +import userEvents from '@testing-library/user-event'; +import { LIST_PATIENTS_URL, patientResourceType } from '../../../constants'; +import { patientResourceDetails } from '../../PatientDetails/tests/fixtures'; - (useSearchParams as jest.Mock).mockReturnValue({ - addParams: jest.fn(), - }); +jest.mock('fhirclient', () => { + return jest.requireActual('fhirclient/lib/entry/browser'); +}); - (serverSideSortedColumns as jest.Mock).mockReturnValue([ - { title: 'Name', dataIndex: 'name', key: 'name' }, - ]); +jest.mock('@opensrp/react-utils', () => { + const actual = jest.requireActual('@opensrp/react-utils'); - (parsePatient as jest.Mock).mockReturnValue({ - id: 'patient-1', - name: 'John Doe', - }); - }); + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const SearchForm = (props: any) => { + const { onChangeHandler } = props; + return ( +
+ +
+ ); + }; + return { + ...actual, + SearchForm, + }; +}); - test('renders without crashing', () => { - (reactUtils.useSimpleTabularView as jest.Mock).mockReturnValue({ - searchFormProps: {}, - tablePaginationProps: {}, - queryValues: { - data: { records: [] }, - isFetching: false, - isLoading: false, - error: null, - }, - }); +nock.disableNetConnect(); - render(); +const queryClient = new QueryClient({ + defaultOptions: { + queries: { + retry: false, + cacheTime: 0, + }, + }, +}); - expect(screen.getByText('Patients')).toBeInTheDocument(); - expect(screen.getByText('Name')).toBeInTheDocument(); - }); +const props = { + fhirBaseURL: 'http://test.server.org', +}; + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +const AppWrapper = (props: any) => { + return ( + + + + + {(routeProps) => } + + + + + ); +}; - test('shows loading state', () => { - (reactUtils.useSimpleTabularView as jest.Mock).mockReturnValue({ - searchFormProps: {}, - tablePaginationProps: {}, - queryValues: { - data: { records: [] }, - isFetching: true, - isLoading: true, - error: null, +beforeAll(() => { + store.dispatch( + authenticateUser( + true, + { + email: 'bob@example.com', + name: 'Bobbie', + username: 'RobertBaratheon', }, - }); + { api_token: 'hunter2', oAuth2Data: { access_token: 'sometoken', state: 'abcde' } } + ) + ); +}); - render(); +afterEach(() => { + nock.cleanAll(); + cleanup(); +}); - expect(screen.getByRole('progressbar')).toBeInTheDocument(); - }); +afterAll(() => { + nock.enableNetConnect(); +}); - test('handles error state', () => { - const errorMessage = 'Error fetching patients'; - (reactUtils.useSimpleTabularView as jest.Mock).mockReturnValue({ - searchFormProps: {}, - tablePaginationProps: {}, - queryValues: { - data: null, - isFetching: false, - isLoading: false, - error: new Error(errorMessage), - }, - }); +test('renders correctly in list view', async () => { + const history = createMemoryHistory(); + history.push(LIST_PATIENTS_URL); - render(); + nock(props.fhirBaseURL) + .get(`/${patientResourceType}/_search`) + .query({ _total: 'accurate', _getpagesoffset: 0, _count: 20 }) + .reply(200, patients) + .persist(); - expect(screen.getByText(errorMessage)).toBeInTheDocument(); - }); + nock(props.fhirBaseURL) + .get(`/${patientResourceType}/_search`) + .query({ _total: 'accurate', _getpagesoffset: 0, _count: 20, 'name:contains': '345' }) + .reply(200, patients); - test('renders table with data', async () => { - const patientData: IPatient[] = [{ id: 'patient-1', name: 'John Doe' } as unknown as IPatient]; - (reactUtils.useSimpleTabularView as jest.Mock).mockReturnValue({ - searchFormProps: {}, - tablePaginationProps: {}, - queryValues: { - data: { records: patientData }, - isFetching: false, - isLoading: false, - error: null, - }, + render( + + + + ); + + const waitForSpinner = async () => { + return await waitFor(() => { + expect(document.querySelector('.ant-spin')).not.toBeInTheDocument(); }); + }; + + await waitForElementToBeRemoved(document.querySelector('.ant-spin')); - render(); + expect(document.querySelector('.site-page-header')).toMatchSnapshot('Header title'); - await waitFor(() => { - expect(screen.getByText('John Doe')).toBeInTheDocument(); + document.querySelectorAll('tr').forEach((tr, idx) => { + tr.querySelectorAll('td').forEach((td) => { + expect(td).toMatchSnapshot(`table row ${idx} page 1`); }); }); + + // partial side View test + nock(props.fhirBaseURL).get(`/Patient/${1}`).reply(200, patientResourceDetails); + const patientOneView = screen.getByTestId('1'); + fireEvent.click(patientOneView as Element); + await waitForElementToBeRemoved(document.querySelector('.ant-alert-content')); + expect(history.location.search).toEqual('?viewDetails=1'); + const closeBtn = screen.findByTestId('cancel'); + fireEvent.click(await closeBtn); + expect(history.location.pathname).toEqual(LIST_PATIENTS_URL); + expect(history.location.search).toEqual(''); + + // test search + // works with search as well. + const searchForm = document.querySelector('[data-testid="search-form"]'); + userEvents.paste(searchForm as HTMLElement, '345'); + + await waitForSpinner(); + await waitForElementToBeRemoved(document.querySelector('.ant-spin')); + + expect(history.location.search).toEqual('?search=345&page=1&pageSize=20'); + + // remove search. + userEvents.clear(searchForm); + expect(history.location.search).toEqual('?page=1&pageSize=20'); + + // test sort + const dobCaretUp = document.querySelector('.anticon-caret-up:first-child'); + expect(dobCaretUp).not.toHaveClass('active'); + + const dateOfbirths = Array.from(document.querySelectorAll('tr td:nth-child(2)')).map( + (td) => td.textContent + ); + expect(dateOfbirths).toEqual(['8/4/1988', '8/4/1988', '8/4/1988', '8/4/1988']); + + // mock requests due to sort + nock(props.fhirBaseURL) + .get(`/${patientResourceType}/_search`) + .query({ _total: 'accurate', _getpagesoffset: 0, _count: 20, _sort: 'birthdate' }) + .reply(200, sortedAscPatients) + .persist(); + + nock(props.fhirBaseURL) + .get(`/${patientResourceType}/_search`) + .query({ + _total: 'accurate', + _getpagesoffset: 0, + _count: 20, + _sort: 'birthdate', + _summary: 'count', + }) + .reply(200, { total: 20 }) + .persist(); + + fireEvent.click(dobCaretUp); + + await waitForSpinner(); + await waitForElementToBeRemoved(document.querySelector('.ant-spin')); + + // its now selected and is active. + expect(dobCaretUp).toHaveClass('active'); + + const sortedBirthDates = Array.from(document.querySelectorAll('tr td:nth-child(2)')).map( + (td) => td.textContent + ); + expect(sortedBirthDates).toEqual([ + '7/10/1909', + '5/28/1919', + '9/14/1921', + '1/3/1935', + '9/10/1938', + ]); + + // sort the other way + const dobCaretDown = document.querySelector('.anticon-caret-down'); + + nock(props.fhirBaseURL) + .get(`/${patientResourceType}/_search`) + .query({ _total: 'accurate', _getpagesoffset: 0, _count: 20, _sort: '-birthdate' }) + .reply(200, sortedDescPatients) + .persist(); + + nock(props.fhirBaseURL) + .get(`/${patientResourceType}/_search`) + .query({ + _total: 'accurate', + _getpagesoffset: 0, + _count: 20, + _sort: '-birthdate', + _summary: 'count', + }) + .reply(200, { total: 20 }) + .persist(); + + fireEvent.click(dobCaretDown); + + await waitForSpinner(); + await waitForElementToBeRemoved(document.querySelector('.ant-spin')); + + const ascendingBirthDates = Array.from(document.querySelectorAll('tr td:nth-child(2)')).map( + (td) => td.textContent + ); + expect(ascendingBirthDates).toEqual([ + '5/5/2022', + '5/3/2022', + '5/1/2022', + '4/29/2022', + '4/29/2022', + ]); + + expect(nock.isDone()).toBeTruthy(); +}); + +test('responds as expected to errors', async () => { + const history = createMemoryHistory(); + history.push(LIST_PATIENTS_URL); + + nock(props.fhirBaseURL) + .get(`/${patientResourceType}/_search`) + .query({ _total: 'accurate', _getpagesoffset: 0, _count: 20 }) + .replyWithError('An error happened'); + + render( + + + + ); + + await waitForElementToBeRemoved(document.querySelector('.ant-spin')); + + expect(screen.getByText(/An error happened/)).toBeInTheDocument(); }); diff --git a/packages/react-utils/src/components/GenericDetailsView/ResourceDetails/tests/index.test.tsx b/packages/react-utils/src/components/GenericDetailsView/ResourceDetails/tests/index.test.tsx index c3205ec45..92ab65a21 100644 --- a/packages/react-utils/src/components/GenericDetailsView/ResourceDetails/tests/index.test.tsx +++ b/packages/react-utils/src/components/GenericDetailsView/ResourceDetails/tests/index.test.tsx @@ -57,7 +57,7 @@ test('ResourceDetails component renders correctly', () => { // Test Status Tag expect(screen.getByText(/Active/)).toBeInTheDocument(); - expect(screen.getByText(/Active/).closest('.status')).toHaveStyle('background-color: green'); + expect(document.querySelector('.ant-tag-green')).toBeInTheDocument(); // Test Footer Button Click fireEvent.click(screen.getByText('view details'));