Skip to content

Commit

Permalink
(fix) Evaluate calculate expressions after general form field initial…
Browse files Browse the repository at this point in the history
…ization (#407)

* (fix) setFieldValue on date field intialization

* Adds tests

* removes dependency

* Evaluate calculate expressions after field initialization

* Cleanup

---------

Co-authored-by: samuelmale <[email protected]>
  • Loading branch information
pirupius and samuelmale authored Oct 10, 2024
1 parent 291fe8b commit 798d9ce
Show file tree
Hide file tree
Showing 3 changed files with 118 additions and 9 deletions.
107 changes: 107 additions & 0 deletions src/components/inputs/date/date.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
import React from 'react';
import { act, render, screen } from '@testing-library/react';
import { useFormProviderContext } from 'src/provider/form-provider';
import DateField from './date.component';
import { type FormField } from 'src/types';
import { OpenmrsDatePicker } from '@openmrs/esm-framework';
import dayjs from 'dayjs';

jest.mock('src/provider/form-provider', () => ({
useFormProviderContext: jest.fn(),
}));

const mockUseFormProviderContext = useFormProviderContext as jest.Mock;
const mockSetFieldValue = jest.fn();

const mockOpenmrsDatePicker = jest.mocked(OpenmrsDatePicker);

mockOpenmrsDatePicker.mockImplementation(({ id, labelText, value, onChange, isInvalid, invalidText }) => {
return (
<>
<label htmlFor={id}>{labelText}</label>
<input
id={id}
value={value ? dayjs(value as unknown as string).format('DD/MM/YYYY') : ''}
onChange={(evt) => {
onChange(dayjs(evt.target.value).toDate());
}}
/>
{isInvalid && <span>{invalidText}</span>}
</>
);
});

const dateFieldMock: FormField = {
id: 'test-date-field',
label: 'Test Date Field',
type: 'obs',
datePickerFormat: 'both',
questionOptions: {
rendering: 'date',
concept: '6089AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
},
isHidden: false,
isDisabled: false,
readonly: false,
};

const renderDateField = async (props) => {
await act(() => render(<DateField {...props} />));
};

describe('DateField Component', () => {
beforeEach(() => {
mockUseFormProviderContext.mockReturnValue({
layoutType: 'default',
sessionMode: 'edit',
workspaceLayout: 'default',
formFieldAdapters: {},
});
});

it('should render date picker and time picker when datePickerFormat is "both"', async () => {
await renderDateField({
field: dateFieldMock,
value: new Date(),
errors: [],
warnings: [],
setFieldValue: mockSetFieldValue,
});

expect(screen.getByLabelText('Test Date Field')).toBeInTheDocument();
expect(screen.getByText('Time')).toBeInTheDocument();
});

it('should display error message when there are errors', async () => {
await renderDateField({
field: dateFieldMock,
value: new Date(),
errors: [{ resultType: 'error', message: 'Error message' }],
warnings: [],
setFieldValue: mockSetFieldValue,
});

const errorMessages = screen.getAllByText(/Error message/i);
expect(errorMessages.length).toBeGreaterThan(0);
errorMessages.forEach((message) => {
expect(message).toBeInTheDocument();
});
});

it('should display warning message when there are warnings', async () => {
const warnings = [{ resultType: 'warning', message: 'Warning message' }];
await renderDateField({
field: dateFieldMock,
value: new Date(),
errors: [],
warnings: warnings,
setFieldValue: mockSetFieldValue,
});

const warningMessages = screen.getAllByText(/Warning message/i);
expect(warningMessages.length).toBeGreaterThan(0);
warningMessages.forEach((message) => {
expect(message).toBeInTheDocument();
});
});
});
18 changes: 11 additions & 7 deletions src/processors/encounter/encounter-form-processor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -256,26 +256,30 @@ export class EncounterFormProcessor extends FormProcessor {
const filteredFields = formFields.filter(
(field) => field.questionOptions.rendering !== 'group' && field.type !== 'obsGroup',
);
const fieldsWithCalculateExpressions = [];
await Promise.all(
filteredFields.map(async (field) => {
const adapter = formFieldAdapters[field.type];
initialValues[field.id] = emptyValues[field.questionOptions.rendering] ?? null;
if (field.questionOptions.calculate?.calculateExpression) {
try {
await evaluateCalculateExpression(field, initialValues, context);
} catch (error) {
console.error(error);
}
}
if (isEmpty(initialValues[field.id]) && contextInitializableTypes.includes(field.type)) {
try {
initialValues[field.id] = await adapter.getInitialValue(field, null, context);
} catch (error) {
console.error(error);
}
}
if (field.questionOptions.calculate?.calculateExpression) {
fieldsWithCalculateExpressions.push(field);
}
}),
);
fieldsWithCalculateExpressions.forEach(async (field) => {
try {
await evaluateCalculateExpression(field, initialValues, context);
} catch (error) {
console.error(error);
}
});
}
return initialValues;
}
Expand Down
2 changes: 0 additions & 2 deletions src/types/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -215,8 +215,6 @@ export type RenderType =
| 'toggle'
| 'ui-select-extended'
| 'workspace-launcher'
| 'fixed-value'
| 'file'
| 'markdown'
| 'extension-widget'
| 'select-concept-answers';
Expand Down

0 comments on commit 798d9ce

Please sign in to comment.