Skip to content

Commit

Permalink
Write tests; fix coded obs so that it actually works
Browse files Browse the repository at this point in the history
  • Loading branch information
brandones committed Jul 13, 2022
1 parent 139e396 commit c44190e
Show file tree
Hide file tree
Showing 7 changed files with 398 additions and 70 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,13 @@ const PastAppointmentDetails: React.FC<PastAppointmentDetailsProps> = ({ pastApp
{pastAppointments.length >= 1 ? (
pastAppointments.map((appointment, index) => {
return (
<>
<React.Fragment key={`past-appointment-${index}`}>
<p className={styles.title}>{t('lastEncounter', 'Last encounter')}</p>
<p className={styles.subtitle}>
{formatDatetime(parseDate(appointment.startDateTime))} · {appointment.service.name} ·{' '}
{appointment.location.name}{' '}
</p>
</>
</React.Fragment>
);
})
) : (
Expand All @@ -52,13 +52,13 @@ const UpcomingAppointmentDetails: React.FC<UpcomingAppointmentDetailsProps> = ({
{upcomingAppointments.length >= 1 ? (
upcomingAppointments.map((appointment, index) => {
return (
<>
<React.Fragment key={`upcoming-appointment-${index}`}>
<p className={styles.title}>{t('returnDate', 'Return date')}</p>
<p className={styles.subtitle}>
{formatDatetime(parseDate(appointment.startDateTime))} · {appointment.service.name} ·{' '}
{appointment.location.name}{' '}
</p>
</>
</React.Fragment>
);
})
) : (
Expand Down
12 changes: 5 additions & 7 deletions packages/esm-patient-registration-app/src/config-schema.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Type, validator, validators } from '@openmrs/esm-framework';
import { Type, validators } from '@openmrs/esm-framework';

export interface SectionDefinition {
id: string;
Expand All @@ -9,14 +9,14 @@ export interface SectionDefinition {
export interface FieldDefinition {
id: string;
type: string;
label: string;
label: string | null;
uuid: string;
placeholder: string;
validation: {
required: boolean;
matches: string;
matches: string | null;
};
answerConceptSetUuid: string;
answerConceptSetUuid: string | null;
}

export interface RegistrationConfig {
Expand Down Expand Up @@ -104,9 +104,7 @@ export const esmPatientRegistrationSchema = {
type: {
_type: Type.String,
_description: "How this field's data will be stored—a person attribute or an obs.",
_validators: [
validator((val) => ['person attribute', 'obs'].includes(val), "Must be one of 'person attribute' or 'obs'."),
],
_validators: [validators.oneOf(['person attribute', 'obs'])],
},
uuid: {
_type: Type.UUID,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import { ConceptResponse } from '../../patient-registration-types';

export const useConcept = jest.fn(function mockUseConceptImplementation(uuid: string): {
data: ConceptResponse;
isLoading: boolean;
} {
let data;
if (uuid == 'weight-uuid') {
data = {
uuid: 'weight-uuid',
display: 'Weight (kg)',
datatype: { display: 'Numeric', uuid: 'num' },
answers: [],
setMembers: [],
};
} else if (uuid == 'chief-complaint-uuid') {
data = {
uuid: 'chief-complaint-uuid',
display: 'Chief Complaint',
datatype: { display: 'Text', uuid: 'txt' },
answers: [],
setMembers: [],
};
} else if (uuid == 'nationality-uuid') {
data = {
uuid: 'nationality-uuid',
display: 'Nationality',
datatype: { display: 'Coded', uuid: 'cdd' },
answers: [
{ display: 'USA', uuid: 'usa' },
{ display: 'Mexico', uuid: 'mex' },
],
setMembers: [],
};
}
return {
data: data ?? null,
isLoading: !data,
};
});

export const useConceptAnswers = jest.fn((uuid: string) => {
if (uuid == 'nationality-uuid') {
return {
data: [
{ display: 'USA', uuid: 'usa' },
{ display: 'Mexico', uuid: 'mex' },
],
isLoading: false,
};
} else if (uuid == 'other-countries-uuid') {
return {
data: [
{ display: 'Kenya', uuid: 'ke' },
{ display: 'Uganda', uuid: 'ug' },
],
isLoading: false,
};
}
});
Original file line number Diff line number Diff line change
Expand Up @@ -144,12 +144,24 @@ function CodedObsField({ concept, answerConceptSetUuid, label }: CodedObsFieldPr
return (
<div className={`${styles.customField} ${styles.halfWidthInDesktopView}`}>
{!isLoadingConceptAnswers ? (
<Select id={fieldName} name={fieldName} labelText={label ?? concept?.display} light>
<SelectItem key={`no-answer-select-item-${fieldName}`} value={''} text="" />
{conceptAnswers.map((answer) => (
<SelectItem key={answer.uuid} value={answer.uuid} text={answer.display} />
))}
</Select>
<Field name={fieldName}>
{({ field, form: { touched, errors }, meta }) => {
return (
<Select
id={fieldName}
name={fieldName}
labelText={label ?? concept?.display}
light
invalid={errors[fieldName] && touched[fieldName]}
{...field}>
<SelectItem key={`no-answer-select-item-${fieldName}`} value={''} text="" />
{conceptAnswers.map((answer) => (
<SelectItem key={answer.uuid} value={answer.uuid} text={answer.display} />
))}
</Select>
);
}}
</Field>
) : null}
</div>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
import React from 'react';
import { render, screen } from '@testing-library/react';
import { FieldDefinition, RegistrationConfig } from '../../../config-schema';
import { ObsField } from './obs-field.component';
import { useConfig } from '@openmrs/esm-framework';
import { useConcept, useConceptAnswers } from '../field.resource';
import userEvent from '@testing-library/user-event';

const mockUseConfig = useConfig as jest.Mock;

// The UUIDs in this test all refer to ones that are in `__mocks__/field.resource.ts`
jest.mock('../field.resource');

type FieldProps = {
children: ({ field, form: { touched, errors } }) => React.ReactNode;
};
jest.mock('formik', () => ({
...(jest.requireActual('formik') as object),
Field: jest.fn(({ children }: FieldProps) => <>{children({ field: {}, form: { touched: {}, errors: {} } })}</>),
useField: jest.fn(() => [{ value: null }, {}]),
}));

const textFieldDef: FieldDefinition = {
id: 'chief-complaint',
type: 'obs',
label: '',
placeholder: '',
uuid: 'chief-complaint-uuid',
validation: {
required: false,
matches: null,
},
answerConceptSetUuid: null,
};

const numberFieldDef: FieldDefinition = {
id: 'weight',
type: 'obs',
label: '',
placeholder: '',
uuid: 'weight-uuid',
validation: {
required: false,
matches: null,
},
answerConceptSetUuid: null,
};

const codedFieldDef: FieldDefinition = {
id: 'nationality',
type: 'obs',
label: '',
placeholder: '',
uuid: 'nationality-uuid',
validation: {
required: false,
matches: null,
},
answerConceptSetUuid: null,
};

describe('ObsField', () => {
beforeEach(() => {
mockUseConfig.mockReturnValue({ registrationObs: { encounterTypeUuid: 'reg-enc-uuid' } });
});

it("logs an error and doesn't render if no registration encounter type is provided", () => {
mockUseConfig.mockReturnValue({ registrationObs: { encounterTypeUuid: null } });
console.error = jest.fn();
render(<ObsField fieldDefinition={textFieldDef} />);
expect(console.error).toHaveBeenCalledWith(expect.stringMatching(/no registration encounter type.*configure/i));
expect(screen.queryByRole('textbox')).toBeNull();
});

it('renders a text box for text concept', () => {
render(<ObsField fieldDefinition={textFieldDef} />);
// I don't know why the labels aren't in the DOM, but they aren't
// expect(screen.getByLabelText("Chief Complaint")).toBeInTheDocument();
expect(screen.getByRole('textbox')).toBeInTheDocument();
});

it('renders a number box for number concept', () => {
render(<ObsField fieldDefinition={numberFieldDef} />);
// expect(screen.getByLabelText("Weight (kg)")).toBeInTheDocument();
expect(screen.getByRole('spinbutton')).toBeInTheDocument();
});

it('renders a select for a coded concept', () => {
render(<ObsField fieldDefinition={codedFieldDef} />);
// expect(screen.getByLabelText("Nationality")).toBeInTheDocument();
const select = screen.getByRole('combobox');
expect(select).toBeInTheDocument();
expect(select).toHaveDisplayValue('');
});

it('select uses answerConcept for answers when it is provided', () => {
render(<ObsField fieldDefinition={{ ...codedFieldDef, answerConceptSetUuid: 'other-countries-uuid' }} />);
// expect(screen.getByLabelText("Nationality")).toBeInTheDocument();
const select = screen.getByRole('combobox');
expect(select).toBeInTheDocument();
userEvent.selectOptions(select, 'Kenya');
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,6 @@ export default class FormManager {

if (savePatientResponse.ok) {
savePatientTransactionManager.patientSaved = true;
console.log('got ok savePatientResponse');
await this.saveRelationships(values.relationships, savePatientResponse, abortController);

await this.saveObservations(
Expand All @@ -147,7 +146,6 @@ export default class FormManager {
}
}

console.log('returning patient UUID');
return savePatientResponse.data.uuid;
};

Expand Down
Loading

0 comments on commit c44190e

Please sign in to comment.