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

Commit

Permalink
Merge branch 'master' of github.com:HospitalRun/hospitalrun-frontend …
Browse files Browse the repository at this point in the history
…into incident
  • Loading branch information
jackcmeyer committed May 3, 2020
2 parents 4a4a682 + b695ac8 commit da2ea77
Show file tree
Hide file tree
Showing 40 changed files with 645 additions and 16 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
"dependencies": {
"@hospitalrun/components": "^1.4.0",
"@reduxjs/toolkit": "~1.3.0",
"@types/escape-string-regexp": "~2.0.1",
"@types/pouchdb-find": "~6.3.4",
"bootstrap": "~4.4.1",
"date-fns": "~2.12.0",
Expand Down
14 changes: 14 additions & 0 deletions src/__tests__/clients/db/LabRepository.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import shortid from 'shortid'
import LabRepository from '../../../clients/db/LabRepository'
import Lab from '../../../model/Lab'

describe('lab repository', () => {
it('should generate a lab code', async () => {
const newLab = await LabRepository.save({
patientId: '123',
type: 'test',
} as Lab)

expect(shortid.isValid(newLab.code)).toBeTruthy()
})
})
5 changes: 4 additions & 1 deletion src/__tests__/labs/ViewLab.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ describe('View Labs', () => {
let history: any
const mockPatient = { fullName: 'test' }
const mockLab = {
code: 'L-1234',
id: '12456',
status: 'requested',
patientId: '1234',
Expand Down Expand Up @@ -83,7 +84,9 @@ describe('View Labs', () => {
it('should set the title', async () => {
await setup(mockLab, [Permissions.ViewLab])

expect(titleSpy).toHaveBeenCalledWith(`${mockLab.type} for ${mockPatient.fullName}`)
expect(titleSpy).toHaveBeenCalledWith(
`${mockLab.type} for ${mockPatient.fullName}(${mockLab.code})`,
)
})

describe('page content', () => {
Expand Down
17 changes: 11 additions & 6 deletions src/__tests__/labs/ViewLabs.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ describe('View Labs', () => {
let wrapper: ReactWrapper
let history: any
const expectedLab = {
code: 'L-1234',
id: '1234',
type: 'lab type',
patientId: 'patientId',
Expand Down Expand Up @@ -133,19 +134,23 @@ describe('View Labs', () => {
expect(table).toBeDefined()
expect(tableHeader).toBeDefined()
expect(tableBody).toBeDefined()
expect(tableColumnHeaders.at(0).text().trim()).toEqual('labs.lab.type')
expect(tableColumnHeaders.at(0).text().trim()).toEqual('labs.lab.code')

expect(tableColumnHeaders.at(1).text().trim()).toEqual('labs.lab.requestedOn')
expect(tableColumnHeaders.at(1).text().trim()).toEqual('labs.lab.type')

expect(tableColumnHeaders.at(2).text().trim()).toEqual('labs.lab.status')
expect(tableColumnHeaders.at(2).text().trim()).toEqual('labs.lab.requestedOn')

expect(tableDataColumns.at(0).text().trim()).toEqual(expectedLab.type)
expect(tableColumnHeaders.at(3).text().trim()).toEqual('labs.lab.status')

expect(tableDataColumns.at(1).text().trim()).toEqual(
expect(tableDataColumns.at(0).text().trim()).toEqual(expectedLab.code)

expect(tableDataColumns.at(1).text().trim()).toEqual(expectedLab.type)

expect(tableDataColumns.at(2).text().trim()).toEqual(
format(new Date(expectedLab.requestedOn), 'yyyy-MM-dd hh:mm a'),
)

expect(tableDataColumns.at(2).text().trim()).toEqual(expectedLab.status)
expect(tableDataColumns.at(3).text().trim()).toEqual(expectedLab.status)
})

it('should navigate to the lab when the row is clicked', () => {
Expand Down
94 changes: 94 additions & 0 deletions src/__tests__/patients/labs/LabsTab.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import '../../../__mocks__/matchMediaMock'
import React from 'react'
import configureMockStore from 'redux-mock-store'
import thunk from 'redux-thunk'
import { mount } from 'enzyme'
import { createMemoryHistory } from 'history'
import { Router } from 'react-router'
import { Provider } from 'react-redux'
import * as components from '@hospitalrun/components'
import format from 'date-fns/format'
import { act } from 'react-dom/test-utils'
import LabsTab from '../../../patients/labs/LabsTab'
import Patient from '../../../model/Patient'
import Lab from '../../../model/Lab'
import Permissions from '../../../model/Permissions'
import LabRepository from '../../../clients/db/LabRepository'

const expectedPatient = {
id: '123',
} as Patient

const labs = [
{
id: 'labId',
patientId: '123',
type: 'type',
status: 'requested',
requestedOn: new Date().toISOString(),
} as Lab,
]

const mockStore = configureMockStore([thunk])
const history = createMemoryHistory()

let user: any
let store: any

const setup = (patient = expectedPatient, permissions = [Permissions.WritePatients]) => {
user = { permissions }
store = mockStore({ patient, user })
jest.spyOn(LabRepository, 'findAllByPatientId').mockResolvedValue(labs)
const wrapper = mount(
<Router history={history}>
<Provider store={store}>
<LabsTab patientId={patient.id} />
</Provider>
</Router>,
)

return wrapper
}

describe('Labs Tab', () => {
it('should list the patients labs', async () => {
const expectedLabs = labs
let wrapper: any
await act(async () => {
wrapper = await setup()
})
wrapper.update()

const table = wrapper.find('table')
const tableHeader = wrapper.find('thead')
const tableHeaders = wrapper.find('th')
const tableBody = wrapper.find('tbody')
const tableData = wrapper.find('td')

expect(table).toHaveLength(1)
expect(tableHeader).toHaveLength(1)
expect(tableBody).toHaveLength(1)
expect(tableHeaders.at(0).text()).toEqual('labs.lab.type')
expect(tableHeaders.at(1).text()).toEqual('labs.lab.requestedOn')
expect(tableHeaders.at(2).text()).toEqual('labs.lab.status')
expect(tableData.at(0).text()).toEqual(expectedLabs[0].type)
expect(tableData.at(1).text()).toEqual(
format(new Date(expectedLabs[0].requestedOn), 'yyyy-MM-dd hh:mm a'),
)
expect(tableData.at(2).text()).toEqual(expectedLabs[0].status)
})

it('should render a warning message if the patient does not have any labs', async () => {
let wrapper: any

await act(async () => {
wrapper = await setup({ ...expectedPatient })
})

const alert = wrapper.find(components.Alert)

expect(alert).toHaveLength(1)
expect(alert.prop('title')).toEqual('patient.labs.warning.noLabs')
expect(alert.prop('message')).toEqual('patient.labs.noLabsMessage')
})
})
39 changes: 39 additions & 0 deletions src/__tests__/patients/patient-slice.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,37 @@ describe('patients slice', () => {
}),
)
})

it('should validate fields that should only contian alpha characters', async () => {
const store = mockStore()
const expectedPatientId = 'sliceId10'
const expectedPatient = {
id: expectedPatientId,
givenName: 'some given name',
suffix: 'A123',
familyName: 'B456',
prefix: 'C987',
preferredLanguage: 'D321',
} as Patient
const saveOrUpdateSpy = jest
.spyOn(PatientRepository, 'saveOrUpdate')
.mockResolvedValue(expectedPatient)
const onSuccessSpy = jest.fn()

await store.dispatch(createPatient(expectedPatient, onSuccessSpy))

expect(onSuccessSpy).not.toHaveBeenCalled()
expect(saveOrUpdateSpy).not.toHaveBeenCalled()
expect(store.getActions()[1]).toEqual(
createPatientError({
message: 'patient.errors.createPatientError',
suffix: 'patient.errors.patientNumInSuffixFeedback',
familyName: 'patient.errors.patientNumInFamilyNameFeedback',
prefix: 'patient.errors.patientNumInPrefixFeedback',
preferredLanguage: 'patient.errors.patientNumInPreferredLanguageFeedback',
}),
)
})
})

describe('fetch patient', () => {
Expand Down Expand Up @@ -386,6 +417,10 @@ describe('patients slice', () => {
id: expectedPatientId,
givenName: undefined,
dateOfBirth: addDays(new Date(), 4).toISOString(),
suffix: '061002',
prefix: '061002',
familyName: '061002',
preferredLanguage: '061002',
} as Patient
const saveOrUpdateSpy = jest
.spyOn(PatientRepository, 'saveOrUpdate')
Expand All @@ -401,6 +436,10 @@ describe('patients slice', () => {
message: 'patient.errors.updatePatientError',
givenName: 'patient.errors.patientGivenNameFeedback',
dateOfBirth: 'patient.errors.patientDateOfBirthFeedback',
suffix: 'patient.errors.patientNumInSuffixFeedback',
familyName: 'patient.errors.patientNumInFamilyNameFeedback',
prefix: 'patient.errors.patientNumInPrefixFeedback',
preferredLanguage: 'patient.errors.patientNumInPreferredLanguageFeedback',
}),
)
})
Expand Down
31 changes: 29 additions & 2 deletions src/__tests__/patients/view/ViewPatient.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ import * as titleUtil from '../../../page-header/useTitle'
import ViewPatient from '../../../patients/view/ViewPatient'
import * as patientSlice from '../../../patients/patient-slice'
import Permissions from '../../../model/Permissions'
import LabsTab from '../../../patients/labs/LabsTab'
import LabRepository from '../../../clients/db/LabRepository'

const mockStore = configureMockStore([thunk])

Expand All @@ -47,9 +49,9 @@ describe('ViewPatient', () => {

const setup = (permissions = [Permissions.ReadPatients]) => {
jest.spyOn(PatientRepository, 'find')
jest.spyOn(LabRepository, 'findAllByPatientId').mockResolvedValue([])
const mockedPatientRepository = mocked(PatientRepository, true)
mockedPatientRepository.find.mockResolvedValue(patient)

history = createMemoryHistory()
store = mockStore({
patient: { patient },
Expand Down Expand Up @@ -127,13 +129,14 @@ describe('ViewPatient', () => {
const tabs = tabsHeader.find(Tab)
expect(tabsHeader).toHaveLength(1)

expect(tabs).toHaveLength(6)
expect(tabs).toHaveLength(7)
expect(tabs.at(0).prop('label')).toEqual('patient.generalInformation')
expect(tabs.at(1).prop('label')).toEqual('patient.relatedPersons.label')
expect(tabs.at(2).prop('label')).toEqual('scheduling.appointments.label')
expect(tabs.at(3).prop('label')).toEqual('patient.allergies.label')
expect(tabs.at(4).prop('label')).toEqual('patient.diagnoses.label')
expect(tabs.at(5).prop('label')).toEqual('patient.notes.label')
expect(tabs.at(6).prop('label')).toEqual('patient.labs.label')
})

it('should mark the general information tab as active and render the general information component when route is /patients/:id', async () => {
Expand Down Expand Up @@ -262,4 +265,28 @@ describe('ViewPatient', () => {
expect(notesTab).toHaveLength(1)
expect(notesTab.prop('patient')).toEqual(patient)
})

it('should mark the labs tab as active when it is clicked and render the lab component when route is /patients/:id/labs', async () => {
let wrapper: any
await act(async () => {
wrapper = await setup()
})

await act(async () => {
const tabsHeader = wrapper.find(TabsHeader)
const tabs = tabsHeader.find(Tab)
tabs.at(6).prop('onClick')()
})

wrapper.update()

const tabsHeader = wrapper.find(TabsHeader)
const tabs = tabsHeader.find(Tab)
const labsTab = wrapper.find(LabsTab)

expect(history.location.pathname).toEqual(`/patients/${patient.id}/labs`)
expect(tabs.at(6).prop('active')).toBeTruthy()
expect(labsTab).toHaveLength(1)
expect(labsTab.prop('patientId')).toEqual(patient.id)
})
})
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ import AppointmentDetailForm from 'scheduling/appointments/AppointmentDetailForm
import * as components from '@hospitalrun/components'
import * as titleUtil from '../../../../page-header/useTitle'
import * as appointmentSlice from '../../../../scheduling/appointments/appointment-slice'
import LabRepository from '../../../../clients/db/LabRepository'
import Lab from '../../../../model/Lab'

const mockStore = configureMockStore([thunk])
const mockedComponents = mocked(components, true)
Expand All @@ -32,6 +34,7 @@ describe('New Appointment', () => {
mocked(AppointmentRepository, true).save.mockResolvedValue(
expectedNewAppointment as Appointment,
)
jest.spyOn(LabRepository, 'findAllByPatientId').mockResolvedValue([] as Lab[])

history = createMemoryHistory()
store = mockStore({
Expand Down
6 changes: 6 additions & 0 deletions src/__tests__/utils/generateCode.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import generateCode from '../../util/generateCode'

it('should generate a code with prefix A-', () => {
const generatedCode = generateCode('A')
expect(generatedCode).toMatch(/^A-/)
})
19 changes: 19 additions & 0 deletions src/clients/db/LabRepository.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import Lab from 'model/Lab'
import generateCode from '../../util/generateCode'
import Repository from './Repository'
import { labs } from '../../config/pouchdb'

Expand All @@ -9,6 +10,24 @@ export class LabRepository extends Repository<Lab> {
index: { fields: ['requestedOn'] },
})
}

async save(entity: Lab): Promise<Lab> {
const labCode = generateCode('L')
entity.code = labCode
return super.save(entity)
}

async findAllByPatientId(patientId: string): Promise<Lab[]> {
return super.search({
selector: {
$and: [
{
patientId,
},
],
},
})
}
}

export default new LabRepository()
8 changes: 2 additions & 6 deletions src/clients/db/PatientRepository.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,9 @@
import escapeStringRegexp from 'escape-string-regexp'
import shortid from 'shortid'
import Patient from '../../model/Patient'
import generateCode from '../../util/generateCode'
import Repository from './Repository'
import { patients } from '../../config/pouchdb'

const formatPatientCode = (prefix: string, sequenceNumber: string) => `${prefix}${sequenceNumber}`

const getPatientCode = (): string => formatPatientCode('P-', shortid.generate())

export class PatientRepository extends Repository<Patient> {
constructor() {
super(patients)
Expand All @@ -32,7 +28,7 @@ export class PatientRepository extends Repository<Patient> {
}

async save(entity: Patient): Promise<Patient> {
const patientCode = getPatientCode()
const patientCode = generateCode('P')
entity.code = patientCode
return super.save(entity)
}
Expand Down
4 changes: 4 additions & 0 deletions src/i18n.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,12 @@ import translationJA from './locales/ja/translations'
import translationPtBR from './locales/ptBr/translations'
import translationRU from './locales/ru/translations'
import translationZR from './locales/zr/translations'
import translationIT from './locales/it/translations'

const resources = {
it: {
translation: translationIT,
},
ar: {
translation: translationAR,
},
Expand Down
Loading

0 comments on commit da2ea77

Please # to comment.