Skip to content
This repository has been archived by the owner on Jan 9, 2023. It is now read-only.

Commit

Permalink
Merge pull request #1708 from HospitalRun/feature/search-patients
Browse files Browse the repository at this point in the history
feat(patients): adds friendly id and adds search for name and friendly id
  • Loading branch information
matteovivona authored Jan 11, 2020
2 parents e7d6859 + 2d8f7ab commit 4ede163
Show file tree
Hide file tree
Showing 20 changed files with 406 additions and 128 deletions.
4 changes: 4 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,19 @@
"@semantic-release/changelog": "~3.0.4",
"@semantic-release/git": "~7.0.16",
"@semantic-release/release-notes-generator": "~7.3.0",
"@types/pouchdb-find": "^6.3.4",
"bootstrap": "~4.4.1",
"date-fns": "~2.9.0",
"i18next": "^19.0.1",
"i18next-browser-languagedetector": "^4.0.1",
"i18next-xhr-backend": "^3.2.2",
"pouchdb": "~7.1.1",
"pouchdb-adapter-memory": "^7.1.1",
"pouchdb-find": "^7.1.1",
"pouchdb-quick-search": "^1.3.0",
"react": "~16.12.0",
"react-bootstrap": "^1.0.0-beta.16",
"react-bootstrap-typeahead": "^3.4.7",
"react-dom": "~16.12.0",
"react-i18next": "^11.2.2",
"react-redux": "~7.1.3",
Expand Down
1 change: 1 addition & 0 deletions src/__tests__/containers/HospitalRun.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ describe('HospitalRun', () => {
givenName: 'test',
familyName: 'test',
suffix: 'test',
friendlyId: 'P00001',
} as Patient

mockedPatientRepository.find.mockResolvedValue(patient)
Expand Down
87 changes: 87 additions & 0 deletions src/__tests__/patients/list/Patients.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import '../../../__mocks__/matchMediaMock'
import React from 'react'
import { mount } from 'enzyme'
import { TextInput, Button } from '@hospitalrun/components'
import { MemoryRouter } from 'react-router-dom'
import { Provider } from 'react-redux'
import thunk from 'redux-thunk'
import configureStore from 'redux-mock-store'
import { mocked } from 'ts-jest/utils'
import { act } from 'react-dom/test-utils'
import Patients from '../../../patients/list/Patients'
import PatientRepository from '../../../clients/db/PatientRepository'
import * as patientSlice from '../../../patients/patients-slice'

const middlewares = [thunk]
const mockStore = configureStore(middlewares)

describe('Patients', () => {
const mockedPatientRepository = mocked(PatientRepository, true)

const setup = () => {
const store = mockStore({
patients: {
patients: [],
isLoading: false,
},
})
return mount(
<Provider store={store}>
<MemoryRouter>
<Patients />
</MemoryRouter>
</Provider>,
)
}

beforeEach(() => {
jest.resetAllMocks()
jest.spyOn(PatientRepository, 'findAll')
mockedPatientRepository.findAll.mockResolvedValue([])
})

describe('layout', () => {
it('should render a search input with button', () => {
const wrapper = setup()
const searchInput = wrapper.find(TextInput)
const searchButton = wrapper.find(Button)
expect(searchInput).toHaveLength(1)
expect(searchInput.prop('placeholder')).toEqual('actions.search')
expect(searchButton.text().trim()).toEqual('actions.search')
})
})

describe('search functionality', () => {
it('should call the searchPatients() action with the correct data', () => {
const searchPatientsSpy = jest.spyOn(patientSlice, 'searchPatients')
const expectedSearchText = 'search text'
const wrapper = setup()

act(() => {
;(wrapper.find(TextInput).prop('onChange') as any)({
target: {
value: expectedSearchText,
},
preventDefault(): void {
// noop
},
} as React.ChangeEvent<HTMLInputElement>)
})

wrapper.update()

act(() => {
;(wrapper.find(Button).prop('onClick') as any)({
preventDefault(): void {
// noop
},
} as React.MouseEvent<HTMLButtonElement>)
})

wrapper.update()

expect(searchPatientsSpy).toHaveBeenCalledTimes(1)
expect(searchPatientsSpy).toHaveBeenLastCalledWith(expectedSearchText)
})
})
})
3 changes: 3 additions & 0 deletions src/__tests__/patients/new/NewPatientForm.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import SelectWithLabelFormGroup from '../../../components/input/SelectWithLableF
import DatePickerWithLabelFormGroup from '../../../components/input/DatePickerWithLabelFormGroup'
import TextFieldWithLabelFormGroup from '../../../components/input/TextFieldWithLabelFormGroup'
import Patient from '../../../model/Patient'
import { getPatientName } from '../../../util/patient-name-util'

const onSave = jest.fn()
const onCancel = jest.fn()
Expand Down Expand Up @@ -280,6 +281,7 @@ describe('New Patient Form', () => {
const expectedPhoneNumber = 'phone number'
const expectedEmail = '[email protected]'
const expectedAddress = 'address'

act(() => {
fireEvent.change(prefixInput, { target: { value: expectedPrefix } })
})
Expand Down Expand Up @@ -348,6 +350,7 @@ describe('New Patient Form', () => {
phoneNumber: expectedPhoneNumber,
email: expectedEmail,
address: expectedAddress,
fullName: getPatientName(expectedGivenName, expectedFamilyName, expectedSuffix),
} as Patient

expect(onSave).toHaveBeenCalledTimes(1)
Expand Down
12 changes: 4 additions & 8 deletions src/__tests__/patients/patient-slice.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,7 @@ describe('patients slice', () => {
it('should create the proper initial state with empty patients array', () => {
const patientStore = patient(undefined, {} as AnyAction)
expect(patientStore.isLoading).toBeFalsy()
expect(patientStore.patient).toEqual({
id: '',
rev: '',
sex: '',
dateOfBirth: '',
})
expect(patientStore.patient).toEqual({})
})

it('should handle the GET_PATIENT_START action', () => {
Expand All @@ -39,8 +34,9 @@ describe('patients slice', () => {
rev: '123',
sex: 'male',
dateOfBirth: new Date().toISOString(),
giveName: 'test',
} as Patient
givenName: 'test',
familyName: 'test',
}
const patientStore = patient(undefined, {
type: getPatientSuccess.type,
payload: {
Expand Down
98 changes: 73 additions & 25 deletions src/__tests__/patients/patients-slice.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,14 @@ import { AnyAction } from 'redux'
import { createMemoryHistory } from 'history'
import { mocked } from 'ts-jest/utils'
import * as components from '@hospitalrun/components'
import * as patientsSlice from '../../patients/patients-slice'
import patients, {
getPatientsStart,
getAllPatientsSuccess,
createPatientStart,
createPatientSuccess,
createPatient,
searchPatients,
} from '../../patients/patients-slice'
import Patient from '../../model/Patient'
import PatientRepository from '../../clients/db/PatientRepository'

Expand All @@ -14,22 +21,22 @@ describe('patients slice', () => {

describe('patients reducer', () => {
it('should create the proper initial state with empty patients array', () => {
const patientsStore = patientsSlice.default(undefined, {} as AnyAction)
const patientsStore = patients(undefined, {} as AnyAction)
expect(patientsStore.isLoading).toBeFalsy()
expect(patientsStore.patients).toHaveLength(0)
})

it('should handle the CREATE_PATIENT_START action', () => {
const patientsStore = patientsSlice.default(undefined, {
type: patientsSlice.createPatientStart.type,
const patientsStore = patients(undefined, {
type: createPatientStart.type,
})

expect(patientsStore.isLoading).toBeTruthy()
})

it('should handle the CREATE_PATIENT_SUCCESS actions', () => {
const patientsStore = patientsSlice.default(undefined, {
type: patientsSlice.createPatientSuccess().type,
const patientsStore = patients(undefined, {
type: createPatientSuccess.type,
})

expect(patientsStore.isLoading).toBeFalsy()
Expand All @@ -44,13 +51,9 @@ describe('patients slice', () => {
id: 'id',
} as Patient

await patientsSlice.createPatient(expectedPatient, createMemoryHistory())(
dispatch,
getState,
null,
)
await createPatient(expectedPatient, createMemoryHistory())(dispatch, getState, null)

expect(dispatch).toHaveBeenCalledWith({ type: patientsSlice.createPatientStart.type })
expect(dispatch).toHaveBeenCalledWith({ type: createPatientStart.type })
})

it('should call the PatientRepository save method with the correct patient', async () => {
Expand All @@ -61,11 +64,7 @@ describe('patients slice', () => {
id: 'id',
} as Patient

await patientsSlice.createPatient(expectedPatient, createMemoryHistory())(
dispatch,
getState,
null,
)
await createPatient(expectedPatient, createMemoryHistory())(dispatch, getState, null)

expect(PatientRepository.save).toHaveBeenCalledWith(expectedPatient)
})
Expand All @@ -79,13 +78,9 @@ describe('patients slice', () => {
id: 'id',
} as Patient

await patientsSlice.createPatient(expectedPatient, createMemoryHistory())(
dispatch,
getState,
null,
)
await createPatient(expectedPatient, createMemoryHistory())(dispatch, getState, null)

expect(dispatch).toHaveBeenCalledWith({ type: patientsSlice.createPatientSuccess().type })
expect(dispatch).toHaveBeenCalledWith({ type: createPatientSuccess.type })
})

it('should navigate to the /patients/:id where id is the new patient id', async () => {
Expand All @@ -98,7 +93,7 @@ describe('patients slice', () => {
const getState = jest.fn()
const expectedPatient = {} as Patient

await patientsSlice.createPatient(expectedPatient, history)(dispatch, getState, null)
await createPatient(expectedPatient, history)(dispatch, getState, null)

expect(history.entries[1].pathname).toEqual(`/patients/${expectedPatientId}`)
})
Expand All @@ -122,7 +117,7 @@ describe('patients slice', () => {
const dispatch = jest.fn()
const getState = jest.fn()

await patientsSlice.createPatient(expectedPatient, history)(dispatch, getState, null)
await createPatient(expectedPatient, history)(dispatch, getState, null)

expect(mockedComponents.Toast).toHaveBeenCalledWith(
'success',
Expand All @@ -131,4 +126,57 @@ describe('patients slice', () => {
)
})
})

describe('searchPatients', () => {
it('should dispatch the GET_PATIENTS_START action', async () => {
const dispatch = jest.fn()
const getState = jest.fn()

await searchPatients('search string')(dispatch, getState, null)

expect(dispatch).toHaveBeenCalledWith({ type: getPatientsStart.type })
})

it('should call the PatientRepository search method with the correct search criteria', async () => {
const dispatch = jest.fn()
const getState = jest.fn()
jest.spyOn(PatientRepository, 'search')

const expectedSearchString = 'search string'
await searchPatients(expectedSearchString)(dispatch, getState, null)

expect(PatientRepository.search).toHaveBeenCalledWith(expectedSearchString)
})

it('should call the PatientRepository findALl method if there is no string text', async () => {
const dispatch = jest.fn()
const getState = jest.fn()
jest.spyOn(PatientRepository, 'findAll')

await searchPatients('')(dispatch, getState, null)

expect(PatientRepository.findAll).toHaveBeenCalledTimes(1)
})

it('should dispatch the GET_ALL_PATIENTS_SUCCESS action', async () => {
const dispatch = jest.fn()
const getState = jest.fn()

const expectedPatients = [
{
id: '1234',
},
] as Patient[]

const mockedPatientRepository = mocked(PatientRepository, true)
mockedPatientRepository.search.mockResolvedValue(expectedPatients)

await searchPatients('search string')(dispatch, getState, null)

expect(dispatch).toHaveBeenLastCalledWith({
type: getAllPatientsSuccess.type,
payload: expectedPatients,
})
})
})
})
7 changes: 4 additions & 3 deletions src/__tests__/patients/view/ViewPatient.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ describe('ViewPatient', () => {
phoneNumber: 'phoneNumber',
email: '[email protected]',
address: 'address',
friendlyId: 'P00001',
dateOfBirth: new Date().toISOString(),
} as Patient

Expand Down Expand Up @@ -62,7 +63,7 @@ describe('ViewPatient', () => {
await setup()
})
expect(titleUtil.default).toHaveBeenCalledWith(
`${patient.givenName} ${patient.familyName} ${patient.suffix}`,
`${patient.givenName} ${patient.familyName} ${patient.suffix} (${patient.friendlyId})`,
)
})

Expand Down Expand Up @@ -177,12 +178,12 @@ describe('ViewPatient', () => {

wrapper.update()

const ageInput = wrapper.findWhere((w) => w.prop('name') === 'age')
const ageInput = wrapper.findWhere((w: any) => w.prop('name') === 'age')
expect(ageInput.prop('value')).toEqual('0')
expect(ageInput.prop('label')).toEqual('patient.approximateAge')
expect(ageInput.prop('isEditable')).toBeFalsy()

const dateOfBirthInput = wrapper.findWhere((w) => w.prop('name') === 'dateOfBirth')
const dateOfBirthInput = wrapper.findWhere((w: any) => w.prop('name') === 'dateOfBirth')
expect(dateOfBirthInput.prop('value')).toEqual(new Date(patient.dateOfBirth))
expect(dateOfBirthInput.prop('label')).toEqual('patient.approximateDateOfBirth')
expect(dateOfBirthInput.prop('isEditable')).toBeFalsy()
Expand Down
Loading

1 comment on commit 4ede163

@vercel
Copy link

@vercel vercel bot commented on 4ede163 Jan 11, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.