// SPDX-FileCopyrightText: Copyright Orangebot, Inc. and Medplum contributors
// SPDX-License-Identifier: Apache-2.0
import { MantineProvider } from '@mantine/core';
import { render, screen, waitFor } from '@testing-library/react';
import { MedplumProvider } from '@medplum/react';
import type { Encounter, Organization, Practitioner, Task } from '@medplum/fhirtypes';
import { MockClient, HomerSimpson } from '@medplum/mock';
import { describe, expect, test, vi, beforeEach } from 'vitest';
import { TaskProperties } from './TaskProperties';
describe('TaskProperties', () => {
let medplum: MockClient;
beforeEach(async () => {
medplum = new MockClient();
vi.clearAllMocks();
await medplum.createResource(HomerSimpson);
});
const setup = (
task: Task,
props: Partial<React.ComponentProps<typeof TaskProperties>> = {}
): ReturnType<typeof render> => {
return render(
<MedplumProvider medplum={medplum}>
<MantineProvider>
<TaskProperties task={task} onTaskChange={vi.fn()} {...props} />
</MantineProvider>
</MedplumProvider>
);
};
const mockTask: Task = {
resourceType: 'Task',
id: 'task-123',
status: 'in-progress',
intent: 'order',
code: { text: 'Test Task' },
priority: 'routine',
for: { reference: 'Patient/patient-123', display: 'Test Patient' },
};
test('renders all task property fields', async () => {
setup(mockTask);
await waitFor(() => {
expect(screen.getByText('Status')).toBeInTheDocument();
expect(screen.getByText('Due Date')).toBeInTheDocument();
expect(screen.getByText('Assignee')).toBeInTheDocument();
expect(screen.getByText('Priority')).toBeInTheDocument();
expect(screen.getByText('Based On')).toBeInTheDocument();
expect(screen.getByText('Patient')).toBeInTheDocument();
});
});
test('renders due date field', async () => {
setup(mockTask);
await waitFor(() => {
expect(screen.getByLabelText('Due Date')).toBeInTheDocument();
});
});
test('renders due date field with value when restriction period is set', async () => {
const dueDate = new Date('2024-12-31T00:00:00');
const taskWithDueDate: Task = {
...mockTask,
restriction: {
period: {
end: dueDate.toISOString(),
},
},
};
setup(taskWithDueDate);
await waitFor(() => {
const dueDateInput = screen.getByLabelText('Due Date');
expect(dueDateInput).toBeInTheDocument();
expect(dueDateInput).toHaveValue('2024-12-31T00:00');
});
});
test('renders priority field with current priority value', async () => {
setup(mockTask);
await waitFor(() => {
expect(screen.getByText('routine')).toBeInTheDocument();
});
});
test('shows ReferenceInput for basedOn when not present', async () => {
setup(mockTask);
await waitFor(() => {
expect(screen.getByText('Based On')).toBeInTheDocument();
expect(screen.getByPlaceholderText('Select any resource...')).toBeInTheDocument();
});
});
test('displays encounter when present', async () => {
const encounter: Encounter = {
resourceType: 'Encounter',
id: 'encounter-123',
status: 'finished',
class: { code: 'AMB', system: 'http://terminology.hl7.org/CodeSystem/v3-ActCode' },
};
await medplum.createResource(encounter);
const taskWithEncounter: Task = {
...mockTask,
encounter: { reference: 'Encounter/encounter-123' },
};
setup(taskWithEncounter);
await waitFor(() => {
expect(screen.getByText('Encounter')).toBeInTheDocument();
});
});
test('does not display encounter when not present', async () => {
setup(mockTask);
await waitFor(() => {
expect(screen.getByText('Patient')).toBeInTheDocument();
});
expect(screen.queryByText('Encounter')).not.toBeInTheDocument();
});
test('updates task when initialTask changes', async () => {
const { rerender } = setup(mockTask);
await waitFor(() => {
expect(screen.getByText('in-progress')).toBeInTheDocument();
});
const updatedTask: Task = {
...mockTask,
status: 'completed',
};
rerender(
<MedplumProvider medplum={medplum}>
<MantineProvider>
<TaskProperties task={updatedTask} onTaskChange={vi.fn()} />
</MantineProvider>
</MedplumProvider>
);
await waitFor(() => {
expect(screen.getByText('completed')).toBeInTheDocument();
});
});
test('handles task with owner reference and displays owner', async () => {
const practitioner: Practitioner = {
resourceType: 'Practitioner',
id: 'prac-123',
name: [{ given: ['John'], family: 'Doe' }],
};
await medplum.createResource(practitioner);
const taskWithOwner: Task = {
...mockTask,
owner: { reference: 'Practitioner/prac-123', display: 'John Doe' },
};
setup(taskWithOwner);
await waitFor(() => {
expect(screen.getByText('John Doe')).toBeInTheDocument();
});
});
test('handles task with organization owner and displays organization', async () => {
const organization: Organization = {
resourceType: 'Organization',
id: 'org-123',
name: 'Test Organization',
};
await medplum.createResource(organization);
const taskWithOrgOwner: Task = {
...mockTask,
owner: { reference: 'Organization/org-123', display: 'Test Organization' },
};
setup(taskWithOrgOwner);
await waitFor(() => {
expect(screen.getByText('Test Organization')).toBeInTheDocument();
});
});
test('displays encounter reference when encounter is present', async () => {
const encounter: Encounter = {
resourceType: 'Encounter',
id: 'encounter-123',
status: 'finished',
class: { code: 'AMB', system: 'http://terminology.hl7.org/CodeSystem/v3-ActCode' },
};
await medplum.createResource(encounter);
const taskWithEncounter: Task = {
...mockTask,
encounter: { reference: 'Encounter/encounter-123' },
};
setup(taskWithEncounter);
await waitFor(() => {
expect(screen.getByText('Encounter')).toBeInTheDocument();
});
});
});