Skip to main content
Glama
TaskDetailsModal.test.tsx7.89 kB
// SPDX-FileCopyrightText: Copyright Orangebot, Inc. and Medplum contributors // SPDX-License-Identifier: Apache-2.0 import { MantineProvider } from '@mantine/core'; import { act, render, screen, waitFor } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { MedplumProvider } from '@medplum/react'; import type { Task, Patient } from '@medplum/fhirtypes'; import { MockClient } from '@medplum/mock'; import { MemoryRouter, Route, Routes } from 'react-router'; import { describe, expect, test, vi, beforeEach } from 'vitest'; import { TaskDetailsModal } from './TaskDetailsModal'; import * as usePatientModule from '../../hooks/usePatient'; describe('TaskDetailsModal', () => { let medplum: MockClient; beforeEach(() => { medplum = new MockClient(); vi.clearAllMocks(); vi.spyOn(medplum, 'updateResource').mockResolvedValue({ id: 'task-123', resourceType: 'Task' } as Task & { id: string; }); }); const mockPatient: Patient = { resourceType: 'Patient', id: 'patient-123', name: [{ given: ['John'], family: 'Doe' }], }; const mockTask: Task = { resourceType: 'Task', id: 'task-123', status: 'in-progress', intent: 'order', code: { text: 'Test Task' }, description: 'Test task description', for: { reference: 'Patient/patient-123' }, authoredOn: '2023-01-01T12:00:00Z', }; const setup = (): ReturnType<typeof render> => { vi.spyOn(usePatientModule, 'usePatient').mockReturnValue(mockPatient); return render( <MemoryRouter initialEntries={['/Patient/patient-123/Encounter/encounter-123/Task/task-123']}> <MedplumProvider medplum={medplum}> <MantineProvider> <Routes> <Route path="/Patient/:patientId/Encounter/:encounterId/Task/:taskId" element={<TaskDetailsModal />} /> </Routes> </MantineProvider> </MedplumProvider> </MemoryRouter> ); }; test('renders task details modal', async () => { await medplum.createResource(mockTask); setup(); await waitFor(() => { expect(screen.getByText('Test Task')).toBeInTheDocument(); expect(screen.getByText('Test task description')).toBeInTheDocument(); }); }); test('displays patient information', async () => { await medplum.createResource(mockTask); await medplum.createResource(mockPatient); setup(); await waitFor(() => { expect(screen.getByText('View Patient')).toBeInTheDocument(); expect(screen.getByText('John Doe')).toBeInTheDocument(); }); }); test('allows changing due date', async () => { await medplum.createResource(mockTask); setup(); await waitFor(() => { expect(screen.getByLabelText('Due Date')).toBeInTheDocument(); }); }); test('allows changing task status', async () => { await medplum.createResource(mockTask); setup(); await waitFor(() => { expect(screen.getByText('Status')).toBeInTheDocument(); }); }); test('allows adding a note', async () => { const user = userEvent.setup(); await medplum.createResource(mockTask); setup(); await waitFor(() => { expect(screen.getByPlaceholderText('Add note to this task')).toBeInTheDocument(); }); const noteInput = screen.getByPlaceholderText('Add note to this task'); await user.type(noteInput, 'This is a test note'); expect(noteInput).toHaveValue('This is a test note'); }); test('saves changes when Save Changes button is clicked', async () => { const user = userEvent.setup(); await medplum.createResource(mockTask); setup(); await waitFor(() => { expect(screen.getByText('Save Changes')).toBeInTheDocument(); }); const noteInput = screen.getByPlaceholderText('Add note to this task'); await user.type(noteInput, 'Updated note'); const saveButton = screen.getByText('Save Changes'); await act(async () => { await user.click(saveButton); }); await waitFor(() => { expect(medplum.updateResource).toHaveBeenCalled(); }); }); test('shows success notification after saving', async () => { const user = userEvent.setup(); await medplum.createResource(mockTask); setup(); await waitFor(() => { expect(screen.getByText('Save Changes')).toBeInTheDocument(); }); const saveButton = screen.getByText('Save Changes'); await act(async () => { await user.click(saveButton); }); await waitFor(() => { expect(medplum.updateResource).toHaveBeenCalled(); }); }); test('handles save error gracefully', async () => { const user = userEvent.setup(); await medplum.createResource(mockTask); vi.spyOn(medplum, 'updateResource').mockRejectedValueOnce(new Error('Update failed')); setup(); await waitFor(() => { expect(screen.getByText('Save Changes')).toBeInTheDocument(); }); const saveButton = screen.getByText('Save Changes'); await act(async () => { await user.click(saveButton); }); await waitFor(() => { expect(medplum.updateResource).toHaveBeenCalled(); }); }); test('closes modal when close button is clicked', async () => { const user = userEvent.setup(); await medplum.createResource(mockTask); setup(); await waitFor(() => { expect(screen.getByText('Test Task')).toBeInTheDocument(); }); const closeButton = document.querySelector('.mantine-Modal-close'); expect(closeButton).toBeInTheDocument(); if (closeButton) { await user.click(closeButton); } await waitFor(() => { expect(screen.queryByText('Test Task')).not.toBeInTheDocument(); }); }); test('handles task fetch error', async () => { vi.spyOn(medplum, 'readResource').mockRejectedValueOnce(new Error('Task not found')); setup(); await waitFor(() => { expect(medplum.readResource).toHaveBeenCalled(); }); }); test('updates task with all fields', async () => { const user = userEvent.setup(); const taskWithAllFields: Task = { ...mockTask, owner: { reference: 'Practitioner/prac-123' }, restriction: { period: { end: '2023-12-31' } }, }; await medplum.createResource(taskWithAllFields); setup(); await waitFor(() => { expect(screen.getByText('Save Changes')).toBeInTheDocument(); }); const noteInput = screen.getByPlaceholderText('Add note to this task'); await user.type(noteInput, 'Comprehensive update'); const saveButton = screen.getByText('Save Changes'); await act(async () => { await user.click(saveButton); }); await waitFor(() => { expect(medplum.updateResource).toHaveBeenCalled(); const calls = (medplum.updateResource as any).mock.calls; expect(calls.length).toBeGreaterThan(0); const updatedTask = calls[calls.length - 1][0] as Task; expect(updatedTask.note).toBeDefined(); expect(updatedTask.note?.[0].text).toBe('Comprehensive update'); }); }); test('does not add empty notes', async () => { const user = userEvent.setup(); await medplum.createResource(mockTask); setup(); await waitFor(() => { expect(screen.getByText('Save Changes')).toBeInTheDocument(); }); const noteInput = screen.getByPlaceholderText('Add note to this task'); await user.type(noteInput, 'Test'); await user.clear(noteInput); const saveButton = screen.getByText('Save Changes'); await act(async () => { await user.click(saveButton); }); await waitFor(() => { expect(medplum.updateResource).toHaveBeenCalled(); const calls = (medplum.updateResource as any).mock.calls; if (calls.length > 0) { const updatedTask = calls[calls.length - 1][0] as Task; expect(updatedTask.note).toBeUndefined(); } }); }); });

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/medplum/medplum'

If you have feedback or need assistance with the MCP directory API, please join our Discord server