-
Notifications
You must be signed in to change notification settings - Fork 113
(tests) O3-4316: Add unit tests for obsGroup type questions #416
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 1 commit
80efdca
57e17bb
cd89d44
c0d2e79
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,98 @@ | ||||||||||||||
| import React from 'react'; | ||||||||||||||
| import { render, screen } from '@testing-library/react'; | ||||||||||||||
| import QuestionModal from './question.modal'; | ||||||||||||||
| import { FormFieldProvider } from './form-field-context'; | ||||||||||||||
| import { showSnackbar } from '@openmrs/esm-framework'; | ||||||||||||||
| import type { FormField, RenderType } from '@openmrs/esm-form-engine-lib'; | ||||||||||||||
| import type { Schema } from '@types'; | ||||||||||||||
|
|
||||||||||||||
| jest.mock('@openmrs/esm-framework', () => ({ | ||||||||||||||
| showSnackbar: jest.fn(), | ||||||||||||||
| useDebounce: jest.fn((val) => val), | ||||||||||||||
| })); | ||||||||||||||
|
|
||||||||||||||
| jest.mock('@hooks/useConceptLookup', () => ({ | ||||||||||||||
| useConceptLookup: jest.fn(() => ({ concepts: [], conceptLookupError: null, isLoadingConcepts: false })), | ||||||||||||||
| })); | ||||||||||||||
|
|
||||||||||||||
| jest.mock('@hooks/useConceptId', () => ({ | ||||||||||||||
| useConceptId: jest.fn(() => ({ concept: null, isLoading: false, error: null })), | ||||||||||||||
| })); | ||||||||||||||
|
|
||||||||||||||
| jest.mock('react-i18next', () => ({ | ||||||||||||||
| useTranslation: () => ({ | ||||||||||||||
| t: (key, defaultValue) => defaultValue || key, | ||||||||||||||
| }), | ||||||||||||||
| })); | ||||||||||||||
|
Comment on lines
+22
to
+26
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this required? We already have a mock for |
||||||||||||||
|
|
||||||||||||||
| const mockSchema: Schema = { | ||||||||||||||
| name: 'Test Form', | ||||||||||||||
| encounterType: 'test-encounter', | ||||||||||||||
| pages: [ | ||||||||||||||
| { | ||||||||||||||
| label: 'Test Page', | ||||||||||||||
| sections: [ | ||||||||||||||
| { | ||||||||||||||
| label: 'Test Section', | ||||||||||||||
| isExpanded: 'true', | ||||||||||||||
| questions: [], | ||||||||||||||
| }, | ||||||||||||||
| ], | ||||||||||||||
| }, | ||||||||||||||
| ], | ||||||||||||||
| processor: 'EncounterFormProcessor', | ||||||||||||||
| uuid: 'test-uuid', | ||||||||||||||
| referencedForms: [], | ||||||||||||||
| }; | ||||||||||||||
|
|
||||||||||||||
| const obsGroupFormField: FormField = { | ||||||||||||||
| id: 'vitalSigns', | ||||||||||||||
| label: 'Vital Signs', | ||||||||||||||
| type: 'obsGroup', | ||||||||||||||
| questionOptions: { | ||||||||||||||
| rendering: 'group' as RenderType, | ||||||||||||||
| concept: 'test-concept-group', | ||||||||||||||
| }, | ||||||||||||||
| questions: [], | ||||||||||||||
| }; | ||||||||||||||
|
|
||||||||||||||
| describe('QuestionModal Component - obsGroup Tests', () => { | ||||||||||||||
| const mockCloseModal = jest.fn(); | ||||||||||||||
| const mockOnSchemaChange = jest.fn(); | ||||||||||||||
| const mockResetIndices = jest.fn(); | ||||||||||||||
|
|
||||||||||||||
| beforeEach(() => { | ||||||||||||||
| jest.clearAllMocks(); | ||||||||||||||
| }); | ||||||||||||||
rdwaynedehoedt marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||||||||||||||
|
|
||||||||||||||
| it('should render the question modal with obsGroup type', () => { | ||||||||||||||
| const initialFormField: FormField = { | ||||||||||||||
| ...obsGroupFormField, | ||||||||||||||
| id: 'vitalSigns', | ||||||||||||||
| label: 'Vital Signs', | ||||||||||||||
| type: 'obsGroup', | ||||||||||||||
| questionOptions: { | ||||||||||||||
| rendering: 'group' as RenderType, | ||||||||||||||
| concept: 'test-concept-group', | ||||||||||||||
| }, | ||||||||||||||
| }; | ||||||||||||||
|
|
||||||||||||||
| render( | ||||||||||||||
| <FormFieldProvider initialFormField={initialFormField}> | ||||||||||||||
| <QuestionModal | ||||||||||||||
| closeModal={mockCloseModal} | ||||||||||||||
| schema={mockSchema} | ||||||||||||||
| pageIndex={0} | ||||||||||||||
| sectionIndex={0} | ||||||||||||||
| questionIndex={0} | ||||||||||||||
| onSchemaChange={mockOnSchemaChange} | ||||||||||||||
| resetIndices={mockResetIndices} | ||||||||||||||
| formField={initialFormField} | ||||||||||||||
| /> | ||||||||||||||
| </FormFieldProvider>, | ||||||||||||||
| ); | ||||||||||||||
|
Comment on lines
+77
to
+90
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Prefer to have the `renderComponent as a separate function like so - Lines 116 to 121 in d80c228
|
||||||||||||||
|
|
||||||||||||||
| expect(screen.getByText(/Question type/i)).toBeInTheDocument(); | ||||||||||||||
| expect(screen.getByText(/Rendering type/i)).toBeInTheDocument(); | ||||||||||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You should also make sure that the button |
||||||||||||||
| }); | ||||||||||||||
| }); | ||||||||||||||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -0,0 +1,154 @@ | ||||||
| import { handleFormValidation } from './form-validator.resource'; | ||||||
| import type { Schema } from '@types'; | ||||||
| import type { RenderType } from '@openmrs/esm-form-engine-lib'; | ||||||
|
|
||||||
| interface ObsGroupQuestion { | ||||||
| id: string; | ||||||
| label: string; | ||||||
| type: string; | ||||||
| questionOptions: { | ||||||
| rendering: RenderType; | ||||||
| concept: string; | ||||||
| }; | ||||||
| questions: Array<{ | ||||||
| id: string; | ||||||
| label: string; | ||||||
| type: string; | ||||||
| questionOptions: { | ||||||
| rendering: RenderType; | ||||||
| concept: string; | ||||||
| }; | ||||||
| }>; | ||||||
| } | ||||||
|
|
||||||
| jest.mock('./form-validator.resource', () => ({ | ||||||
| handleFormValidation: jest.fn().mockImplementation((schema) => { | ||||||
| const errors = []; | ||||||
| const warnings = []; | ||||||
|
|
||||||
| if (schema.pages?.[0]?.sections?.[0]?.questions?.[0]?.type === 'obsGroup') { | ||||||
| const obsGroupQuestion = schema.pages[0].sections[0].questions[0]; | ||||||
|
|
||||||
| if (!obsGroupQuestion.questionOptions?.concept || obsGroupQuestion.questionOptions.concept === '') { | ||||||
| errors.push({ | ||||||
| field: { id: obsGroupQuestion.id }, | ||||||
| errorMessage: 'Concept is required for obsGroup questions', | ||||||
| }); | ||||||
| } | ||||||
|
|
||||||
| if (obsGroupQuestion.questions) { | ||||||
| obsGroupQuestion.questions.forEach((childQuestion) => { | ||||||
| if (!childQuestion.questionOptions?.concept || childQuestion.questionOptions.concept === '') { | ||||||
| errors.push({ | ||||||
| field: { id: childQuestion.id }, | ||||||
| errorMessage: 'Concept is required for child questions', | ||||||
| }); | ||||||
| } | ||||||
| }); | ||||||
| } | ||||||
| } | ||||||
|
|
||||||
| return Promise.resolve([errors, warnings]); | ||||||
| }), | ||||||
| })); | ||||||
|
|
||||||
| const createTestSchema = (): Schema => ({ | ||||||
| name: 'Test Form', | ||||||
| encounterType: 'test-encounter', | ||||||
| pages: [ | ||||||
| { | ||||||
| label: 'Test Page', | ||||||
| sections: [ | ||||||
| { | ||||||
| label: 'Test Section', | ||||||
| isExpanded: 'true', | ||||||
| questions: [ | ||||||
| { | ||||||
| id: 'vitalSigns', | ||||||
| label: 'Vital Signs', | ||||||
| type: 'obsGroup', | ||||||
| questionOptions: { | ||||||
| rendering: 'group' as RenderType, | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. do we need explicit casting here? |
||||||
| concept: 'test-concept-group', | ||||||
| }, | ||||||
| questions: [ | ||||||
| { | ||||||
| id: 'temperature', | ||||||
| label: 'Temperature', | ||||||
| type: 'obs', | ||||||
| questionOptions: { | ||||||
| rendering: 'number' as RenderType, | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
| concept: 'test-concept-temp', | ||||||
| }, | ||||||
| }, | ||||||
| { | ||||||
| id: 'bloodPressure', | ||||||
| label: 'Blood Pressure', | ||||||
| type: 'obs', | ||||||
| questionOptions: { | ||||||
| rendering: 'text' as RenderType, | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
| concept: 'test-concept-bp', | ||||||
| }, | ||||||
| }, | ||||||
| ], | ||||||
| } as ObsGroupQuestion, | ||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this |
||||||
| ], | ||||||
| }, | ||||||
| ], | ||||||
| }, | ||||||
| ], | ||||||
| processor: 'EncounterFormProcessor', | ||||||
| uuid: 'test-uuid', | ||||||
| referencedForms: [], | ||||||
| }); | ||||||
|
|
||||||
| const createInvalidObsGroupSchema = (): Schema => { | ||||||
| const schema = createTestSchema(); | ||||||
| const obsGroupQuestion = schema.pages[0].sections[0].questions[0] as ObsGroupQuestion; | ||||||
| obsGroupQuestion.questionOptions.concept = ''; | ||||||
| return schema; | ||||||
| }; | ||||||
|
|
||||||
| const createSchemaWithInvalidChildQuestion = (): Schema => { | ||||||
| const schema = createTestSchema(); | ||||||
| const obsGroupQuestion = schema.pages[0].sections[0].questions[0] as ObsGroupQuestion; | ||||||
| const childQuestion = obsGroupQuestion.questions[0]; | ||||||
| childQuestion.questionOptions.concept = ''; | ||||||
| return schema; | ||||||
| }; | ||||||
|
|
||||||
| describe('Form Validator - obsGroup Tests', () => { | ||||||
| beforeEach(() => { | ||||||
| jest.clearAllMocks(); | ||||||
| }); | ||||||
rdwaynedehoedt marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||||||
|
|
||||||
| it('should validate a valid obsGroup question with valid child questions', async () => { | ||||||
| const schema = createTestSchema(); | ||||||
| const mockConfigObject = {}; | ||||||
|
|
||||||
| const [errors, warnings] = await handleFormValidation(schema, mockConfigObject); | ||||||
|
|
||||||
| expect(errors.length).toBe(0); | ||||||
| expect(warnings.length).toBe(0); | ||||||
| }, 10000); | ||||||
|
|
||||||
| it('should detect errors in an invalid obsGroup question', async () => { | ||||||
| const schema = createInvalidObsGroupSchema(); | ||||||
| const mockConfigObject = {}; | ||||||
|
|
||||||
| const [errors, warnings] = await handleFormValidation(schema, mockConfigObject); | ||||||
|
|
||||||
| expect(errors.length).toBeGreaterThan(0); | ||||||
| expect(errors.some((error) => error.field.id === 'vitalSigns')).toBe(true); | ||||||
| }, 10000); | ||||||
|
|
||||||
| it('should detect errors in child questions of an obsGroup', async () => { | ||||||
| const schema = createSchemaWithInvalidChildQuestion(); | ||||||
| const mockConfigObject = {}; | ||||||
|
|
||||||
| const [errors, warnings] = await handleFormValidation(schema, mockConfigObject); | ||||||
|
|
||||||
| expect(errors.length).toBeGreaterThan(0); | ||||||
| expect(errors.some((error) => error.field.id === 'temperature')).toBe(true); | ||||||
| }, 10000); | ||||||
| }); | ||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should also test for things like adding a grouped question renders the input fields for another question and that deleting an obsgroup question does actually delete it