Skip to main content
Glama
BillingTab.test.tsx7.52 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 { ChargeItem, Claim, Coverage, Encounter, Patient, Practitioner } from '@medplum/fhirtypes'; import { HomerSimpson, DrAliceSmith, MockClient } from '@medplum/mock'; import { MemoryRouter } from 'react-router'; import { describe, expect, test, beforeEach, vi } from 'vitest'; import { BillingTab } from './BillingTab'; const mockPatient: Patient = { resourceType: 'Patient', id: 'patient-123', name: [{ given: ['John'], family: 'Doe' }], }; const mockEncounter: Encounter = { resourceType: 'Encounter', id: 'encounter-123', status: 'finished', class: { code: 'AMB', system: 'http://terminology.hl7.org/CodeSystem/v3-ActCode' }, subject: { reference: `Patient/${HomerSimpson.id}` }, participant: [ { individual: { reference: 'Practitioner/practitioner-123' }, }, ], }; const mockCoverage: Coverage = { resourceType: 'Coverage', id: 'coverage-123', status: 'active', beneficiary: { reference: 'Patient/patient-123' }, payor: [{ reference: 'Organization/organization-123' }], }; const mockPractitioner: Practitioner = { resourceType: 'Practitioner', id: 'practitioner-123', name: [{ given: ['Dr.'], family: 'Test' }], }; const mockChargeItem: ChargeItem = { resourceType: 'ChargeItem', id: 'charge-123', status: 'billable', subject: { reference: 'Patient/patient-123' }, code: { text: 'Test Charge' }, }; const mockClaim: Claim = { resourceType: 'Claim', id: 'claim-123', status: 'active', type: { coding: [{ code: 'professional' }] }, use: 'claim', created: new Date().toISOString(), priority: { coding: [{ code: 'normal' }] }, insurance: [], patient: { reference: 'Patient/patient-123' }, provider: { reference: 'Practitioner/practitioner-123' }, }; describe('BillingTab', () => { let medplum: MockClient; beforeEach(async () => { medplum = new MockClient(); await medplum.createResource(HomerSimpson); await medplum.createResource(DrAliceSmith); vi.clearAllMocks(); }); const setup = (props: Partial<Parameters<typeof BillingTab>[0]> = {}): ReturnType<typeof render> => { return render( <MemoryRouter> <MedplumProvider medplum={medplum}> <MantineProvider> <BillingTab patient={mockPatient} encounter={mockEncounter} setEncounter={vi.fn()} practitioner={mockPractitioner} setPractitioner={vi.fn()} chargeItems={[]} setChargeItems={vi.fn()} claim={undefined} setClaim={vi.fn()} {...props} /> </MantineProvider> </MedplumProvider> </MemoryRouter> ); }; test('renders visit details panel', () => { setup(); expect(screen.getByText('Visit Details')).toBeInTheDocument(); expect(screen.getByText(/Dr\. Test/i)).toBeInTheDocument(); }); test('renders condition list when there are conditions', async () => { const mockCondition = { resourceType: 'Condition' as const, id: 'condition-1', code: { coding: [{ code: 'R51', display: 'Headache' }], text: 'Headache', }, }; vi.spyOn(medplum, 'readReference').mockResolvedValue(mockCondition as any); setup({ encounter: { ...mockEncounter, diagnosis: [ { condition: { reference: 'Condition/condition-1' }, }, ], }, }); expect(screen.getByText('Diagnosis')).toBeInTheDocument(); expect(screen.getByText('Add Diagnosis')).toBeInTheDocument(); await waitFor(() => { expect(screen.getByText('Headache')).toBeInTheDocument(); }); }); test('renders condition list when there are NO conditions', () => { setup({ encounter: { ...mockEncounter, diagnosis: [], }, }); expect(screen.getByText('Diagnosis')).toBeInTheDocument(); expect(screen.getByText('Add Diagnosis')).toBeInTheDocument(); expect(screen.queryByText('Headache')).not.toBeInTheDocument(); }); test('renders charge item list when charge items are provided', () => { setup({ chargeItems: [mockChargeItem] }); expect(screen.getByText('Charge Items')).toBeInTheDocument(); expect(screen.getByText('Add Charge Item')).toBeInTheDocument(); // Add assertions for specific charge item information if (mockChargeItem.code?.coding?.[0]?.display) { expect(screen.getByText(mockChargeItem.code.coding[0].display)).toBeInTheDocument(); } if (mockChargeItem.code?.coding?.[0]?.code) { expect(screen.getByText(mockChargeItem.code.coding[0].code)).toBeInTheDocument(); } if (mockChargeItem.quantity?.value !== undefined) { expect(screen.getByText(mockChargeItem.quantity.value.toString())).toBeInTheDocument(); } }); test('does not render export claim button when no claim', () => { setup({ claim: undefined }); expect(screen.queryByText('Export Claim')).not.toBeInTheDocument(); }); test('renders export claim button when claim exists', () => { setup({ claim: mockClaim }); expect(screen.getByText('Export Claim')).toBeInTheDocument(); }); test('shows export menu options when export button is clicked', async () => { const user = userEvent.setup(); setup({ claim: mockClaim }); const exportButton = screen.getByText('Export Claim'); await user.click(exportButton); await waitFor(() => { expect(screen.getByText('CMS 1500 Form')).toBeInTheDocument(); expect(screen.getByText('EDI X12')).toBeInTheDocument(); expect(screen.getByText('NUCC Crosswalk CSV')).toBeInTheDocument(); }); }); test('exports claim as CMS 1500 when option is selected', async () => { const user = userEvent.setup(); vi.spyOn(medplum, 'searchResources').mockResolvedValue([mockCoverage] as any); vi.spyOn(medplum, 'post').mockResolvedValue({ resourceType: 'Media', content: { url: 'https://example.com/claim.pdf' }, } as any); const windowOpenSpy = vi.spyOn(window, 'open').mockImplementation(() => null); setup({ claim: mockClaim }); const exportButton = screen.getByText('Export Claim'); await user.click(exportButton); await waitFor(() => { expect(screen.getByText('CMS 1500 Form')).toBeInTheDocument(); }); await user.click(screen.getByText('CMS 1500 Form')); await waitFor(() => { expect(medplum.post).toHaveBeenCalled(); expect(windowOpenSpy).toHaveBeenCalledWith('https://example.com/claim.pdf', '_blank'); }); windowOpenSpy.mockRestore(); }); test('renders request billing service button', () => { setup({ claim: mockClaim }); expect(screen.getByText('Request to connect a billing service')).toBeInTheDocument(); }); test('fetches coverage on mount', async () => { vi.spyOn(medplum, 'searchResources').mockResolvedValue([mockCoverage] as any); await act(async () => { setup(); }); await waitFor(() => { expect(medplum.searchResources).toHaveBeenCalledWith( 'Coverage', expect.stringContaining('patient=Patient/patient-123') ); }); }); });

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