From 3518b77c1f351e15a4f7fe1ade184bdd19754ddc Mon Sep 17 00:00:00 2001 From: Jack Meyer Date: Thu, 2 Apr 2020 18:49:34 -0500 Subject: [PATCH] feat(labs): adding tests for labs module --- src/__tests__/labs/Labs.test.tsx | 3 + src/__tests__/labs/ViewLab.test.tsx | 409 ++++++++++++++++++ src/__tests__/labs/ViewLabs.test.tsx | 190 ++++++++ .../labs/requests/NewLabRequest.test.tsx | 274 ++++++++++++ src/labs/ViewLab.tsx | 21 +- src/labs/ViewLabs.tsx | 12 +- src/labs/requests/NewLabRequest.tsx | 10 +- src/model/Lab.ts | 8 +- 8 files changed, 903 insertions(+), 24 deletions(-) create mode 100644 src/__tests__/labs/Labs.test.tsx create mode 100644 src/__tests__/labs/ViewLab.test.tsx create mode 100644 src/__tests__/labs/ViewLabs.test.tsx create mode 100644 src/__tests__/labs/requests/NewLabRequest.test.tsx diff --git a/src/__tests__/labs/Labs.test.tsx b/src/__tests__/labs/Labs.test.tsx new file mode 100644 index 0000000000..83960a6136 --- /dev/null +++ b/src/__tests__/labs/Labs.test.tsx @@ -0,0 +1,3 @@ +describe('Labs', () => { + it('should render the routes', () => {}) +}) diff --git a/src/__tests__/labs/ViewLab.test.tsx b/src/__tests__/labs/ViewLab.test.tsx new file mode 100644 index 0000000000..e430bb9a74 --- /dev/null +++ b/src/__tests__/labs/ViewLab.test.tsx @@ -0,0 +1,409 @@ +import '../../__mocks__/matchMediaMock' +import React from 'react' +import { Provider } from 'react-redux' +import { Router, Route } from 'react-router' +import { mount } from 'enzyme' +import thunk from 'redux-thunk' +import { createMemoryHistory } from 'history' +import Permissions from 'model/Permissions' +import { act } from '@testing-library/react' +import LabRepository from 'clients/db/LabRepository' +import PatientRepository from 'clients/db/PatientRepository' +import Lab from 'model/Lab' +import Patient from 'model/Patient' +import * as ButtonBarProvider from 'page-header/ButtonBarProvider' +import createMockStore from 'redux-mock-store' +import { Badge, Button } from '@hospitalrun/components' +import TextFieldWithLabelFormGroup from 'components/input/TextFieldWithLabelFormGroup' +import ButtonToolBar from 'page-header/ButtonToolBar' +import * as titleUtil from '../../page-header/useTitle' +import ViewLab from '../../labs/ViewLab' + +const mockStore = createMockStore([thunk]) + +describe('View Labs', () => { + let history: any + const mockPatient = { fullName: 'test' } + const mockLab = { + id: '12456', + status: 'requested', + patientId: '1234', + type: 'lab type', + notes: 'lab notes', + requestedOn: '2020-03-30T04:43:20.102Z', + } as Lab + + let setButtonToolBarSpy: any + let titleSpy: any + let labRepositorySaveSpy: any + const setup = async (lab: Lab, permissions: Permissions[]) => { + jest.resetAllMocks() + setButtonToolBarSpy = jest.fn() + titleSpy = jest.spyOn(titleUtil, 'default') + jest.spyOn(ButtonBarProvider, 'useButtonToolbarSetter').mockReturnValue(setButtonToolBarSpy) + jest.spyOn(LabRepository, 'find').mockResolvedValue(lab) + labRepositorySaveSpy = jest.spyOn(LabRepository, 'saveOrUpdate').mockResolvedValue(mockLab) + jest.spyOn(PatientRepository, 'find').mockResolvedValue(mockPatient as Patient) + + history = createMemoryHistory() + history.push(`labs/${lab.id}`) + const store = mockStore({ + title: '', + user: { + permissions, + }, + }) + + let wrapper: any + await act(async () => { + wrapper = await mount( + + + + + + + + + , + ) + }) + wrapper.update() + return wrapper + } + + it('should set the title', async () => { + await setup(mockLab, [Permissions.ViewLab]) + + expect(titleSpy).toHaveBeenCalledWith(`${mockLab.type} for ${mockPatient.fullName}`) + }) + + describe('page content', () => { + it('should display the patient full name for the for', async () => { + const expectedLab = { ...mockLab } as Lab + const wrapper = await setup(expectedLab, [Permissions.ViewLab]) + const forPatientDiv = wrapper.find('.for-patient') + expect( + forPatientDiv + .find('h4') + .text() + .trim(), + ).toEqual('labs.lab.for') + + expect( + forPatientDiv + .find('h5') + .text() + .trim(), + ).toEqual(mockPatient.fullName) + }) + + it('should display the lab type for type', async () => { + const expectedLab = { ...mockLab, type: 'expected type' } as Lab + const wrapper = await setup(expectedLab, [Permissions.ViewLab]) + const labTypeDiv = wrapper.find('.lab-type') + expect( + labTypeDiv + .find('h4') + .text() + .trim(), + ).toEqual('labs.lab.type') + + expect( + labTypeDiv + .find('h5') + .text() + .trim(), + ).toEqual(expectedLab.type) + }) + + it('should display the requested on date', async () => { + const expectedLab = { ...mockLab, requestedOn: '2020-03-30T04:43:20.102Z' } as Lab + const wrapper = await setup(expectedLab, [Permissions.ViewLab]) + const requestedOnDiv = wrapper.find('.requested-on') + expect( + requestedOnDiv + .find('h4') + .text() + .trim(), + ).toEqual('labs.lab.requestedOn') + + expect( + requestedOnDiv + .find('h5') + .text() + .trim(), + ).toEqual('2020-03-29 11:43 PM') + }) + + it('should not display the completed date if the lab is not completed', async () => { + const expectedLab = { ...mockLab } as Lab + const wrapper = await setup(expectedLab, [Permissions.ViewLab]) + const completedOnDiv = wrapper.find('.completed-on') + + expect(completedOnDiv).toHaveLength(0) + }) + + it('should not display the canceled date if the lab is not canceled', async () => { + const expectedLab = { ...mockLab } as Lab + const wrapper = await setup(expectedLab, [Permissions.ViewLab]) + const completedOnDiv = wrapper.find('.canceled-on') + + expect(completedOnDiv).toHaveLength(0) + }) + + it('should render a result text field', async () => { + const expectedLab = { + ...mockLab, + result: 'expected results', + } as Lab + const wrapper = await setup(expectedLab, [Permissions.ViewLab]) + + const notesTextField = wrapper.find(TextFieldWithLabelFormGroup).at(0) + + expect(notesTextField).toBeDefined() + expect(notesTextField.prop('label')).toEqual('labs.lab.result') + expect(notesTextField.prop('value')).toEqual(expectedLab.result) + }) + + it('should display the notes in the notes text field', async () => { + const expectedLab = { ...mockLab, notes: 'expected notes' } as Lab + const wrapper = await setup(expectedLab, [Permissions.ViewLab]) + + const notesTextField = wrapper.find(TextFieldWithLabelFormGroup).at(1) + + expect(notesTextField).toBeDefined() + expect(notesTextField.prop('label')).toEqual('labs.lab.notes') + expect(notesTextField.prop('value')).toEqual(expectedLab.notes) + }) + + it('should display an update button if the lab is in a requested state', async () => {}) + + describe('requested lab request', () => { + it('should display a warning badge if the status is requested', async () => { + const expectedLab = { ...mockLab, status: 'requested' } as Lab + const wrapper = await setup(expectedLab, [Permissions.ViewLab]) + const labStatusDiv = wrapper.find('.lab-status') + const badge = labStatusDiv.find(Badge) + expect( + labStatusDiv + .find('h4') + .text() + .trim(), + ).toEqual('labs.lab.status') + + expect(badge.prop('color')).toEqual('warning') + expect(badge.text().trim()).toEqual(expectedLab.status) + }) + + it('should display a complete lab and cancel lab button if the lab is in a requested state', async () => { + const expectedLab = { ...mockLab, notes: 'expected notes' } as Lab + + setup(expectedLab, [Permissions.ViewLab, Permissions.CompleteLab, Permissions.CancelLab]) + + const actualButtons: React.ReactNode[] = setButtonToolBarSpy.mock.calls[0][0] + expect((actualButtons[0] as any).props.children).toEqual('labs.requests.complete') + expect((actualButtons[1] as any).props.children).toEqual('labs.requests.cancel') + }) + }) + + describe('canceled lab request', () => { + it('should display a danger badge if the status is canceled', async () => { + const expectedLab = { ...mockLab, status: 'canceled' } as Lab + const wrapper = await setup(expectedLab, [Permissions.ViewLab]) + + const labStatusDiv = wrapper.find('.lab-status') + const badge = labStatusDiv.find(Badge) + expect( + labStatusDiv + .find('h4') + .text() + .trim(), + ).toEqual('labs.lab.status') + + expect(badge.prop('color')).toEqual('danger') + expect(badge.text().trim()).toEqual(expectedLab.status) + }) + + it('should display the canceled on date if the lab request has been canceled', async () => { + const expectedLab = { + ...mockLab, + status: 'canceled', + canceledOn: '2020-03-30T04:45:20.102Z', + } as Lab + const wrapper = await setup(expectedLab, [Permissions.ViewLab]) + const canceledOnDiv = wrapper.find('.canceled-on') + + expect( + canceledOnDiv + .find('h4') + .text() + .trim(), + ).toEqual('labs.lab.canceledOn') + + expect( + canceledOnDiv + .find('h5') + .text() + .trim(), + ).toEqual('2020-03-29 11:45 PM') + }) + + it('should not display complete and cancel button if the lab is canceled', async () => { + const expectedLab = { ...mockLab, status: 'canceled' } as Lab + + await setup(expectedLab, [ + Permissions.ViewLab, + Permissions.CompleteLab, + Permissions.CancelLab, + ]) + + const { calls } = setButtonToolBarSpy.mock + const actualButtons: React.ReactNode[] = calls[calls.length - 1][0] + expect(actualButtons as any).toEqual([]) + }) + + it('should not display an update button if the lab is canceled', async () => { + const expectedLab = { ...mockLab, status: 'canceled' } as Lab + const wrapper = await setup(expectedLab, [Permissions.ViewLab]) + + const updateButton = wrapper.find(Button) + expect(updateButton).toHaveLength(0) + }) + }) + + describe('completed lab request', () => { + it('should display a primary badge if the status is completed', async () => { + jest.resetAllMocks() + const expectedLab = { ...mockLab, status: 'completed' } as Lab + const wrapper = await setup(expectedLab, [Permissions.ViewLab]) + const labStatusDiv = wrapper.find('.lab-status') + const badge = labStatusDiv.find(Badge) + expect( + labStatusDiv + .find('h4') + .text() + .trim(), + ).toEqual('labs.lab.status') + + expect(badge.prop('color')).toEqual('primary') + expect(badge.text().trim()).toEqual(expectedLab.status) + }) + + it('should display the completed on date if the lab request has been completed', async () => { + const expectedLab = { + ...mockLab, + status: 'completed', + completedOn: '2020-03-30T04:44:20.102Z', + } as Lab + const wrapper = await setup(expectedLab, [Permissions.ViewLab]) + const completedOnDiv = wrapper.find('.completed-on') + + expect( + completedOnDiv + .find('h4') + .text() + .trim(), + ).toEqual('labs.lab.completedOn') + + expect( + completedOnDiv + .find('h5') + .text() + .trim(), + ).toEqual('2020-03-29 11:44 PM') + }) + + it('should not display complete and cancel button if the lab is completed', async () => { + const expectedLab = { ...mockLab, status: 'completed' } as Lab + + await setup(expectedLab, [ + Permissions.ViewLab, + Permissions.CompleteLab, + Permissions.CancelLab, + ]) + + const { calls } = setButtonToolBarSpy.mock + const actualButtons: React.ReactNode[] = calls[calls.length - 1][0] + expect(actualButtons as any).toEqual([]) + }) + + it('should not display an update button if the lab is completed', async () => { + const expectedLab = { ...mockLab, status: 'canceled' } as Lab + const wrapper = await setup(expectedLab, [Permissions.ViewLab]) + + const updateButton = wrapper.find(Button) + expect(updateButton).toHaveLength(0) + }) + }) + }) + + describe('on update', () => { + it('should update the lab with the new information', async () => { + const wrapper = await setup(mockLab, [Permissions.ViewLab]) + const expectedResult = 'expected result' + const expectedNotes = 'expected notes' + + const resultTextField = wrapper.find(TextFieldWithLabelFormGroup).at(0) + act(() => { + const onChange = resultTextField.prop('onChange') + onChange({ currentTarget: { value: expectedResult } }) + }) + wrapper.update() + + const notesTextField = wrapper.find(TextFieldWithLabelFormGroup).at(1) + act(() => { + const onChange = notesTextField.prop('onChange') + onChange({ currentTarget: { value: expectedNotes } }) + }) + wrapper.update() + const updateButton = wrapper.find(Button) + await act(async () => { + const onClick = updateButton.prop('onClick') + onClick() + }) + + expect(labRepositorySaveSpy).toHaveBeenCalledTimes(1) + expect(labRepositorySaveSpy).toHaveBeenCalledWith( + expect.objectContaining({ ...mockLab, result: expectedResult, notes: expectedNotes }), + ) + expect(history.location.pathname).toEqual('/labs') + }) + }) + + describe('on complete', () => { + it('should mark the status as completed and fill in the completed date with the current time', async () => { + const wrapper = await setup(mockLab, [ + Permissions.ViewLab, + Permissions.CompleteLab, + Permissions.CancelLab, + ]) + const expectedResult = 'expected result' + + const resultTextField = wrapper.find(TextFieldWithLabelFormGroup).at(0) + await act(async () => { + const onChange = resultTextField.prop('onChange') + await onChange({ currentTarget: { value: expectedResult } }) + }) + + const completeButton = setButtonToolBarSpy.mock.calls[0][0][0] + await act(async () => { + const { onClick } = completeButton.props + await onClick() + }) + wrapper.update() + + expect(labRepositorySaveSpy).toHaveBeenCalledTimes(1) + expect(labRepositorySaveSpy).toHaveBeenCalledWith( + expect.objectContaining({ ...mockLab, result: expectedResult }), + ) + expect(history.location.pathname).toEqual('/labs') + }) + + it('should validate that the result has been filled in', () => {}) + }) + + describe('on cancel', () => { + it('should mark the status as completed and fill in the cancelled on date with the current time', () => {}) + }) +}) diff --git a/src/__tests__/labs/ViewLabs.test.tsx b/src/__tests__/labs/ViewLabs.test.tsx new file mode 100644 index 0000000000..b48a542ddb --- /dev/null +++ b/src/__tests__/labs/ViewLabs.test.tsx @@ -0,0 +1,190 @@ +import '../../__mocks__/matchMediaMock' +import React from 'react' +import { Provider } from 'react-redux' +import { Router } from 'react-router' +import ViewLabs from 'labs/ViewLabs' +import { mount, ReactWrapper } from 'enzyme' +import configureMockStore from 'redux-mock-store' +import thunk from 'redux-thunk' +import { createMemoryHistory } from 'history' +import Permissions from 'model/Permissions' +import { act } from '@testing-library/react' +import LabRepository from 'clients/db/LabRepository' +import Lab from 'model/Lab' +import * as ButtonBarProvider from 'page-header/ButtonBarProvider' +import * as titleUtil from '../../page-header/useTitle' + +const mockStore = configureMockStore([thunk]) + +describe('View Labs', () => { + describe('title', () => { + let titleSpy: any + beforeEach(async () => { + const store = mockStore({ + title: '', + user: { permissions: [Permissions.ViewLabs, Permissions.RequestLab] }, + }) + titleSpy = jest.spyOn(titleUtil, 'default') + jest.spyOn(LabRepository, 'findAll').mockResolvedValue([]) + await act(async () => { + await mount( + + + + + , + ) + }) + }) + + it('should have New Lab Request as the title', () => { + expect(titleSpy).toHaveBeenCalledWith('labs.label') + }) + }) + + describe('button bar', () => { + it('should display button to add new lab request', async () => { + const store = mockStore({ + title: '', + user: { permissions: [Permissions.ViewLabs, Permissions.RequestLab] }, + }) + const setButtonToolBarSpy = jest.fn() + jest.spyOn(ButtonBarProvider, 'useButtonToolbarSetter').mockReturnValue(setButtonToolBarSpy) + jest.spyOn(LabRepository, 'findAll').mockResolvedValue([]) + await act(async () => { + await mount( + + + + + , + ) + }) + + const actualButtons: React.ReactNode[] = setButtonToolBarSpy.mock.calls[0][0] + expect((actualButtons[0] as any).props.children).toEqual('labs.requests.new') + }) + + it('should not display button to add new lab request if the user does not have permissions', async () => { + const store = mockStore({ + title: '', + user: { permissions: [Permissions.ViewLabs] }, + }) + const setButtonToolBarSpy = jest.fn() + jest.spyOn(ButtonBarProvider, 'useButtonToolbarSetter').mockReturnValue(setButtonToolBarSpy) + jest.spyOn(LabRepository, 'findAll').mockResolvedValue([]) + await act(async () => { + await mount( + + + + + , + ) + }) + + const actualButtons: React.ReactNode[] = setButtonToolBarSpy.mock.calls[0][0] + expect(actualButtons).toEqual([]) + }) + }) + + describe('table', () => { + let wrapper: ReactWrapper + let history: any + const expectedLab = { + id: '1234', + type: 'lab type', + patientId: 'patientId', + status: 'requested', + requestedOn: '2020-03-30T04:43:20.102Z', + } as Lab + + beforeEach(async () => { + const store = mockStore({ + title: '', + user: { permissions: [Permissions.ViewLabs, Permissions.RequestLab] }, + }) + history = createMemoryHistory() + + jest.spyOn(LabRepository, 'findAll').mockResolvedValue([expectedLab]) + await act(async () => { + wrapper = await mount( + + + + + , + ) + }) + + wrapper.update() + }) + + it('should render a table with data', () => { + const table = wrapper.find('table') + const tableHeader = table.find('thead') + const tableBody = table.find('tbody') + + const tableColumnHeaders = tableHeader.find('th') + const tableDataColumns = tableBody.find('td') + + expect(table).toBeDefined() + expect(tableHeader).toBeDefined() + expect(tableBody).toBeDefined() + expect( + tableColumnHeaders + .at(0) + .text() + .trim(), + ).toEqual('labs.lab.type') + + expect( + tableColumnHeaders + .at(1) + .text() + .trim(), + ).toEqual('labs.lab.requestedOn') + + expect( + tableColumnHeaders + .at(2) + .text() + .trim(), + ).toEqual('labs.lab.status') + + expect( + tableDataColumns + .at(0) + .text() + .trim(), + ).toEqual(expectedLab.type) + + expect( + tableDataColumns + .at(1) + .text() + .trim(), + ).toEqual('2020-03-29 11:43 PM') + + expect( + tableDataColumns + .at(2) + .text() + .trim(), + ).toEqual(expectedLab.status) + }) + + it('should navigate to the lab when the row is clicked', () => { + const table = wrapper.find('table') + const tableBody = table.find('tbody') + const tableRow = tableBody.find('tr').at(0) + + act(() => { + const onClick = tableRow.prop('onClick') as any + onClick() + }) + + expect(history.location.pathname).toEqual(`/labs/${expectedLab.id}`) + }) + }) +}) diff --git a/src/__tests__/labs/requests/NewLabRequest.test.tsx b/src/__tests__/labs/requests/NewLabRequest.test.tsx new file mode 100644 index 0000000000..3d8eaae423 --- /dev/null +++ b/src/__tests__/labs/requests/NewLabRequest.test.tsx @@ -0,0 +1,274 @@ +import '../../../__mocks__/matchMediaMock' +import React from 'react' +import NewLabRequest from 'labs/requests/NewLabRequest' +import TextFieldWithLabelFormGroup from 'components/input/TextFieldWithLabelFormGroup' +import TextInputWithLabelFormGroup from 'components/input/TextInputWithLabelFormGroup' +import { mount, ReactWrapper } from 'enzyme' +import { Button, Typeahead, Label, Alert } from '@hospitalrun/components' +import { Router } from 'react-router-dom' +import { Provider } from 'react-redux' +import configureMockStore from 'redux-mock-store' +import thunk from 'redux-thunk' +import { createMemoryHistory } from 'history' +import { act } from 'react-dom/test-utils' +import LabRepository from 'clients/db/LabRepository' +import PatientRepository from 'clients/db/PatientRepository' +import Lab from 'model/Lab' +import Patient from 'model/Patient' +import * as titleUtil from '../../../page-header/useTitle' + +const mockStore = configureMockStore([thunk]) + +describe('New Lab Request', () => { + describe('title and breadcrumbs', () => { + let wrapper: ReactWrapper + let titleSpy: any + const history = createMemoryHistory() + + beforeEach(() => { + const store = mockStore({ title: '' }) + titleSpy = jest.spyOn(titleUtil, 'default') + history.push('/labs/new') + + wrapper = mount( + + + + + , + ) + }) + + it('should have New Lab Request as the title', () => { + expect(titleSpy).toHaveBeenCalledWith('labs.requests.new') + }) + + it('should render the breadcrumbs', () => {}) + }) + + describe('form layout', () => { + let wrapper: ReactWrapper + const history = createMemoryHistory() + + beforeEach(() => { + const store = mockStore({ title: '' }) + history.push('/labs/new') + + wrapper = mount( + + + + + , + ) + }) + + it('should render a patient typeahead', () => { + const typeaheadDiv = wrapper.find('.patient-typeahead') + + expect(typeaheadDiv).toBeDefined() + + const label = typeaheadDiv.find(Label) + const typeahead = typeaheadDiv.find(Typeahead) + + expect(label).toBeDefined() + expect(label.prop('text')).toEqual('labs.lab.patient') + expect(typeahead).toBeDefined() + expect(typeahead.prop('placeholder')).toEqual('labs.lab.patient') + expect(typeahead.prop('searchAccessor')).toEqual('fullName') + }) + + it('should render a type input box', () => { + const typeInputBox = wrapper.find(TextInputWithLabelFormGroup) + + expect(typeInputBox).toBeDefined() + expect(typeInputBox.prop('label')).toEqual('labs.lab.type') + expect(typeInputBox.prop('isRequired')).toBeTruthy() + expect(typeInputBox.prop('isEditable')).toBeTruthy() + }) + + it('should render a notes text field', () => { + const notesTextField = wrapper.find(TextFieldWithLabelFormGroup) + + expect(notesTextField).toBeDefined() + expect(notesTextField.prop('label')).toEqual('labs.lab.notes') + expect(notesTextField.prop('isRequired')).toBeFalsy() + expect(notesTextField.prop('isEditable')).toBeTruthy() + }) + + it('should render a save button', () => { + const saveButton = wrapper.find(Button).at(0) + expect(saveButton).toBeDefined() + expect(saveButton.text().trim()).toEqual('actions.save') + }) + + it('should render a cancel button', () => { + const cancelButton = wrapper.find(Button).at(1) + expect(cancelButton).toBeDefined() + expect(cancelButton.text().trim()).toEqual('actions.cancel') + }) + }) + + describe('on cancel', () => { + let wrapper: ReactWrapper + const history = createMemoryHistory() + + beforeEach(() => { + history.push('/labs/new') + const store = mockStore({ title: '' }) + wrapper = mount( + + + + + , + ) + }) + + it('should navigate back to /labs', () => { + const cancelButton = wrapper.find(Button).at(1) + + act(() => { + const onClick = cancelButton.prop('onClick') as any + onClick({} as React.MouseEvent) + }) + + expect(history.location.pathname).toEqual('/labs') + }) + }) + + describe('on save', () => { + let wrapper: ReactWrapper + const history = createMemoryHistory() + let labRepositorySaveSpy: any + const expectedDate = new Date() + const expectedLab = { + patientId: '12345', + type: 'expected type', + status: 'requested', + notes: 'expected notes', + id: '1234', + requestedOn: expectedDate.toISOString(), + } as Lab + + beforeEach(() => { + jest.resetAllMocks() + Date.now = jest.fn(() => expectedDate.valueOf()) + labRepositorySaveSpy = jest.spyOn(LabRepository, 'save').mockResolvedValue(expectedLab as Lab) + + jest + .spyOn(PatientRepository, 'search') + .mockResolvedValue([{ id: expectedLab.patientId, fullName: 'some full name' }] as Patient[]) + + history.push('/labs/new') + const store = mockStore({ title: '' }) + wrapper = mount( + + + + + , + ) + }) + + it('should save the lab request and navigate to "/labs/:id"', async () => { + const patientTypeahead = wrapper.find(Typeahead) + await act(async () => { + const onChange = patientTypeahead.prop('onChange') + await onChange([{ id: expectedLab.patientId }] as Patient[]) + }) + + const typeInput = wrapper.find(TextInputWithLabelFormGroup) + act(() => { + const onChange = typeInput.prop('onChange') as any + onChange({ currentTarget: { value: expectedLab.type } }) + }) + + const notesTextField = wrapper.find(TextFieldWithLabelFormGroup) + act(() => { + const onChange = notesTextField.prop('onChange') as any + onChange({ currentTarget: { value: expectedLab.notes } }) + }) + wrapper.update() + + const saveButton = wrapper.find(Button).at(0) + await act(async () => { + const onClick = saveButton.prop('onClick') as any + await onClick() + }) + + expect(labRepositorySaveSpy).toHaveBeenCalledTimes(1) + expect(labRepositorySaveSpy).toHaveBeenCalledWith( + expect.objectContaining({ + patientId: expectedLab.patientId, + type: expectedLab.type, + notes: expectedLab.notes, + status: 'requested', + requestedOn: expectedDate.toISOString(), + }), + ) + expect(history.location.pathname).toEqual(`/labs/${expectedLab.id}`) + }) + + it('should require a patient', async () => { + const typeInput = wrapper.find(TextInputWithLabelFormGroup) + act(() => { + const onChange = typeInput.prop('onChange') as any + onChange({ currentTarget: { value: expectedLab.type } }) + }) + + const notesTextField = wrapper.find(TextFieldWithLabelFormGroup) + act(() => { + const onChange = notesTextField.prop('onChange') as any + onChange({ currentTarget: { value: expectedLab.notes } }) + }) + wrapper.update() + + const saveButton = wrapper.find(Button).at(0) + await act(async () => { + const onClick = saveButton.prop('onClick') as any + await onClick() + }) + wrapper.update() + + const alert = wrapper.find(Alert) + const typeahead = wrapper.find(Typeahead) + expect(alert).toBeDefined() + expect(alert.prop('title')).toEqual('states.error') + expect(alert.prop('message')).toEqual('labs.requests.error.unableToRequest') + expect(typeahead.prop('isInvalid')).toBeTruthy() + expect(labRepositorySaveSpy).not.toHaveBeenCalled() + }) + + it('should require a type', async () => { + const patientTypeahead = wrapper.find(Typeahead) + await act(async () => { + const onChange = patientTypeahead.prop('onChange') + await onChange([{ id: expectedLab.patientId }] as Patient[]) + }) + + const notesTextField = wrapper.find(TextFieldWithLabelFormGroup) + act(() => { + const onChange = notesTextField.prop('onChange') as any + onChange({ currentTarget: { value: expectedLab.notes } }) + }) + wrapper.update() + + const saveButton = wrapper.find(Button).at(0) + await act(async () => { + const onClick = saveButton.prop('onClick') as any + await onClick() + }) + wrapper.update() + + const alert = wrapper.find(Alert) + const typeInput = wrapper.find(TextInputWithLabelFormGroup) + expect(alert).toBeDefined() + expect(alert.prop('title')).toEqual('states.error') + expect(alert.prop('message')).toEqual('labs.requests.error.unableToRequest') + expect(typeInput.prop('isInvalid')).toBeTruthy() + expect(typeInput.prop('feedback')).toEqual('labs.requests.error.typeRequired') + expect(labRepositorySaveSpy).not.toHaveBeenCalled() + }) + }) +}) diff --git a/src/labs/ViewLab.tsx b/src/labs/ViewLab.tsx index c135e9dbae..f1895b53f5 100644 --- a/src/labs/ViewLab.tsx +++ b/src/labs/ViewLab.tsx @@ -148,22 +148,22 @@ const ViewLab = () => { } const getCanceledOnOrCompletedOnDate = () => { - if (lab.status === 'completed') { + if (lab.status === 'completed' && lab.completedOn) { return ( -
+

{t('labs.lab.completedOn')}

{format(new Date(lab.completedOn), 'yyyy-MM-dd hh:mm a')}
) } - if (lab.status === 'canceled') { + if (lab.status === 'canceled' && lab.canceledOn) { return ( -
+

{t('labs.lab.canceledOn')}

-
{format(new Date(lab.completedOn), 'yyyy-MM-dd hh:mm a')}
+
{format(new Date(lab.canceledOn), 'yyyy-MM-dd hh:mm a')}
) @@ -178,7 +178,7 @@ const ViewLab = () => { )} -
+

{t('labs.lab.status')}

{lab.status}
@@ -186,21 +186,21 @@ const ViewLab = () => {
-
+

{t('labs.lab.for')}

{patient.fullName}
-
+

{t('labs.lab.type')}

{lab.type}
-
+

{t('labs.lab.requestedOn')}

-
{format(new Date(lab.requestedOn), 'yyyy/mm/dd hh:mm a')}
+
{format(new Date(lab.requestedOn), 'yyyy-MM-dd hh:mm a')}
{getCanceledOnOrCompletedOnDate()} @@ -210,6 +210,7 @@ const ViewLab = () => { { if (permissions.includes(Permissions.RequestLab)) { buttons.push( - , ) @@ -34,7 +34,7 @@ const ViewLabs = () => { return buttons } - setButtons([getButtons()]) + setButtons(getButtons()) useEffect(() => { const fetch = async () => { @@ -54,14 +54,14 @@ const ViewLabs = () => { - - - + + + {labs.map((lab) => ( - onTableRowClick(lab)}> + onTableRowClick(lab)} key={lab.id}> diff --git a/src/labs/requests/NewLabRequest.tsx b/src/labs/requests/NewLabRequest.tsx index 27e96f2db4..affd974c73 100644 --- a/src/labs/requests/NewLabRequest.tsx +++ b/src/labs/requests/NewLabRequest.tsx @@ -63,6 +63,7 @@ const NewLabRequest = () => { if (!newLab.patientId) { setIsPatientInvalid(true) + return } if (!newLab.type) { @@ -71,7 +72,7 @@ const NewLabRequest = () => { return } - newLab.requestedOn = new Date().toISOString() + newLab.requestedOn = new Date(Date.now().valueOf()).toISOString() const createdLab = await LabRepository.save(newLab) history.push(`/labs/${createdLab.id}`) } @@ -89,15 +90,16 @@ const NewLabRequest = () => { /> )} -
-
Lab TypeRequested OnStatus{t('labs.lab.type')}{t('labs.lab.requestedOn')}{t('labs.lab.status')}
{lab.type} {format(new Date(lab.requestedOn), 'yyyy-MM-dd hh:mm a')} {lab.status}