Skip to content

Commit 37111e6

Browse files
committed
basic create link panel tests
1 parent 79fc76e commit 37111e6

File tree

3 files changed

+110
-3
lines changed

3 files changed

+110
-3
lines changed
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
import React from 'react';
2+
import { render, screen, act } from '@testing-library/react';
3+
import userEvent from '@testing-library/user-event';
4+
import { vi } from 'vitest';
5+
import { MantineProvider } from '@mantine/core';
6+
import { notifications } from '@mantine/notifications';
7+
import StripeCreateLinkPanel from './CreateLink';
8+
import { MemoryRouter } from 'react-router-dom';
9+
10+
describe('StripeCreateLinkPanel Tests', () => {
11+
const createLinkMock = vi.fn();
12+
13+
const renderComponent = async (isLoading = false) => {
14+
await act(async () => {
15+
render(
16+
<MemoryRouter>
17+
<MantineProvider withGlobalClasses withCssVariables forceColorScheme="light">
18+
<StripeCreateLinkPanel createLink={createLinkMock} isLoading={isLoading} />
19+
</MantineProvider>
20+
</MemoryRouter>
21+
);
22+
});
23+
};
24+
25+
beforeEach(() => {
26+
vi.clearAllMocks();
27+
});
28+
29+
it('renders the form fields correctly', async () => {
30+
await renderComponent();
31+
32+
expect(screen.getByText('Invoice ID')).toBeInTheDocument();
33+
expect(screen.getByText('Invoice Amount')).toBeInTheDocument();
34+
expect(screen.getByText('Invoice Recipient Name')).toBeInTheDocument();
35+
expect(screen.getByText('Invoice Recipient Email')).toBeInTheDocument();
36+
expect(screen.getByRole('button', { name: 'Create Link' })).toBeInTheDocument();
37+
});
38+
39+
it('validates required fields before submission', async () => {
40+
const user = userEvent.setup();
41+
await renderComponent();
42+
await user.click(screen.getByRole('button', { name: 'Create Link' }));
43+
expect(createLinkMock).toHaveBeenCalledTimes(0);
44+
await user.type(screen.getByPlaceholderText('[email protected]'), 'invalidEmail');
45+
await user.clear(screen.getByPlaceholderText('ACM100'));
46+
expect(createLinkMock).toHaveBeenCalledTimes(0);
47+
});
48+
49+
it('calls createLink on valid form submission', async () => {
50+
createLinkMock.mockResolvedValue({ link: 'https://test-link.com' });
51+
const user = userEvent.setup();
52+
await renderComponent();
53+
54+
await user.type(screen.getByPlaceholderText('ACM100'), 'INV123');
55+
await user.clear(screen.getByPlaceholderText('100'));
56+
await user.type(screen.getByPlaceholderText('100'), '100');
57+
await user.type(screen.getByPlaceholderText('John Doe'), 'John Doe');
58+
await user.type(screen.getByPlaceholderText('[email protected]'), '[email protected]');
59+
await user.click(screen.getByRole('button', { name: 'Create Link' }));
60+
61+
await act(async () => {
62+
expect(createLinkMock).toHaveBeenCalledWith({
63+
invoiceId: 'INV123',
64+
invoiceAmountUsd: 100,
65+
contactName: 'John Doe',
66+
contactEmail: '[email protected]',
67+
});
68+
});
69+
});
70+
71+
it('displays success modal with returned link', async () => {
72+
createLinkMock.mockResolvedValue({ link: 'https://test-link.com' });
73+
const user = userEvent.setup();
74+
await renderComponent();
75+
76+
await user.type(screen.getByPlaceholderText('ACM100'), 'INV123');
77+
await user.type(screen.getByPlaceholderText('100'), '100');
78+
await user.type(screen.getByPlaceholderText('John Doe'), 'John Doe');
79+
await user.type(screen.getByPlaceholderText('[email protected]'), '[email protected]');
80+
await user.click(screen.getByRole('button', { name: 'Create Link' }));
81+
82+
expect(await screen.findByText('Payment Link Created!')).toBeInTheDocument();
83+
expect(screen.getByText('https://test-link.com')).toBeInTheDocument();
84+
});
85+
86+
it('handles API failure gracefully', async () => {
87+
const notificationsMock = vi.spyOn(notifications, 'show');
88+
createLinkMock.mockRejectedValue(new Error('API Error'));
89+
const user = userEvent.setup();
90+
await renderComponent();
91+
92+
await user.type(screen.getByPlaceholderText('ACM100'), 'INV123');
93+
await user.type(screen.getByPlaceholderText('100'), '100');
94+
await user.type(screen.getByPlaceholderText('John Doe'), 'John Doe');
95+
await user.type(screen.getByPlaceholderText('[email protected]'), '[email protected]');
96+
await user.click(screen.getByRole('button', { name: 'Create Link' }));
97+
98+
expect(notificationsMock).toHaveBeenCalledWith(
99+
expect.objectContaining({
100+
title: 'Error',
101+
message: 'Failed to create payment link. Please try again or contact support.',
102+
color: 'red',
103+
})
104+
);
105+
106+
notificationsMock.mockRestore();
107+
});
108+
});

src/ui/pages/stripe/CreateLink.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import {
1313
Group,
1414
} from '@mantine/core';
1515
import { useForm } from '@mantine/form';
16-
import { showNotification } from '@mantine/notifications';
16+
import { notifications } from '@mantine/notifications';
1717
import { IconAlertCircle } from '@tabler/icons-react';
1818
import React, { useState } from 'react';
1919
import { PostInvoiceLinkRequest, PostInvoiceLinkResponse } from '@common/types/stripe';
@@ -53,7 +53,7 @@ export const StripeCreateLinkPanel: React.FC<StripeCreateLinkPanelProps> = ({
5353
setModalOpened(true);
5454
form.reset();
5555
} catch (err) {
56-
showNotification({
56+
notifications.show({
5757
title: 'Error',
5858
message: 'Failed to create payment link. Please try again or contact support.',
5959
color: 'red',

src/ui/vitest.setup.mjs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@ vi.mock('react-router-dom', async () => {
3535
};
3636
});
3737

38-
3938
vi.mock('@mantine/hooks', async () => {
4039
const rrdactual = await vi.importActual('react-router-dom');
4140
return {

0 commit comments

Comments
 (0)