Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Frontend Tests: Standardize userEvent usage to conform with upstream recomendations #5872

Merged
merged 3 commits into from
Jun 22, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 8 additions & 5 deletions frontend/src/components/comments/tests/hashtagPaste.test.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import React from 'react';
import { render, screen, fireEvent } from '@testing-library/react';
import { render, screen } from '@testing-library/react';
import '@testing-library/jest-dom';

import { ReduxIntlProviders } from '../../../utils/testWithIntl';
import HashtagPaste from '../hashtagPaste';
import userEvent from '@testing-library/user-event';

test('HashtagPaste with an empty text string', () => {
test('HashtagPaste with an empty text string', async () => {
const setFn = jest.fn();
const user = userEvent.setup();
render(
<ReduxIntlProviders>
<HashtagPaste text="" setFn={setFn} hashtag="#managers" className="pt2 f6" />
Expand All @@ -15,19 +17,20 @@ test('HashtagPaste with an empty text string', () => {
expect(screen.getByText('#managers').className).toBe('bb pointer pt2 f6');
expect(screen.getByText('#managers').style.borderBottomStyle).toBe('dashed');
expect(screen.getByText('#managers').title).toBeTruthy();
fireEvent.click(screen.getByText('#managers'));
await user.click(screen.getByText('#managers'));
expect(setFn).toHaveBeenCalledWith('#managers ');
});

test('HashtagPaste with a text string', () => {
test('HashtagPaste with a text string', async () => {
const setFn = jest.fn();
const user = userEvent.setup();
render(
<ReduxIntlProviders>
<HashtagPaste text="My comment" setFn={setFn} hashtag="#managers" className="pt2 f6" />
</ReduxIntlProviders>,
);
expect(screen.getByText('#managers').className).toBe('bb pointer pt2 f6');
expect(screen.getByText('#managers').style.borderBottomStyle).toBe('dashed');
fireEvent.click(screen.getByText('#managers'));
await user.click(screen.getByText('#managers'));
expect(setFn).toHaveBeenCalledWith('My comment #managers');
});
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
import '@testing-library/jest-dom';
import { screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';

import MyTasksOrderDropdown from '../myTasksOrderDropdown';
import { IntlProviders, renderWithRouter } from '../../../utils/testWithIntl';

describe('MyTasksOrderDropdown', () => {
const setQueryMock = jest.fn();
const setup = async () => {
renderWithRouter(
const { user } = renderWithRouter(
<IntlProviders>
<MyTasksOrderDropdown
allQueryParams={{
Expand All @@ -27,7 +26,8 @@ describe('MyTasksOrderDropdown', () => {
const dropdownBtn = screen.getByRole('button', {
name: /sort by/i,
});
await userEvent.click(dropdownBtn);
await user.click(dropdownBtn);
return { user };
};

it('displays dropdown options after button is clicked', async () => {
Expand All @@ -37,8 +37,8 @@ describe('MyTasksOrderDropdown', () => {
});

it('should set query when an option is selected', async () => {
await setup();
await userEvent.click(screen.getByText(/recently edited/i));
const { user } = await setup();
await user.click(screen.getByText(/recently edited/i));
expect(setQueryMock).toHaveBeenCalled();
});

Expand Down
41 changes: 20 additions & 21 deletions frontend/src/components/contributions/tests/taskCard.test.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
import React from 'react';
import { screen, fireEvent } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { screen } from '@testing-library/react';
import '@testing-library/jest-dom';

import { ReduxIntlProviders, renderWithRouter } from '../../../utils/testWithIntl';
import { TaskCard } from '../taskCard';

describe('TaskCard', () => {
it('on MAPPED state with comments', () => {
const { container } = renderWithRouter(
it('on MAPPED state with comments', async () => {
const { user, container } = renderWithRouter(
<ReduxIntlProviders>
<TaskCard
taskId={987}
Expand All @@ -28,12 +27,12 @@ describe('TaskCard', () => {
expect(container.querySelectorAll('svg').length).toBe(2);
expect(screen.queryByText('Resume task')).not.toBeInTheDocument();
// hovering on the card should not change anything
userEvent.hover(screen.getByText('Ready for validation'));
await user.hover(screen.getByText('Ready for validation'));
expect(screen.queryByText('Resume task')).not.toBeInTheDocument();
});

it('on VALIDATED state without comments', () => {
const { container } = renderWithRouter(
it('on VALIDATED state without comments', async () => {
const { user, container } = renderWithRouter(
<ReduxIntlProviders>
<TaskCard
taskId={987}
Expand All @@ -51,12 +50,12 @@ describe('TaskCard', () => {
expect(screen.queryByText('0')).not.toBeInTheDocument();
expect(container.querySelectorAll('svg').length).toBe(1);
// hovering on the card should not change anything
userEvent.hover(screen.getByText('Finished'));
await user.hover(screen.getByText('Finished'));
expect(screen.queryByText('Resume task')).not.toBeInTheDocument();
});

it('on BADIMAGERY state', () => {
renderWithRouter(
it('on BADIMAGERY state', async () => {
const { user } = renderWithRouter(
<ReduxIntlProviders>
<TaskCard
taskId={987}
Expand All @@ -71,12 +70,12 @@ describe('TaskCard', () => {
expect(screen.getByText('Unavailable')).toBeInTheDocument();
expect(screen.queryByText('Resume task')).not.toBeInTheDocument();
// hovering on the card should not change anything
userEvent.hover(screen.getByText('Unavailable'));
await user.hover(screen.getByText('Unavailable'));
expect(screen.queryByText('Resume task')).not.toBeInTheDocument();
});

it('on LOCKED_FOR_VALIDATION state', () => {
const { container } = renderWithRouter(
it('on LOCKED_FOR_VALIDATION state', async () => {
const { user, container } = renderWithRouter(
<ReduxIntlProviders>
<TaskCard
taskId={987}
Expand All @@ -92,13 +91,13 @@ describe('TaskCard', () => {
expect(screen.getByText('Locked for validation by user_1')).toBeInTheDocument();
expect(screen.queryByText('Resume task')).not.toBeInTheDocument();
// hovering on the card should show the resume task button
fireEvent.mouseOver(screen.getByText('Locked for validation by user_1'));
await user.hover(screen.getByText('Locked for validation by user_1'));
expect(screen.getByText('Resume task')).toBeInTheDocument();
expect(container.querySelectorAll('a')[1].href).toContain('/projects/4321/tasks?search=987');
});

it('on INVALIDATED state', () => {
renderWithRouter(
it('on INVALIDATED state', async () => {
const { user } = renderWithRouter(
<ReduxIntlProviders>
<TaskCard
taskId={987}
Expand All @@ -112,12 +111,12 @@ describe('TaskCard', () => {
expect(screen.getByText('More mapping needed')).toBeInTheDocument();
expect(screen.queryByText('Resume task')).not.toBeInTheDocument();
// hovering on the card should show the resume task button
fireEvent.mouseOver(screen.getByText('More mapping needed'));
await user.hover(screen.getByText('More mapping needed'));
expect(screen.getByText('Resume task')).toBeInTheDocument();
});

it('on READY state', () => {
const { container } = renderWithRouter(
it('on READY state', async () => {
const { user, container } = renderWithRouter(
<ReduxIntlProviders>
<TaskCard
taskId={543}
Expand All @@ -134,14 +133,14 @@ describe('TaskCard', () => {
expect(screen.getByText('Available for mapping')).toBeInTheDocument();
expect(screen.queryByText('Resume task')).not.toBeInTheDocument();
// hover on the card
fireEvent.mouseOver(screen.getByText('Available for mapping'));
await user.hover(screen.getByText('Available for mapping'));
expect(screen.getByText('Resume task')).toBeInTheDocument();
expect(screen.getByText('Resume task').className).toBe(
'dn dib-l link pv2 ph3 mh3 mv1 bg-red white f7 fr',
);
expect(container.querySelectorAll('a')[1].href).toContain('/projects/9983/tasks?search=543');
// unhover
fireEvent.mouseOut(screen.getByText('Available for mapping'));
await user.unhover(screen.getByText('Available for mapping'));
expect(screen.queryByText('Resume task')).not.toBeInTheDocument();
});
});
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import '@testing-library/jest-dom';
import { screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';

import { IntlProviders, renderWithRouter } from '../../../utils/testWithIntl';
import { userTasks } from '../../../network/tests/mockData/tasksStats';
Expand All @@ -19,7 +18,7 @@ describe('Task Results Component', () => {

it('should prompt user to retry on failure to fetch tasks', async () => {
const retryFnMock = jest.fn();
renderWithRouter(
const { user } = renderWithRouter(
<IntlProviders>
<TaskResults state={{ isError: true, isLoading: false, tasks: [] }} retryFn={retryFnMock} />
</IntlProviders>,
Expand All @@ -29,7 +28,7 @@ describe('Task Results Component', () => {
name: messages.retry.defaultMessage,
});
expect(retryBtn).toBeInTheDocument();
await userEvent.click(retryBtn);
await user.click(retryBtn);
expect(retryFnMock).toHaveBeenCalled();
});

Expand Down
31 changes: 16 additions & 15 deletions frontend/src/components/deleteModal/tests/index.test.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React from 'react';
import { screen, fireEvent, waitFor, within } from '@testing-library/react';
import { screen, waitFor, within } from '@testing-library/react';
import '@testing-library/jest-dom';

import {
Expand All @@ -12,7 +12,7 @@ import { DeleteModal } from '../index';

describe('Delete Interest', () => {
const setup = () => {
const { history } = renderWithRouter(
const { user, history } = renderWithRouter(
<ReduxIntlProviders>
<DeleteModal id={interest.id} name={interest.name} type="interests" />
</ReduxIntlProviders>,
Expand All @@ -22,24 +22,25 @@ describe('Delete Interest', () => {
});

return {
user,
deleteButton,
history,
};
};

it('should ask for confirmation when user tries to delete an interest', () => {
const { deleteButton } = setup();
fireEvent.click(deleteButton);
it('should ask for confirmation when user tries to delete an interest', async () => {
const { user, deleteButton } = setup();
await user.click(deleteButton);
expect(screen.getByText('Are you sure you want to delete this category?')).toBeInTheDocument();
});

it('should close the confirmation popup when cancel is clicked', () => {
const { deleteButton } = setup();
fireEvent.click(deleteButton);
it('should close the confirmation popup when cancel is clicked', async () => {
const { user, deleteButton } = setup();
await user.click(deleteButton);
const cancelButton = screen.getByRole('button', {
name: /cancel/i,
});
fireEvent.click(cancelButton);
await user.click(cancelButton);
expect(
screen.queryByRole('heading', {
name: 'Are you sure you want to delete this category?',
Expand All @@ -48,7 +49,7 @@ describe('Delete Interest', () => {
});

it('should direct to passed type list page on successful deletion of an interest', async () => {
const { router } = createComponentWithMemoryRouter(
const { user, router } = createComponentWithMemoryRouter(
<ReduxIntlProviders>
<DeleteModal id={interest.id} name={interest.name} type="campaigns" />
</ReduxIntlProviders>,
Expand All @@ -58,20 +59,20 @@ describe('Delete Interest', () => {
name: 'Delete',
});

fireEvent.click(deleteButton);
await user.click(deleteButton);
const dialog = screen.getByRole('dialog');
const deleteConfirmationButton = within(dialog).getByRole('button', {
name: /delete/i,
});
fireEvent.click(deleteConfirmationButton);
await user.click(deleteConfirmationButton);
expect(
await screen.findByRole('heading', { name: /campaign deleted successfully./i }),
).toBeInTheDocument();
await waitFor(() => expect(router.state.location.pathname).toBe('/manage/campaigns'));
});

it('should direct to categories list page on successful deletion of an interest', async () => {
const { router } = createComponentWithMemoryRouter(
const { user, router } = createComponentWithMemoryRouter(
<ReduxIntlProviders>
<DeleteModal id={interest.id} name={interest.name} type="interests" />
</ReduxIntlProviders>,
Expand All @@ -81,12 +82,12 @@ describe('Delete Interest', () => {
name: 'Delete',
});

fireEvent.click(deleteButton);
await user.click(deleteButton);
const dialog = screen.getByRole('dialog');
const deleteConfirmationButton = within(dialog).getByRole('button', {
name: /delete/i,
});
fireEvent.click(deleteConfirmationButton);
await user.click(deleteConfirmationButton);
expect(
await screen.findByRole('heading', { name: /interest deleted successfully./i }),
).toBeInTheDocument();
Expand Down
13 changes: 8 additions & 5 deletions frontend/src/components/header/tests/authButtons.test.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import React from 'react';
import { render, screen, fireEvent } from '@testing-library/react';
import { render, screen } from '@testing-library/react';
import '@testing-library/jest-dom';

import { ReduxIntlProviders } from '../../../utils/testWithIntl';
import { AuthButtons } from '../index';
import userEvent from '@testing-library/user-event';

describe('AuthButtons', () => {
it('without alternativeSignUpText', () => {
it('without alternativeSignUpText', async () => {
const user = userEvent.setup();
render(
<ReduxIntlProviders>
<AuthButtons
Expand All @@ -20,12 +22,13 @@ describe('AuthButtons', () => {
expect(screen.getByText('Sign up').className).toContain('bg-blue-dark white ml1 v-mid');
expect(screen.queryByText('Create an account')).not.toBeInTheDocument();
expect(screen.queryByText('Name')).not.toBeInTheDocument();
fireEvent.click(screen.getByText('Sign up'));
await user.click(screen.getByText('Sign up'));
expect(screen.getByText('Name')).toBeInTheDocument();
expect(screen.getByText('Email')).toBeInTheDocument();
expect(screen.getByText('Next')).toBeInTheDocument();
});
it('with alternativeSignUpText', () => {
it('with alternativeSignUpText', async () => {
const user = userEvent.setup();
render(
<ReduxIntlProviders>
<AuthButtons
Expand All @@ -40,7 +43,7 @@ describe('AuthButtons', () => {
expect(screen.getByText('Create an account').className).toContain('bg-orange black ml1 v-mid');
expect(screen.queryByText('Sign up')).not.toBeInTheDocument();
expect(screen.queryByText('Name')).not.toBeInTheDocument();
fireEvent.click(screen.getByText('Create an account'));
await user.click(screen.getByText('Create an account'));
expect(screen.getByText('Name')).toBeInTheDocument();
expect(screen.getByText('Email')).toBeInTheDocument();
expect(screen.getByText('Next')).toBeInTheDocument();
Expand Down
Loading
Loading