Skip to content

Commit

Permalink
Add some test coverage for the interactive builder
Browse files Browse the repository at this point in the history
  • Loading branch information
denniskigen committed Sep 18, 2024
1 parent 3b99ba9 commit 467d00b
Show file tree
Hide file tree
Showing 3 changed files with 122 additions and 4 deletions.
1 change: 1 addition & 0 deletions jest.config.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/** @type {import('jest').Config} */
module.exports = {
clearMocks: true,
transform: {
'^.+\\.tsx?$': ['@swc/jest'],
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -380,7 +380,7 @@ const InteractiveBuilder: React.FC<InteractiveBuilderProps> = ({
>
{schema?.pages?.length
? schema.pages.map((page, pageIndex) => (
<div className={styles.editableFieldsContainer}>
<div className={styles.editableFieldsContainer} key={pageIndex}>
<div style={{ display: 'flex', alignItems: 'center' }}>
<div className={styles.editorContainer}>
<EditableValue
Expand Down Expand Up @@ -411,7 +411,7 @@ const InteractiveBuilder: React.FC<InteractiveBuilderProps> = ({
) : null}
{page?.sections?.length ? (
page.sections?.map((section, sectionIndex) => (
<Accordion>
<Accordion key={sectionIndex}>
<AccordionItem title={section.label}>
<>
<div style={{ display: 'flex', alignItems: 'center' }}>
Expand All @@ -437,7 +437,10 @@ const InteractiveBuilder: React.FC<InteractiveBuilderProps> = ({
{section.questions?.length ? (
section.questions.map((question, questionIndex) => {
return (
<Droppable id={`droppable-question-${pageIndex}-${sectionIndex}-${questionIndex}`}>
<Droppable
id={`droppable-question-${pageIndex}-${sectionIndex}-${questionIndex}`}
key={questionIndex}
>
<DraggableQuestion
handleDuplicateQuestion={duplicateQuestion}
key={question.id}
Expand All @@ -457,9 +460,10 @@ const InteractiveBuilder: React.FC<InteractiveBuilderProps> = ({
{getAnswerErrors(question.questionOptions.answers)?.length ? (
<div className={styles.answerErrors}>
<div>Answer Errors</div>
{getAnswerErrors(question.questionOptions.answers)?.map((error) => (
{getAnswerErrors(question.questionOptions.answers)?.map((error, index) => (
<div
className={styles.validationErrorMessage}
key={index}
>{`${error.field.label}: ${error.errorMessage}`}</div>
))}
</div>
Expand Down
113 changes: 113 additions & 0 deletions src/components/interactive-builder/interactive-builder.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
import React from 'react';
import userEvent from '@testing-library/user-event';
import { render, screen } from '@testing-library/react';
import { showModal } from '@openmrs/esm-framework';
import { type FormSchema } from '@openmrs/esm-form-engine-lib';
import { type Schema } from '../../types';
import InteractiveBuilder from './interactive-builder.component';

const mockShowModal = jest.mocked(showModal);

describe('InteractiveBuilder', () => {
it('renders the interactive builder', async () => {
const user = userEvent.setup();
renderInteractiveBuilder();

const startBuildingButton = screen.getByRole('button', { name: /start building/i });
expect(startBuildingButton).toBeInTheDocument();
await user.click(startBuildingButton);

expect(mockShowModal).toHaveBeenCalledTimes(1);
expect(mockShowModal).toHaveBeenCalledWith('new-form-modal', {
closeModal: expect.any(Function),
schema: {},
onSchemaChange: expect.any(Function),
});
});

it('populates the interactive builder with the provided schema', () => {
const dummySchema: FormSchema = {
encounterType: '',
name: 'Sample Form',
processor: 'EncounterFormProcessor',
referencedForms: [],
uuid: '',
version: '1.0',
pages: [
{
label: 'First Page',
sections: [
{
label: 'A Section',
isExpanded: 'true',
questions: [
{
id: 'sampleQuestion',
label: 'A Question of type obs that renders a text input',
type: 'obs',
questionOptions: {
rendering: 'text',
concept: 'a-system-defined-concept-uuid',
},
},
],
},
{
label: 'Another Section',
isExpanded: 'true',
questions: [
{
id: 'anotherSampleQuestion',
label: 'Another Question of type obs whose answers get rendered as radio inputs',
type: 'obs',
questionOptions: {
rendering: 'radio',
concept: 'system-defined-concept-uuid',
answers: [
{
concept: 'another-system-defined-concept-uuid',
label: 'Choice 1',
conceptMappings: [],
},
{
concept: 'yet-another-system-defined-concept-uuid',
label: 'Choice 2',
conceptMappings: [],
},
{
concept: 'yet-one-more-system-defined-concept-uuid',
label: 'Choice 3',
conceptMappings: [],
},
],
},
},
],
},
],
},
],
};

renderInteractiveBuilder({ schema: dummySchema });
expect(screen.getByRole('link', { name: /form builder documentation/i })).toBeInTheDocument();
expect(screen.getByRole('button', { name: /add page/i })).toBeInTheDocument();
expect(screen.getByRole('heading', { name: dummySchema.name })).toBeInTheDocument();
expect(screen.getByRole('heading', { name: dummySchema.pages[0].label })).toBeInTheDocument();
expect(screen.getByRole('button', { name: dummySchema.pages[0].sections[0].label })).toBeInTheDocument();
expect(screen.getByRole('button', { name: dummySchema.pages[0].sections[1].label })).toBeInTheDocument();
expect(screen.getByRole('button', { name: /delete page/i })).toBeInTheDocument();
expect(screen.getByRole('button', { name: /add section/i })).toBeInTheDocument();
});
});

function renderInteractiveBuilder(props = {}) {
const defaultProps = {
isLoading: false,
onSchemaChange: jest.fn(),
schema: {} as Schema,
validationResponse: [],
};

render(<InteractiveBuilder {...defaultProps} {...props} />);
}

0 comments on commit 467d00b

Please sign in to comment.