From 80efdcab1127b6111588b49a89f924dafebeea52 Mon Sep 17 00:00:00 2001 From: Dwayne Date: Wed, 12 Mar 2025 22:33:18 +0530 Subject: [PATCH 1/3] Add unit tests for obsGroup type questions --- .../modals/question/question.modal.test.tsx | 98 +++++++++++ src/resources/form-validator-obsgroup.test.ts | 154 ++++++++++++++++++ 2 files changed, 252 insertions(+) create mode 100644 src/components/interactive-builder/modals/question/question.modal.test.tsx create mode 100644 src/resources/form-validator-obsgroup.test.ts diff --git a/src/components/interactive-builder/modals/question/question.modal.test.tsx b/src/components/interactive-builder/modals/question/question.modal.test.tsx new file mode 100644 index 000000000..7d76d2a59 --- /dev/null +++ b/src/components/interactive-builder/modals/question/question.modal.test.tsx @@ -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, + }), +})); + +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(); + }); + + 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( + + + , + ); + + expect(screen.getByText(/Question type/i)).toBeInTheDocument(); + expect(screen.getByText(/Rendering type/i)).toBeInTheDocument(); + }); +}); diff --git a/src/resources/form-validator-obsgroup.test.ts b/src/resources/form-validator-obsgroup.test.ts new file mode 100644 index 000000000..88bb3740a --- /dev/null +++ b/src/resources/form-validator-obsgroup.test.ts @@ -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, + concept: 'test-concept-group', + }, + questions: [ + { + id: 'temperature', + label: 'Temperature', + type: 'obs', + questionOptions: { + rendering: 'number' as RenderType, + concept: 'test-concept-temp', + }, + }, + { + id: 'bloodPressure', + label: 'Blood Pressure', + type: 'obs', + questionOptions: { + rendering: 'text' as RenderType, + concept: 'test-concept-bp', + }, + }, + ], + } as ObsGroupQuestion, + ], + }, + ], + }, + ], + 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(); + }); + + 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); +}); From cd89d4449c277546892ac7932bf06de8b8e60c49 Mon Sep 17 00:00:00 2001 From: Dwayne Dehoedt Date: Fri, 14 Mar 2025 21:57:59 +0530 Subject: [PATCH 2/3] Update src/components/interactive-builder/modals/question/question.modal.test.tsx Co-authored-by: Nethmi Rodrigo --- .../modals/question/question.modal.test.tsx | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/components/interactive-builder/modals/question/question.modal.test.tsx b/src/components/interactive-builder/modals/question/question.modal.test.tsx index 7d76d2a59..65edca47f 100644 --- a/src/components/interactive-builder/modals/question/question.modal.test.tsx +++ b/src/components/interactive-builder/modals/question/question.modal.test.tsx @@ -61,9 +61,6 @@ describe('QuestionModal Component - obsGroup Tests', () => { const mockOnSchemaChange = jest.fn(); const mockResetIndices = jest.fn(); - beforeEach(() => { - jest.clearAllMocks(); - }); it('should render the question modal with obsGroup type', () => { const initialFormField: FormField = { From c0d2e7999747813ff100a27bc2c26c182b98a983 Mon Sep 17 00:00:00 2001 From: Dwayne Dehoedt Date: Fri, 14 Mar 2025 21:58:25 +0530 Subject: [PATCH 3/3] Update src/resources/form-validator-obsgroup.test.ts Co-authored-by: Nethmi Rodrigo --- src/resources/form-validator-obsgroup.test.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/resources/form-validator-obsgroup.test.ts b/src/resources/form-validator-obsgroup.test.ts index 88bb3740a..01426d39b 100644 --- a/src/resources/form-validator-obsgroup.test.ts +++ b/src/resources/form-validator-obsgroup.test.ts @@ -118,9 +118,6 @@ const createSchemaWithInvalidChildQuestion = (): Schema => { }; describe('Form Validator - obsGroup Tests', () => { - beforeEach(() => { - jest.clearAllMocks(); - }); it('should validate a valid obsGroup question with valid child questions', async () => { const schema = createTestSchema();