Skip to content

Commit b0daefa

Browse files
test: Deprecate react-unit-test-utils 2/15 (#643)
1 parent 42a2118 commit b0daefa

File tree

11 files changed

+178
-282
lines changed

11 files changed

+178
-282
lines changed
Lines changed: 24 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import { shallow } from '@edx/react-unit-test-utils';
1+
import { render, screen } from '@testing-library/react';
2+
import userEvent from '@testing-library/user-event';
23

34
import { reduxHooks } from 'hooks';
45
import useActionDisabledState from '../hooks';
@@ -7,28 +8,36 @@ import SelectSessionButton from './SelectSessionButton';
78

89
jest.mock('hooks', () => ({
910
reduxHooks: {
10-
useUpdateSelectSessionModalCallback: () => jest.fn().mockName('mockOpenSessionModal'),
11+
useUpdateSelectSessionModalCallback: jest.fn(),
1112
},
1213
}));
1314
jest.mock('../hooks', () => jest.fn(() => ({ disableSelectSession: false })));
14-
jest.mock('./ActionButton', () => 'ActionButton');
1515

16-
let wrapper;
16+
jest.unmock('@openedx/paragon');
17+
jest.mock('./ActionButton/hooks', () => jest.fn(() => false));
1718

1819
describe('SelectSessionButton', () => {
1920
const props = { cardId: 'cardId' };
2021
it('default render', () => {
21-
wrapper = shallow(<SelectSessionButton {...props} />);
22-
expect(wrapper.snapshot).toMatchSnapshot();
23-
expect(wrapper.instance.props.disabled).toEqual(false);
24-
expect(wrapper.instance.props.onClick.getMockName()).toEqual(
25-
reduxHooks.useUpdateSelectSessionModalCallback().getMockName(),
26-
);
22+
render(<SelectSessionButton {...props} />);
23+
const button = screen.getByRole('button', { name: 'Select Session' });
24+
expect(button).toBeInTheDocument();
2725
});
28-
test('disabled states', () => {
29-
useActionDisabledState.mockReturnValueOnce({ disableSelectSession: true });
30-
wrapper = shallow(<SelectSessionButton {...props} />);
31-
expect(wrapper.snapshot).toMatchSnapshot();
32-
expect(wrapper.instance.props.disabled).toEqual(true);
26+
describe('if useActionDisabledState is false', () => {
27+
it('should disabled Select Session', () => {
28+
useActionDisabledState.mockReturnValueOnce({ disableSelectSession: true });
29+
render(<SelectSessionButton {...props} />);
30+
const button = screen.getByRole('button', { name: 'Select Session' });
31+
expect(button).toBeDisabled();
32+
});
33+
});
34+
describe('on click', () => {
35+
it('should call openSessionModal', async () => {
36+
render(<SelectSessionButton {...props} />);
37+
const user = userEvent.setup();
38+
const button = screen.getByRole('button', { name: 'Select Session' });
39+
await user.click(button);
40+
expect(reduxHooks.useUpdateSelectSessionModalCallback).toHaveBeenCalledWith(props.cardId);
41+
});
3342
});
3443
});
Lines changed: 25 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import { shallow } from '@edx/react-unit-test-utils';
1+
import { render, screen } from '@testing-library/react';
2+
import userEvent from '@testing-library/user-event';
23

34
import track from 'tracking';
45
import { reduxHooks } from 'hooks';
@@ -14,32 +15,41 @@ jest.mock('tracking', () => ({
1415
jest.mock('hooks', () => ({
1516
reduxHooks: {
1617
useCardCourseRunData: jest.fn(() => ({ homeUrl: 'homeUrl' })),
17-
useTrackCourseEvent: jest.fn(
18-
(eventName, cardId, url) => ({ trackCourseEvent: { eventName, cardId, url } }),
19-
),
18+
useTrackCourseEvent: jest.fn(),
2019
},
2120
}));
2221
jest.mock('../hooks', () => jest.fn(() => ({ disableViewCourse: false })));
23-
jest.mock('./ActionButton', () => 'ActionButton');
22+
23+
jest.unmock('@openedx/paragon');
24+
jest.mock('./ActionButton/hooks', () => jest.fn(() => false));
2425

2526
const defaultProps = { cardId: 'cardId' };
2627
const homeUrl = 'homeUrl';
2728

2829
describe('ViewCourseButton', () => {
29-
test('learner can view course', () => {
30-
const wrapper = shallow(<ViewCourseButton {...defaultProps} />);
31-
expect(wrapper.snapshot).toMatchSnapshot();
32-
expect(wrapper.instance.props.onClick).toEqual(reduxHooks.useTrackCourseEvent(
30+
it('learner can view course', async () => {
31+
render(<ViewCourseButton {...defaultProps} />);
32+
const button = screen.getByRole('button', { name: 'View Course' });
33+
expect(button).toBeInTheDocument();
34+
expect(button).not.toHaveClass('disabled');
35+
expect(button).not.toHaveAttribute('aria-disabled', 'true');
36+
});
37+
it('calls trackCourseEvent on click', async () => {
38+
render(<ViewCourseButton {...defaultProps} />);
39+
const user = userEvent.setup();
40+
const button = screen.getByRole('button', { name: 'View Course' });
41+
await user.click(button);
42+
expect(reduxHooks.useTrackCourseEvent).toHaveBeenCalledWith(
3343
track.course.enterCourseClicked,
3444
defaultProps.cardId,
3545
homeUrl,
36-
));
37-
expect(wrapper.instance.props.disabled).toEqual(false);
46+
);
3847
});
39-
test('learner cannot view course', () => {
48+
it('learner cannot view course', () => {
4049
useActionDisabledState.mockReturnValueOnce({ disableViewCourse: true });
41-
const wrapper = shallow(<ViewCourseButton {...defaultProps} />);
42-
expect(wrapper.snapshot).toMatchSnapshot();
43-
expect(wrapper.instance.props.disabled).toEqual(true);
50+
render(<ViewCourseButton {...defaultProps} />);
51+
const button = screen.getByRole('button', { name: 'View Course' });
52+
expect(button).toHaveClass('disabled');
53+
expect(button).toHaveAttribute('aria-disabled', 'true');
4454
});
4555
});

src/containers/CourseCard/components/CourseCardActions/__snapshots__/SelectSessionButton.test.jsx.snap

Lines changed: 0 additions & 19 deletions
This file was deleted.

src/containers/CourseCard/components/CourseCardActions/__snapshots__/ViewCourseButton.test.jsx.snap

Lines changed: 0 additions & 39 deletions
This file was deleted.

src/containers/CourseCard/components/CourseCardBanners/CreditBanner/views/ApprovedContent.test.jsx

Lines changed: 44 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
1-
import React from 'react';
2-
import { shallow } from '@edx/react-unit-test-utils';
3-
1+
import { render, screen } from '@testing-library/react';
2+
import { IntlProvider } from '@edx/frontend-platform/i18n';
43
import { formatMessage } from 'testUtils';
54
import { reduxHooks } from 'hooks';
65
import messages from './messages';
7-
import ProviderLink from './components/ProviderLink';
86
import ApprovedContent from './ApprovedContent';
97

108
jest.mock('hooks', () => ({
@@ -13,10 +11,11 @@ jest.mock('hooks', () => ({
1311
useMasqueradeData: jest.fn(),
1412
},
1513
}));
16-
jest.mock('./components/CreditContent', () => 'CreditContent');
17-
jest.mock('./components/ProviderLink', () => 'ProviderLink');
1814

19-
let el;
15+
jest.unmock('@openedx/paragon');
16+
jest.unmock('react');
17+
jest.unmock('@edx/frontend-platform/i18n');
18+
2019
const cardId = 'test-card-id';
2120
const credit = {
2221
providerStatusUrl: 'test-credit-provider-status-url',
@@ -26,38 +25,54 @@ reduxHooks.useCardCreditData.mockReturnValue(credit);
2625
reduxHooks.useMasqueradeData.mockReturnValue({ isMasquerading: false });
2726

2827
describe('ApprovedContent component', () => {
29-
beforeEach(() => {
30-
el = shallow(<ApprovedContent cardId={cardId} />);
31-
});
32-
describe('behavior', () => {
28+
describe('hooks', () => {
3329
it('initializes credit data with cardId', () => {
30+
render(<IntlProvider locale="en"><ApprovedContent cardId={cardId} /></IntlProvider>);
3431
expect(reduxHooks.useCardCreditData).toHaveBeenCalledWith(cardId);
3532
});
3633
});
3734
describe('render', () => {
3835
describe('rendered CreditContent component', () => {
39-
let component;
40-
beforeAll(() => {
41-
component = el.instance.findByType('CreditContent');
36+
beforeEach(() => {
37+
jest.clearAllMocks();
38+
render(<IntlProvider locale="en"><ApprovedContent cardId={cardId} /></IntlProvider>);
4239
});
43-
test('action.href from credit.providerStatusUrl', () => {
44-
expect(component[0].props.action.href).toEqual(credit.providerStatusUrl);
40+
it('action.message is formatted viewCredit message', () => {
41+
const actionButton = screen.getByRole('link', { name: messages.viewCredit.defaultMessage });
42+
expect(actionButton).toBeInTheDocument();
43+
expect(actionButton).toHaveTextContent(formatMessage(messages.viewCredit));
4544
});
46-
test('action.message is formatted viewCredit message', () => {
47-
expect(component[0].props.action.message).toEqual(formatMessage(messages.viewCredit));
45+
it('action.href from credit.providerStatusUrl', () => {
46+
const actionButton = screen.getByRole('link', { name: messages.viewCredit.defaultMessage });
47+
expect(actionButton).toHaveAttribute('href', credit.providerStatusUrl);
4848
});
49-
test('action.disabled is false', () => {
50-
expect(component[0].props.action.disabled).toEqual(false);
49+
it('action.disabled is false', () => {
50+
const actionButton = screen.getByRole('link', { name: messages.viewCredit.defaultMessage });
51+
expect(actionButton).not.toHaveAttribute('aria-disabled', 'true');
52+
expect(actionButton).not.toHaveClass('disabled');
53+
expect(actionButton).toBeEnabled();
5154
});
52-
test('message is formatted approved message', () => {
53-
expect(component[0].props.message).toEqual(formatMessage(
54-
messages.approved,
55-
{
56-
congratulations: (<b>{formatMessage(messages.congratulations)}</b>),
57-
linkToProviderSite: <ProviderLink cardId={cardId} />,
58-
providerName: credit.providerName,
59-
},
60-
));
55+
it('message is formatted approved message', () => {
56+
const creditMsg = screen.getByTestId('credit-msg');
57+
expect(creditMsg).toBeInTheDocument();
58+
expect(creditMsg.textContent).toContain(`${credit.providerName} has approved your request for course credit`);
59+
});
60+
});
61+
describe('when masquerading', () => {
62+
beforeEach(() => {
63+
reduxHooks.useMasqueradeData.mockReturnValue({ isMasquerading: true });
64+
render(<IntlProvider locale="en"><ApprovedContent cardId={cardId} /></IntlProvider>);
65+
});
66+
67+
it('disables the action button', () => {
68+
const actionButton = screen.getByRole('link', { name: messages.viewCredit.defaultMessage });
69+
expect(actionButton).toHaveAttribute('aria-disabled', 'true');
70+
expect(actionButton).toHaveClass('disabled');
71+
});
72+
73+
it('still renders provider name and link correctly', () => {
74+
const creditMsg = screen.getByTestId('credit-msg');
75+
expect(creditMsg.textContent).toContain(credit.providerName);
6176
});
6277
});
6378
});

src/containers/CourseCard/components/CourseCardBanners/CreditBanner/views/components/CreditContent.test.jsx

Lines changed: 41 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1-
import React from 'react';
2-
import { shallow } from '@edx/react-unit-test-utils';
1+
import { render, screen } from '@testing-library/react';
32

43
import CreditContent from './CreditContent';
54

6-
let el;
5+
jest.unmock('@openedx/paragon');
6+
jest.unmock('react');
7+
78
const action = {
89
href: 'test-action-href',
910
onClick: jest.fn().mockName('test-action-onClick'),
@@ -15,45 +16,57 @@ const message = 'test-message';
1516
const requestData = { url: 'test-request-data-url', parameters: { key1: 'val1' } };
1617
const props = { action, message, requestData };
1718

19+
const renderCreditContent = (data) => render(
20+
<CreditContent {...data} />,
21+
);
22+
1823
describe('CreditContent component', () => {
1924
describe('render', () => {
2025
describe('with action', () => {
21-
beforeEach(() => {
22-
el = shallow(<CreditContent {...props} />);
23-
});
24-
test('snapshot', () => {
25-
expect(el.snapshot).toMatchSnapshot();
26-
});
27-
it('loads href, onClick, and message into action row button', () => {
28-
const buttonEl = el.instance.findByTestId('action-row-btn')[0];
29-
expect(buttonEl.props.href).toEqual(action.href);
30-
expect(buttonEl.props.onClick).toEqual(action.onClick);
31-
expect(buttonEl.props.disabled).toEqual(action.disabled);
32-
expect(buttonEl.children[0].el).toEqual(action.message);
26+
it('loads href and message into action row button', () => {
27+
renderCreditContent(props);
28+
const button = screen.getByRole('link', { name: action.message });
29+
expect(button).toBeInTheDocument();
30+
expect(button).toHaveAttribute('href', action.href);
31+
expect(button).not.toHaveAttribute('disabled');
3332
});
3433
it('loads message into credit-msg div', () => {
35-
expect(el.instance.findByTestId('credit-msg')[0].children[0].el).toEqual(message);
34+
renderCreditContent(props);
35+
const creditMsg = screen.getByTestId('credit-msg');
36+
expect(creditMsg).toBeInTheDocument();
37+
expect(creditMsg.innerHTML).toEqual(message);
3638
});
3739
it('loads CreditRequestForm with passed requestData', () => {
38-
expect(el.instance.findByType('CreditRequestForm')[0].props.requestData).toEqual(requestData);
40+
const { container } = renderCreditContent(props);
41+
const creditForm = container.querySelector('form');
42+
expect(creditForm).toBeInTheDocument();
43+
expect(creditForm).toHaveAttribute('action', requestData.url);
3944
});
40-
test('disables action button when action.disabled is true', () => {
41-
el = shallow(<CreditContent {...props} action={{ ...action, disabled: true }} />);
42-
expect(el.instance.findByTestId('action-row-btn')[0].props.disabled).toEqual(true);
45+
it('disables action button when action.disabled is true', () => {
46+
renderCreditContent({ ...props, action: { ...action, disabled: true } });
47+
const button = screen.getByRole('link', { name: action.message });
48+
expect(button).toBeInTheDocument();
49+
expect(button).toHaveClass('disabled');
50+
expect(button).toHaveAttribute('aria-disabled', 'true');
4351
});
4452
});
4553
describe('without action', () => {
46-
test('snapshot', () => {
47-
el = shallow(<CreditContent {...{ message, requestData }} />);
48-
});
49-
test('snapshot', () => {
50-
expect(el.snapshot).toMatchSnapshot();
51-
});
5254
it('loads message into credit-msg div', () => {
53-
expect(el.instance.findByTestId('credit-msg')[0].children[0].el).toEqual(message);
55+
renderCreditContent({ message, requestData });
56+
const creditMsg = screen.getByTestId('credit-msg');
57+
expect(creditMsg).toBeInTheDocument();
58+
expect(creditMsg.innerHTML).toEqual(message);
5459
});
5560
it('loads CreditRequestForm with passed requestData', () => {
56-
expect(el.instance.findByType('CreditRequestForm')[0].props.requestData).toEqual(requestData);
61+
const { container } = renderCreditContent({ message, requestData });
62+
const creditForm = container.querySelector('form');
63+
expect(creditForm).toBeInTheDocument();
64+
expect(creditForm).toHaveAttribute('action', requestData.url);
65+
});
66+
it('does not render action row button', () => {
67+
renderCreditContent({ message, requestData });
68+
const button = screen.queryByRole('link', { name: action.message });
69+
expect(button).not.toBeInTheDocument();
5770
});
5871
});
5972
});

0 commit comments

Comments
 (0)