Skip to content

Commit

Permalink
test(ui-voip): Normalize @rocket.chat/ui-voip unit tests (#33739)
Browse files Browse the repository at this point in the history
  • Loading branch information
tassoevan authored Oct 24, 2024
1 parent 72182ba commit c2b92f4
Show file tree
Hide file tree
Showing 15 changed files with 258 additions and 227 deletions.
2 changes: 2 additions & 0 deletions packages/ui-voip/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
"devDependencies": {
"@babel/core": "~7.25.8",
"@faker-js/faker": "~8.0.2",
"@react-spectrum/test-utils": "~1.0.0-alpha.2",
"@rocket.chat/css-in-js": "~0.31.25",
"@rocket.chat/eslint-config": "workspace:^",
"@rocket.chat/fuselage": "^0.59.3",
Expand All @@ -49,6 +50,7 @@
"@types/jest": "~29.5.12",
"@types/jest-axe": "~3.5.9",
"@types/react": "~17.0.80",
"@types/react-dom": "~17.0.25",
"eslint": "~8.45.0",
"eslint-plugin-react": "~7.32.2",
"eslint-plugin-react-hooks": "~4.6.2",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,64 +2,63 @@ import { faker } from '@faker-js/faker';
import { mockAppRoot } from '@rocket.chat/mock-providers';
import { composeStories } from '@storybook/react';
import { render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { axe } from 'jest-axe';

import VoipContactId from './VoipContactId';
import * as stories from './VoipContactId.stories';

const testCases = Object.values(composeStories(stories)).map((story) => [story.storyName || 'Story', story]);

describe('VoipContactId', () => {
beforeAll(() => {
Object.assign(navigator, {
clipboard: {
writeText: jest.fn(),
},
});
beforeAll(() => {
Object.assign(navigator, {
clipboard: {
writeText: jest.fn(),
},
});
});

test.each(testCases)(`renders %s without crashing`, async (_storyname, Story) => {
const tree = render(<Story />, { wrapper: mockAppRoot().build(), legacyRoot: true });
expect(tree.baseElement).toMatchSnapshot();
});
test.each(testCases)(`renders %s without crashing`, async (_storyname, Story) => {
const tree = render(<Story />, { wrapper: mockAppRoot().build(), legacyRoot: true });
expect(tree.baseElement).toMatchSnapshot();
});

test.each(testCases)('%s should have no a11y violations', async (_storyname, Story) => {
const { container } = render(<Story />, { wrapper: mockAppRoot().build(), legacyRoot: true });
test.each(testCases)('%s should have no a11y violations', async (_storyname, Story) => {
const { container } = render(<Story />, { wrapper: mockAppRoot().build(), legacyRoot: true });

const results = await axe(container);
expect(results).toHaveNoViolations();
});

const results = await axe(container);
expect(results).toHaveNoViolations();
it('should display avatar and name when username is available', () => {
render(<VoipContactId name='John Doe' username='john.doe' />, {
wrapper: mockAppRoot().build(),
legacyRoot: true,
});

it('should display avatar and name when username is available', () => {
render(<VoipContactId name='John Doe' username='john.doe' />, {
wrapper: mockAppRoot().build(),
legacyRoot: true,
});
expect(screen.getByRole('img', { hidden: true })).toHaveAttribute('title', 'john.doe');
expect(screen.getByText('John Doe')).toBeInTheDocument();
});

expect(screen.getByRole('img', { hidden: true })).toHaveAttribute('title', 'john.doe');
expect(screen.getByText('John Doe')).toBeInTheDocument();
it('should display transferedBy information when available', () => {
render(<VoipContactId name='John Doe' username='john.doe' transferedBy='Jane Doe' />, {
wrapper: mockAppRoot().build(),
legacyRoot: true,
});

it('should display transferedBy information when available', () => {
render(<VoipContactId name='John Doe' username='john.doe' transferedBy='Jane Doe' />, {
wrapper: mockAppRoot().build(),
legacyRoot: true,
});
expect(screen.getByText('From: Jane Doe')).toBeInTheDocument();
});

expect(screen.getByText('From: Jane Doe')).toBeInTheDocument();
it('should display copy button when username isnt available', async () => {
const phone = faker.phone.number();
render(<VoipContactId name={phone} />, {
wrapper: mockAppRoot().build(),
legacyRoot: true,
});

it('should display copy button when username isnt available', async () => {
const phone = faker.phone.number();
render(<VoipContactId name={phone} />, {
wrapper: mockAppRoot().build(),
legacyRoot: true,
});
const copyButton = screen.getByRole('button', { name: 'Copy_phone_number' });
expect(copyButton).toBeInTheDocument();

const copyButton = screen.getByRole('button', { name: 'Copy_phone_number' });
expect(copyButton).toBeInTheDocument();

copyButton.click();
await waitFor(() => expect(navigator.clipboard.writeText).toHaveBeenCalledWith(phone));
});
await userEvent.click(copyButton);
await waitFor(() => expect(navigator.clipboard.writeText).toHaveBeenCalledWith(phone));
});
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`VoipContactId renders Loading without crashing 1`] = `
exports[`renders Loading without crashing 1`] = `
<body>
<div>
<div
Expand All @@ -21,7 +21,7 @@ exports[`VoipContactId renders Loading without crashing 1`] = `
</body>
`;

exports[`VoipContactId renders WithPhoneNumber without crashing 1`] = `
exports[`renders WithPhoneNumber without crashing 1`] = `
<body>
<div>
<div
Expand Down Expand Up @@ -59,7 +59,7 @@ exports[`VoipContactId renders WithPhoneNumber without crashing 1`] = `
</body>
`;

exports[`VoipContactId renders WithTransfer without crashing 1`] = `
exports[`renders WithTransfer without crashing 1`] = `
<body>
<div>
<div
Expand Down Expand Up @@ -106,7 +106,7 @@ exports[`VoipContactId renders WithTransfer without crashing 1`] = `
</body>
`;

exports[`VoipContactId renders WithUsername without crashing 1`] = `
exports[`renders WithUsername without crashing 1`] = `
<body>
<div>
<div
Expand Down
104 changes: 54 additions & 50 deletions packages/ui-voip/src/components/VoipDialPad/VoipDialPad.spec.tsx
Original file line number Diff line number Diff line change
@@ -1,75 +1,79 @@
/* eslint-disable no-await-in-loop */
import { installPointerEvent, triggerLongPress } from '@react-spectrum/test-utils';
import { mockAppRoot } from '@rocket.chat/mock-providers';
import { fireEvent, render, screen } from '@testing-library/react';
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';

import DialPad from './VoipDialPad';

describe('VoipDialPad', () => {
beforeEach(() => {
jest.useFakeTimers();
});
const user = userEvent.setup({ advanceTimers: jest.advanceTimersByTime });

afterEach(() => {
jest.clearAllTimers();
});
installPointerEvent();

it('should not be editable by default', () => {
render(<DialPad value='' onChange={jest.fn()} />, { wrapper: mockAppRoot().build(), legacyRoot: true });
beforeEach(() => {
jest.useFakeTimers();
});

expect(screen.getByLabelText('Phone_number')).toHaveAttribute('readOnly');
});
afterEach(() => {
jest.clearAllTimers();
});

it('should enable input when editable', () => {
render(<DialPad editable value='' onChange={jest.fn()} />, { wrapper: mockAppRoot().build(), legacyRoot: true });
it('should not be editable by default', async () => {
render(<DialPad value='' onChange={jest.fn()} />, { wrapper: mockAppRoot().build(), legacyRoot: true });

expect(screen.getByLabelText('Phone_number')).not.toHaveAttribute('readOnly');
});
expect(screen.getByLabelText('Phone_number')).toHaveAttribute('readOnly');
});

it('should disable backspace button when input is empty', () => {
render(<DialPad editable value='' onChange={jest.fn()} />, { wrapper: mockAppRoot().build(), legacyRoot: true });
it('should enable input when editable', async () => {
render(<DialPad editable value='' onChange={jest.fn()} />, { wrapper: mockAppRoot().build(), legacyRoot: true });

expect(screen.getByTestId('dial-paid-input-backspace')).toBeDisabled();
});
expect(screen.getByLabelText('Phone_number')).not.toHaveAttribute('readOnly');
});

it('should enable backspace button when input has value', () => {
render(<DialPad editable value='123' onChange={jest.fn()} />, { wrapper: mockAppRoot().build(), legacyRoot: true });
it('should disable backspace button when input is empty', async () => {
render(<DialPad editable value='' onChange={jest.fn()} />, { wrapper: mockAppRoot().build(), legacyRoot: true });

expect(screen.getByTestId('dial-paid-input-backspace')).toBeEnabled();
});
expect(screen.getByTestId('dial-paid-input-backspace')).toBeDisabled();
});

it('should remove last character when backspace is clicked', () => {
const fn = jest.fn();
render(<DialPad editable value='123' onChange={fn} />, { wrapper: mockAppRoot().build(), legacyRoot: true });
it('should enable backspace button when input has value', async () => {
render(<DialPad editable value='123' onChange={jest.fn()} />, { wrapper: mockAppRoot().build(), legacyRoot: true });

expect(screen.getByLabelText('Phone_number')).toHaveValue('123');
expect(screen.getByTestId('dial-paid-input-backspace')).toBeEnabled();
});

screen.getByTestId('dial-paid-input-backspace').click();
it('should remove last character when backspace is clicked', async () => {
const fn = jest.fn();
render(<DialPad editable value='123' onChange={fn} />, { wrapper: mockAppRoot().build(), legacyRoot: true });

expect(fn).toHaveBeenCalledWith('12');
});
expect(screen.getByLabelText('Phone_number')).toHaveValue('123');

it('should call onChange when number is clicked', () => {
const fn = jest.fn();
render(<DialPad editable value='123' onChange={fn} />, { wrapper: mockAppRoot().build(), legacyRoot: true });
await user.click(screen.getByTestId('dial-paid-input-backspace'));

expect(fn).toHaveBeenCalledWith('12');
});

it('should call onChange when number is clicked', async () => {
const fn = jest.fn();
render(<DialPad editable value='123' onChange={fn} />, { wrapper: mockAppRoot().build(), legacyRoot: true });

for (const digit of ['1', '2', '3', '4', '5', '6', '7', '8', '9', '0']) {
await user.click(screen.getByTestId(`dial-pad-button-${digit}`));
expect(fn).toHaveBeenCalledWith(`123${digit}`, digit);
}
});

['1', '2', '3', '4', '5', '6', '7', '8', '9', '0'].forEach((digit) => {
screen.getByTestId(`dial-pad-button-${digit}`).click();
expect(fn).toHaveBeenCalledWith(`123${digit}`, digit);
});
});
it('should call onChange with + when 0 pressed and held', async () => {
const fn = jest.fn();
render(<DialPad editable longPress value='123' onChange={fn} />, { wrapper: mockAppRoot().build(), legacyRoot: true });

xit('should call onChange with + when 0 pressed and held', () => {
const fn = jest.fn();
render(<DialPad editable longPress value='123' onChange={fn} />, { wrapper: mockAppRoot().build(), legacyRoot: true });
const button = screen.getByTestId('dial-pad-button-0');

const button = screen.getByTestId('dial-pad-button-0');
await user.click(button);

button.click();
expect(fn).toHaveBeenCalledWith('1230', '0');
expect(fn).toHaveBeenCalledWith('1230', '0');

fireEvent.pointerDown(button);
jest.runOnlyPendingTimers();
fireEvent.pointerUp(button);
await triggerLongPress({ element: button, advanceTimer: (time = 800) => jest.advanceTimersByTime(time) });

expect(fn).toHaveBeenCalledWith('123+', '+');
});
expect(fn).toHaveBeenCalledWith('123+', '+');
});
17 changes: 8 additions & 9 deletions packages/ui-voip/src/components/VoipPopup/VoipPopup.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,49 +18,48 @@ jest.mock('../../hooks/useVoipDialer', () => ({
}));

const mockedUseVoipSession = jest.mocked(useVoipSession);
const appRoot = mockAppRoot();

it('should properly render incoming popup', async () => {
mockedUseVoipSession.mockImplementationOnce(() => createMockVoipSession({ type: 'INCOMING' }));
render(<VoipPopup />, { wrapper: appRoot.build(), legacyRoot: true });
render(<VoipPopup />, { wrapper: mockAppRoot().build(), legacyRoot: true });

expect(screen.getByTestId('vc-popup-incoming')).toBeInTheDocument();
});

it('should properly render ongoing popup', async () => {
mockedUseVoipSession.mockImplementationOnce(() => createMockVoipSession({ type: 'ONGOING' }));

render(<VoipPopup />, { wrapper: appRoot.build(), legacyRoot: true });
render(<VoipPopup />, { wrapper: mockAppRoot().build(), legacyRoot: true });

expect(screen.getByTestId('vc-popup-ongoing')).toBeInTheDocument();
});

it('should properly render outgoing popup', async () => {
mockedUseVoipSession.mockImplementationOnce(() => createMockVoipSession({ type: 'OUTGOING' }));

render(<VoipPopup />, { wrapper: appRoot.build(), legacyRoot: true });
render(<VoipPopup />, { wrapper: mockAppRoot().build(), legacyRoot: true });

expect(screen.getByTestId('vc-popup-outgoing')).toBeInTheDocument();
});

it('should properly render error popup', async () => {
mockedUseVoipSession.mockImplementationOnce(() => createMockVoipSession({ type: 'ERROR' }));

render(<VoipPopup />, { wrapper: appRoot.build(), legacyRoot: true });
render(<VoipPopup />, { wrapper: mockAppRoot().build(), legacyRoot: true });

expect(screen.getByTestId('vc-popup-error')).toBeInTheDocument();
});

it('should properly render dialer popup', async () => {
render(<VoipPopup />, { wrapper: appRoot.build(), legacyRoot: true });
render(<VoipPopup />, { wrapper: mockAppRoot().build(), legacyRoot: true });

expect(screen.getByTestId('vc-popup-dialer')).toBeInTheDocument();
});

it('should prioritize session over dialer', async () => {
mockedUseVoipSession.mockImplementationOnce(() => createMockVoipSession({ type: 'INCOMING' }));

render(<VoipPopup />, { wrapper: appRoot.build(), legacyRoot: true });
render(<VoipPopup />, { wrapper: mockAppRoot().build(), legacyRoot: true });

expect(screen.queryByTestId('vc-popup-dialer')).not.toBeInTheDocument();
expect(screen.getByTestId('vc-popup-incoming')).toBeInTheDocument();
Expand All @@ -69,12 +68,12 @@ it('should prioritize session over dialer', async () => {
const testCases = Object.values(composeStories(stories)).map((story) => [story.storyName || 'Story', story]);

test.each(testCases)(`renders %s without crashing`, async (_storyname, Story) => {
const tree = render(<Story />, { wrapper: appRoot.build(), legacyRoot: true });
const tree = render(<Story />, { wrapper: mockAppRoot().build(), legacyRoot: true });
expect(replaceReactAriaIds(tree.baseElement)).toMatchSnapshot();
});

test.each(testCases)('%s should have no a11y violations', async (_storyname, Story) => {
const { container } = render(<Story />, { wrapper: appRoot.build(), legacyRoot: true });
const { container } = render(<Story />, { wrapper: mockAppRoot().build(), legacyRoot: true });

const results = await axe(container);
expect(results).toHaveNoViolations();
Expand Down
Loading

0 comments on commit c2b92f4

Please sign in to comment.