Skip to content

Commit

Permalink
Add tests for creating a new clinical view (#12)
Browse files Browse the repository at this point in the history
* Add tests for creating a new clinical view

* Remove comments and change from fireEvent to userEvent
  • Loading branch information
ODORA0 authored Oct 21, 2024
1 parent 1184b57 commit 3d76a7a
Show file tree
Hide file tree
Showing 12 changed files with 816 additions and 30 deletions.
17 changes: 9 additions & 8 deletions jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,15 @@ module.exports = {
'^.+\\.tsx?$': ['@swc/jest'],
},
transformIgnorePatterns: ['/node_modules/(?!@openmrs)'],
moduleNameMapper: {
'@openmrs/esm-framework': '@openmrs/esm-framework/mock',
'@openmrs/esm-utils': '@openmrs/esm-framework/mock',
'\\.(s?css)$': 'identity-obj-proxy',
'^lodash-es/(.*)$': 'lodash/$1',
'lodash-es': 'lodash',
'^dexie$': require.resolve('dexie'),
},
moduleNameMapper: {
'@openmrs/esm-framework': '@openmrs/esm-framework/mock',
'@openmrs/esm-utils': '@openmrs/esm-framework/mock',
'\\.(s?css)$': 'identity-obj-proxy',
'^lodash-es/(.*)$': 'lodash/$1',
'lodash-es': 'lodash',
'^dexie$': require.resolve('dexie'),
'^@testing-library/jest-dom/extend-expect$': '@testing-library/jest-dom',
},
setupFilesAfterEnv: ['<rootDir>/src/setup-tests.ts'],
testPathIgnorePatterns: [path.resolve(__dirname, 'e2e')],
testEnvironment: 'jsdom',
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@
"@swc/core": "^1.5.7",
"@swc/jest": "^0.2.36",
"@testing-library/dom": "^9.3.4",
"@testing-library/jest-dom": "^6.4.8",
"@testing-library/jest-dom": "^6.6.1",
"@testing-library/react": "^14.3.1",
"@testing-library/user-event": "^14.5.2",
"@types/jest": "^29.5.12",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
import React from 'react';
import { render, screen } from '@testing-library/react';
import '@testing-library/jest-dom/extend-expect';
import userEvent from '@testing-library/user-event';
import { useTranslation } from 'react-i18next';
import ConfigureDashboardModal from './add-columns-modal.component';
import { showSnackbar } from '@openmrs/esm-framework';
import { DefinitionTypes } from '../../types';

jest.mock('react-i18next', () => ({
useTranslation: () => ({
t: (key) => key,
}),
}));

jest.mock('@openmrs/esm-framework', () => ({
isDesktop: jest.fn(() => true),
showSnackbar: jest.fn(),
useLayoutType: jest.fn(() => 'desktop'),
}));

jest.mock('../../hooks/useForm', () => ({
useForms: jest.fn(() => ({
isLoadingForm: false,
forms: [{ display: 'Form 1' }],
formsError: null,
})),
}));

jest.mock('../../hooks/useFormConcepts', () => ({
useFormConcepts: jest.fn(() => ({
isLoadingFormConcepts: false,
formConcepts: [{ concept: 'concept1', label: 'Concept 1' }],
formConceptsError: null,
mutate: jest.fn(),
})),
}));

jest.mock('../../hooks/useEncounter', () => ({
useEncounterTypes: jest.fn(() => ({
isLoading: false,
encounterTypes: [{ uuid: 'encounter1', display: 'Encounter 1' }],
encounterTypesError: null,
})),
}));

jest.mock('../../helpers', () => ({
generateNodeId: jest.fn(() => 'generated-id'),
}));

const mockProps = {
schema: {
'@openmrs/esm-patient-chart-app': {
extensionSlots: {
'patient-chart-dashboard-slot': {
add: [],
configure: {
slot1: {
title: 'Slot 1 Title',
slotName: 'slot1',
tabDefinitions: [
{
id: 'tab1',
tabName: 'Tab 1',
headerTitle: 'Tab 1 Header',
displayText: 'Display Text for Tab 1',
encounterType: 'Encounter 1',
hasFilter: false,
columns: [],
launchOptions: { displayText: 'Launch Tab 1' },
formList: [],
},
],
},
},
},
slot1: {
add: [],
configure: {
slot1: {
title: 'Slot 1 Title',
slotName: 'slot1',
tabDefinitions: [
{
id: 'tab1',
tabName: 'Tab 1',
headerTitle: 'Tab 1 Header',
displayText: 'Display Text for Tab 1',
encounterType: 'Encounter 1',
hasFilter: false,
columns: [],
launchOptions: { displayText: 'Launch Tab 1' },
formList: [],
},
],
},
},
},
},
},
},
onSchemaChange: jest.fn(),
closeModal: jest.fn(),
slotDetails: {
slot: 'slot1',
title: 'Dashboard Slot 1',
path: '/dashboard/slot1',
},
tabDefinition: {
id: 'tab1',
tabName: 'Tab 1',
headerTitle: 'Tab 1 Header',
displayText: 'Display Text for Tab 1',
encounterType: 'Encounter 1',
columns: [],
launchOptions: { displayText: 'Launch Tab 1' },
formList: [],
},
definitionType: DefinitionTypes.TAB_DEFINITION,
};

describe('ConfigureDashboardModal', () => {
const user = userEvent.setup();

it('renders without crashing', () => {
render(<ConfigureDashboardModal {...mockProps} />);
expect(screen.getByText('createNewSubMenu')).toBeInTheDocument();
});

it('handles form input changes', async () => {
render(<ConfigureDashboardModal {...mockProps} />);

await user.type(screen.getByLabelText('columnTitle'), 'New Column');
await user.selectOptions(screen.getByLabelText('selectConcept'), 'concept1');
await user.selectOptions(screen.getByLabelText('selectEncounterType'), 'Encounter 1');

expect(screen.getByLabelText('columnTitle')).toHaveValue('New Column');
expect(screen.getByLabelText('selectConcept')).toHaveValue('concept1');
expect(screen.getByLabelText('selectEncounterType')).toHaveValue('Encounter 1');
});

it('calls updateSchema and closeModal on create column', async () => {
render(<ConfigureDashboardModal {...mockProps} />);

await user.type(screen.getByLabelText('columnTitle'), 'New Column');
await user.selectOptions(screen.getByLabelText('selectConcept'), 'concept1');
await user.selectOptions(screen.getByLabelText('selectEncounterType'), 'Encounter 1');

await user.click(screen.getByText('createSubMenu'));

expect(mockProps.onSchemaChange).toHaveBeenCalled();
expect(mockProps.closeModal).toHaveBeenCalled();
expect(showSnackbar).toHaveBeenCalledWith({
title: 'success',
kind: 'success',
isLowContrast: true,
subtitle: 'tabColumnsCreated',
});
});

it('shows error snackbar on schema update failure', async () => {
const errorProps = {
...mockProps,
onSchemaChange: () => {
throw new Error('Test Error');
},
};

render(<ConfigureDashboardModal {...errorProps} />);

await user.type(screen.getByLabelText('columnTitle'), 'New Column');
await user.selectOptions(screen.getByLabelText('selectConcept'), 'concept1');
await user.selectOptions(screen.getByLabelText('selectEncounterType'), 'Encounter 1');

await user.click(screen.getByText('createSubMenu'));

expect(showSnackbar).toHaveBeenCalledWith({
title: 'errorCreatingTabColumns',
kind: 'error',
subtitle: 'Test Error',
});
});
});
29 changes: 14 additions & 15 deletions src/components/interactive-builder/add-columns-modal.component.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -92,8 +92,6 @@ const ConfigureDashboardModal: React.FC<ConfigureDashboardModalProps> = ({
},
};
onSchemaChange(updatedSchema);

// Show success notification
setColumnTitle('');
setColumnConcept('');
setIsColumnDate(false);
Expand Down Expand Up @@ -160,10 +158,10 @@ const ConfigureDashboardModal: React.FC<ConfigureDashboardModalProps> = ({
setEncounterType(event.target.value);
}}
>
{!encounterType && <SelectItem text={t('selectEncounterType', 'Select an encounter type')} />}
{!encounterType && <SelectItem text={t('selectEncounterType', 'Select an encounter type')} value="" />}
{encounterTypes.length === 0 ||
(encounterTypesError && (
<SelectItem text={t('noEncounterTypesAvailable', 'No encounter types available')} />
<SelectItem text={t('noEncounterTypesAvailable', 'No encounter types available')} value="" />
))}
{encounterTypes?.length > 0 &&
encounterTypes.map((encounterType) => (
Expand Down Expand Up @@ -193,9 +191,11 @@ const ConfigureDashboardModal: React.FC<ConfigureDashboardModalProps> = ({
setColumnConcept(event.target.value);
}}
>
{!columnConcept && <SelectItem text={t('selectConcept', 'Select a concept')} />}
{!columnConcept && <SelectItem text={t('selectConcept', 'Select a concept')} value="" />}
{formConcepts.length === 0 ||
(formConceptsError && <SelectItem text={t('noConceptsAvailable', 'No concepts available')} />)}
(formConceptsError && (
<SelectItem text={t('noConceptsAvailable', 'No concepts available')} value="" />
))}
{formConcepts?.length > 0 &&
formConcepts.map((concept) => (
<SelectItem key={concept.concept} text={concept.label} value={concept.concept}>
Expand All @@ -216,21 +216,20 @@ const ConfigureDashboardModal: React.FC<ConfigureDashboardModalProps> = ({
name="isDate"
orientation="horizontal"
legendText={t('isDate', 'Is date')}
className={styles.label}
defaultSelected={isColumnDate}
onChange={(event) => setIsColumnDate(event.toString())}
defaultSelected={isColumnDate ? 'true' : 'false'}
onChange={(value) => setIsColumnDate(value === 'true')}
>
<RadioButton
className={styles.radioButton}
id="isDateTrue"
labelText={t('true', 'True')}
value={true}
value="true"
/>
<RadioButton
className={styles.radioButton}
id="isDateFalse"
labelText={t('false', 'False')}
value={false}
value="false"
/>
</RadioButtonGroup>

Expand All @@ -239,20 +238,20 @@ const ConfigureDashboardModal: React.FC<ConfigureDashboardModalProps> = ({
orientation="horizontal"
legendText={t('isLink', 'Is link')}
className={styles.label}
defaultSelected={isColumnLink}
onChange={(event) => setIsColumnLink(event.toString())}
defaultSelected={isColumnLink ? 'true' : 'false'}
onChange={(value) => setIsColumnLink(value === 'true')}
>
<RadioButton
className={styles.radioButton}
id="isLinkTrue"
labelText={t('true', 'True')}
value={true}
value="true"
/>
<RadioButton
className={styles.radioButton}
id="isLinkFalse"
labelText={t('false', 'False')}
value={false}
value="false"
/>
</RadioButtonGroup>
</FormGroup>
Expand Down
Loading

0 comments on commit 3d76a7a

Please sign in to comment.