mirror of https://github.com/buster-so/buster.git
wrote simple unit tests
Update InvitePeopleModal.test.tsx
This commit is contained in:
parent
1892f812f0
commit
9924120267
|
@ -0,0 +1,153 @@
|
|||
import { render, screen, fireEvent, waitFor } from '@testing-library/react';
|
||||
import { InvitePeopleModal } from './InvitePeopleModal';
|
||||
import { useInviteUser } from '@/api/buster_rest/users';
|
||||
import { useBusterNotifications } from '@/context/BusterNotifications';
|
||||
|
||||
// Mock the hooks
|
||||
jest.mock('@/api/buster_rest/users', () => ({
|
||||
useInviteUser: jest.fn()
|
||||
}));
|
||||
|
||||
jest.mock('@/context/BusterNotifications', () => ({
|
||||
useBusterNotifications: jest.fn()
|
||||
}));
|
||||
|
||||
describe('InvitePeopleModal', () => {
|
||||
const mockOnClose = jest.fn();
|
||||
const mockMutateAsync = jest.fn();
|
||||
const mockOpenErrorMessage = jest.fn();
|
||||
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
(useInviteUser as jest.Mock).mockReturnValue({
|
||||
mutateAsync: mockMutateAsync,
|
||||
isPending: false
|
||||
});
|
||||
(useBusterNotifications as jest.Mock).mockReturnValue({
|
||||
openErrorMessage: mockOpenErrorMessage
|
||||
});
|
||||
});
|
||||
|
||||
it('renders correctly when open', () => {
|
||||
render(<InvitePeopleModal open={true} onClose={mockOnClose} />);
|
||||
|
||||
expect(screen.getByText('Invite others to join your workspace')).toBeInTheDocument();
|
||||
expect(screen.getByPlaceholderText(/buster@bluthbananas.com/)).toBeInTheDocument();
|
||||
expect(screen.getByRole('button', { name: 'Send invites' })).toBeDisabled();
|
||||
});
|
||||
|
||||
it('handles valid email input', async () => {
|
||||
render(<InvitePeopleModal open={true} onClose={mockOnClose} />);
|
||||
|
||||
const input = screen.getByPlaceholderText(/buster@bluthbananas.com/);
|
||||
fireEvent.change(input, { target: { value: 'test@example.com' } });
|
||||
fireEvent.keyDown(input, { key: 'Enter' });
|
||||
|
||||
expect(screen.getByText('test@example.com')).toBeInTheDocument();
|
||||
expect(screen.getByText('Send invites')).toBeEnabled();
|
||||
});
|
||||
|
||||
it('handles invalid email input', () => {
|
||||
render(<InvitePeopleModal open={true} onClose={mockOnClose} />);
|
||||
|
||||
const input = screen.getByPlaceholderText(/buster@bluthbananas.com/);
|
||||
fireEvent.change(input, { target: { value: 'invalid-email' } });
|
||||
fireEvent.keyDown(input, { key: 'Enter' });
|
||||
|
||||
expect(mockOpenErrorMessage).toHaveBeenCalledWith('Invalid email');
|
||||
expect(screen.queryByText('invalid-email')).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('handles multiple email inputs', () => {
|
||||
render(<InvitePeopleModal open={true} onClose={mockOnClose} />);
|
||||
|
||||
const input = screen.getByPlaceholderText(/buster@bluthbananas.com/);
|
||||
fireEvent.change(input, { target: { value: 'test1@example.com, test2@example.com' } });
|
||||
fireEvent.keyDown(input, { key: 'Enter' });
|
||||
|
||||
expect(screen.getByText('test1@example.com')).toBeInTheDocument();
|
||||
expect(screen.getByText('test2@example.com')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('removes email tag when clicked', async () => {
|
||||
render(<InvitePeopleModal open={true} onClose={mockOnClose} />);
|
||||
|
||||
const input = screen.getByPlaceholderText(/buster@bluthbananas.com/);
|
||||
fireEvent.change(input, { target: { value: 'test@example.com' } });
|
||||
fireEvent.keyDown(input, { key: 'Enter' });
|
||||
|
||||
const tag = screen.getByText('test@example.com').closest('[data-tag="true"]');
|
||||
expect(tag).toBeInTheDocument();
|
||||
|
||||
const removeButton = tag?.querySelector('button');
|
||||
expect(removeButton).toBeInTheDocument();
|
||||
fireEvent.pointerDown(removeButton!);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.queryByText('test@example.com')).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
it('sends invites when submit button is clicked', async () => {
|
||||
render(<InvitePeopleModal open={true} onClose={mockOnClose} />);
|
||||
|
||||
const input = screen.getByPlaceholderText(/buster@bluthbananas.com/);
|
||||
fireEvent.change(input, { target: { value: 'test@example.com' } });
|
||||
fireEvent.keyDown(input, { key: 'Enter' });
|
||||
|
||||
const submitButton = screen.getByText('Send invites');
|
||||
fireEvent.click(submitButton);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(mockMutateAsync).toHaveBeenCalledWith({
|
||||
emails: ['test@example.com']
|
||||
});
|
||||
expect(mockOnClose).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
it('deduplicates email addresses', async () => {
|
||||
render(<InvitePeopleModal open={true} onClose={mockOnClose} />);
|
||||
|
||||
const input = screen.getByPlaceholderText(/buster@bluthbananas.com/);
|
||||
fireEvent.change(input, { target: { value: 'test@example.com, test@example.com' } });
|
||||
fireEvent.keyDown(input, { key: 'Enter' });
|
||||
|
||||
const submitButton = screen.getByText('Send invites');
|
||||
fireEvent.click(submitButton);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(mockMutateAsync).toHaveBeenCalledWith({
|
||||
emails: ['test@example.com']
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('handles pasting multiple email addresses', async () => {
|
||||
render(<InvitePeopleModal open={true} onClose={mockOnClose} />);
|
||||
|
||||
const input = screen.getByPlaceholderText(/buster@bluthbananas.com/);
|
||||
const pastedEmails = 'test1@example.com, test2@example.com, test3@example.com';
|
||||
|
||||
fireEvent.paste(input, {
|
||||
clipboardData: {
|
||||
getData: () => pastedEmails
|
||||
}
|
||||
});
|
||||
|
||||
expect(screen.getByText('test1@example.com')).toBeInTheDocument();
|
||||
expect(screen.getByText('test2@example.com')).toBeInTheDocument();
|
||||
expect(screen.getByText('test3@example.com')).toBeInTheDocument();
|
||||
|
||||
// Remove the first email
|
||||
const firstTag = screen.getByText('test1@example.com').closest('[data-tag="true"]');
|
||||
const removeButton = firstTag?.querySelector('button');
|
||||
fireEvent.pointerDown(removeButton!);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.queryByText('test1@example.com')).not.toBeInTheDocument();
|
||||
expect(screen.getByText('test2@example.com')).toBeInTheDocument();
|
||||
expect(screen.getByText('test3@example.com')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
});
|
|
@ -6,6 +6,7 @@ import { useInviteUser } from '@/api/buster_rest/users';
|
|||
import { validate } from 'email-validator';
|
||||
import { useBusterNotifications } from '@/context/BusterNotifications';
|
||||
import uniq from 'lodash/uniq';
|
||||
import { timeout } from '@/lib';
|
||||
|
||||
export const InvitePeopleModal: React.FC<{
|
||||
open: boolean;
|
||||
|
@ -14,12 +15,20 @@ export const InvitePeopleModal: React.FC<{
|
|||
const [emails, setEmails] = React.useState<string[]>([]);
|
||||
const { mutateAsync: inviteUsers, isPending: inviting } = useInviteUser();
|
||||
const [inputText, setInputText] = React.useState<string>('');
|
||||
const { openErrorMessage } = useBusterNotifications();
|
||||
const { openErrorMessage, openSuccessMessage } = useBusterNotifications();
|
||||
|
||||
const handleInvite = useMemoizedFn(async () => {
|
||||
const allEmails = uniq([...emails, inputText].filter((email) => !!email && validate(email)));
|
||||
try {
|
||||
await inviteUsers({ emails: allEmails });
|
||||
onClose();
|
||||
openSuccessMessage('Invites sent');
|
||||
await timeout(330);
|
||||
setEmails([]);
|
||||
setInputText('');
|
||||
} catch (error) {
|
||||
openErrorMessage('Failed to invite users');
|
||||
}
|
||||
});
|
||||
|
||||
const memoizedHeader = useMemo(() => {
|
||||
|
|
Loading…
Reference in New Issue