Skip to content

Commit 33d7d66

Browse files
test: deprecate react-unit-test-utils 1/2 (#1750)
1 parent a75c89c commit 33d7d66

File tree

5 files changed

+92
-139
lines changed

5 files changed

+92
-139
lines changed

src/courseware/course/sequence/Unit/ContentIFrame.jsx

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
import PropTypes from 'prop-types';
2-
import React from 'react';
32

43
import { ErrorPage } from '@edx/frontend-platform/react';
5-
import { StrictDict } from '@edx/react-unit-test-utils';
64
import { ModalDialog } from '@openedx/paragon';
75
import { ContentIFrameLoaderSlot } from '../../../../plugin-slots/ContentIFrameLoaderSlot';
86

@@ -22,10 +20,10 @@ export const IFRAME_FEATURE_POLICY = (
2220
'microphone *; camera *; midi *; geolocation *; encrypted-media *; clipboard-write *; autoplay *'
2321
);
2422

25-
export const testIDs = StrictDict({
23+
export const testIDs = {
2624
contentIFrame: 'content-iframe-test-id',
2725
modalIFrame: 'modal-iframe-test-id',
28-
});
26+
};
2927

3028
const ContentIFrame = ({
3129
iframeUrl,

src/courseware/course/sequence/Unit/ContentIFrame.test.jsx

Lines changed: 58 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,11 @@
1-
import React from 'react';
1+
import { render, screen } from '@testing-library/react';
22

3-
import { ErrorPage } from '@edx/frontend-platform/react';
4-
import { ModalDialog } from '@openedx/paragon';
5-
import { shallow } from '@edx/react-unit-test-utils';
6-
7-
import PageLoading from '@src/generic/PageLoading';
8-
9-
import { ContentIFrameLoaderSlot } from '@src/plugin-slots/ContentIFrameLoaderSlot';
103
import * as hooks from './hooks';
11-
import ContentIFrame, { IFRAME_FEATURE_POLICY, testIDs } from './ContentIFrame';
4+
import ContentIFrame, { IFRAME_FEATURE_POLICY } from './ContentIFrame';
125

13-
jest.mock('@edx/frontend-platform/react', () => ({ ErrorPage: 'ErrorPage' }));
6+
jest.mock('@edx/frontend-platform/react', () => ({ ErrorPage: () => <div>ErrorPage</div> }));
147

15-
jest.mock('@openedx/paragon', () => jest.requireActual('@edx/react-unit-test-utils')
16-
.mockComponents({
17-
ModalDialog: {
18-
Body: 'ModalDialog.Body',
19-
},
20-
}));
21-
22-
jest.mock('@src/generic/PageLoading', () => 'PageLoading');
8+
jest.mock('@src/generic/PageLoading', () => jest.fn(() => <div>PageLoading</div>));
239

2410
jest.mock('./hooks', () => ({
2511
useIFrameBehavior: jest.fn(),
@@ -67,14 +53,13 @@ const props = {
6753
title: 'test-title',
6854
};
6955

70-
let el;
7156
describe('ContentIFrame Component', () => {
7257
beforeEach(() => {
7358
jest.clearAllMocks();
7459
});
7560
describe('behavior', () => {
7661
beforeEach(() => {
77-
el = shallow(<ContentIFrame {...props} />);
62+
render(<ContentIFrame {...props} />);
7863
});
7964
it('initializes iframe behavior hook', () => {
8065
expect(hooks.useIFrameBehavior).toHaveBeenCalledWith({
@@ -89,61 +74,61 @@ describe('ContentIFrame Component', () => {
8974
});
9075
});
9176
describe('output', () => {
92-
let component;
9377
describe('if shouldShowContent', () => {
9478
describe('if not hasLoaded', () => {
9579
it('displays errorPage if showError', () => {
9680
hooks.useIFrameBehavior.mockReturnValueOnce({ ...iframeBehavior, showError: true });
97-
el = shallow(<ContentIFrame {...props} />);
98-
expect(el.instance.findByType(ErrorPage).length).toEqual(1);
81+
render(<ContentIFrame {...props} />);
82+
const errorPage = screen.getByText('ErrorPage');
83+
expect(errorPage).toBeInTheDocument();
9984
});
10085
it('displays PageLoading component if not showError', () => {
101-
el = shallow(<ContentIFrame {...props} />);
102-
[component] = el.instance.findByType(ContentIFrameLoaderSlot);
103-
expect(component.props.loadingMessage).toEqual(props.loadingMessage);
86+
render(<ContentIFrame {...props} />);
87+
const pageLoading = screen.getByText('PageLoading');
88+
expect(pageLoading).toBeInTheDocument();
10489
});
10590
});
10691
describe('hasLoaded', () => {
10792
it('does not display PageLoading or ErrorPage', () => {
10893
hooks.useIFrameBehavior.mockReturnValueOnce({ ...iframeBehavior, hasLoaded: true });
109-
el = shallow(<ContentIFrame {...props} />);
110-
expect(el.instance.findByType(PageLoading).length).toEqual(0);
111-
expect(el.instance.findByType(ErrorPage).length).toEqual(0);
94+
render(<ContentIFrame {...props} />);
95+
const pageLoading = screen.queryByText('PageLoading');
96+
expect(pageLoading).toBeNull();
97+
const errorPage = screen.queryByText('ErrorPage');
98+
expect(errorPage).toBeNull();
11299
});
113100
});
114101
it('display iframe with props from hooks', () => {
115-
el = shallow(<ContentIFrame {...props} />);
116-
[component] = el.instance.findByTestId(testIDs.contentIFrame);
117-
expect(component.props).toEqual({
118-
allow: IFRAME_FEATURE_POLICY,
119-
allowFullScreen: true,
120-
scrolling: 'no',
121-
referrerPolicy: 'origin',
122-
title: props.title,
123-
id: props.elementId,
124-
src: props.iframeUrl,
125-
height: iframeBehavior.iframeHeight,
126-
onLoad: iframeBehavior.handleIFrameLoad,
127-
'data-testid': testIDs.contentIFrame,
128-
});
102+
render(<ContentIFrame {...props} />);
103+
const iframe = screen.getByTitle(props.title);
104+
expect(iframe).toBeInTheDocument();
105+
expect(iframe).toHaveAttribute('id', props.elementId);
106+
expect(iframe).toHaveAttribute('src', props.iframeUrl);
107+
expect(iframe).toHaveAttribute('allow', IFRAME_FEATURE_POLICY);
108+
expect(iframe).toHaveAttribute('allowfullscreen', '');
109+
expect(iframe).toHaveAttribute('scrolling', 'no');
110+
expect(iframe).toHaveAttribute('referrerpolicy', 'origin');
129111
});
130112
});
131113
describe('if not shouldShowContent', () => {
132114
it('does not show PageLoading, ErrorPage, or unit-iframe-wrapper', () => {
133-
el = shallow(<ContentIFrame {...{ ...props, shouldShowContent: false }} />);
134-
expect(el.instance.findByType(PageLoading).length).toEqual(0);
135-
expect(el.instance.findByType(ErrorPage).length).toEqual(0);
136-
expect(el.instance.findByTestId(testIDs.contentIFrame).length).toEqual(0);
115+
render(<ContentIFrame {...{ ...props, shouldShowContent: false }} />);
116+
expect(screen.queryByText('PageLoading')).toBeNull();
117+
expect(screen.queryByText('ErrorPage')).toBeNull();
118+
expect(screen.queryByTitle(props.title)).toBeNull();
137119
});
138120
});
139121
it('does not display modal if modalOptions returns isOpen: false', () => {
140-
el = shallow(<ContentIFrame {...props} />);
141-
expect(el.instance.findByType(ModalDialog).length).toEqual(0);
122+
render(<ContentIFrame {...props} />);
123+
const modal = screen.queryByRole('dialog');
124+
expect(modal).toBeNull();
142125
});
143126
describe('if modalOptions.isOpen', () => {
144127
const testModalOpenAndHandleClose = () => {
145-
test('Modal component isOpen, with handleModalClose from hook', () => {
146-
expect(component.props.onClose).toEqual(modalIFrameData.handleModalClose);
128+
it('closes modal on close button click', () => {
129+
const closeButton = screen.getByTestId('modal-backdrop');
130+
closeButton.click();
131+
expect(modalIFrameData.handleModalClose).toHaveBeenCalled();
147132
});
148133
};
149134
describe('fullscreen modal', () => {
@@ -153,14 +138,13 @@ describe('ContentIFrame Component', () => {
153138
...modalIFrameData,
154139
modalOptions: { ...modalOptions.withBody, isFullscreen: true },
155140
});
156-
el = shallow(<ContentIFrame {...props} />);
157-
[component] = el.instance.findByType(ModalDialog);
141+
render(<ContentIFrame {...props} />);
158142
});
159143
it('displays Modal with div wrapping provided body content if modal.body is provided', () => {
160-
const content = component.findByType(ModalDialog.Body)[0].children[0];
161-
expect(content.matches(shallow(
162-
<div className="unit-modal">{modalOptions.withBody.body}</div>,
163-
))).toEqual(true);
144+
const dialog = screen.getByRole('dialog');
145+
expect(dialog).toBeInTheDocument();
146+
const modalBody = screen.getByText(modalOptions.withBody.body);
147+
expect(modalBody).toBeInTheDocument();
164148
});
165149
testModalOpenAndHandleClose();
166150
});
@@ -171,55 +155,42 @@ describe('ContentIFrame Component', () => {
171155
...modalIFrameData,
172156
modalOptions: { ...modalOptions.withUrl, isFullscreen: true },
173157
});
174-
el = shallow(<ContentIFrame {...props} />);
175-
[component] = el.instance.findByType(ModalDialog);
158+
render(<ContentIFrame {...props} />);
176159
});
177-
testModalOpenAndHandleClose();
178160
it('displays Modal with iframe to provided url if modal.body is not provided', () => {
179-
const content = component.findByType(ModalDialog.Body)[0].children[0];
180-
expect(content.matches(shallow(
181-
<iframe
182-
title={modalOptions.withUrl.title}
183-
allow={IFRAME_FEATURE_POLICY}
184-
frameBorder="0"
185-
src={modalOptions.withUrl.url}
186-
style={{ width: '100%', height: modalOptions.withUrl.height }}
187-
/>,
188-
))).toEqual(true);
161+
const iframe = screen.getByTitle(modalOptions.withUrl.title);
162+
expect(iframe).toBeInTheDocument();
163+
expect(iframe).toHaveAttribute('allow', IFRAME_FEATURE_POLICY);
164+
expect(iframe).toHaveAttribute('src', modalOptions.withUrl.url);
189165
});
166+
testModalOpenAndHandleClose();
190167
});
191168
});
192169
describe('body modal', () => {
193170
beforeEach(() => {
194171
hooks.useModalIFrameData.mockReturnValueOnce({ ...modalIFrameData, modalOptions: modalOptions.withBody });
195-
el = shallow(<ContentIFrame {...props} />);
196-
[component] = el.instance.findByType(ModalDialog);
172+
render(<ContentIFrame {...props} />);
197173
});
198174
it('displays Modal with div wrapping provided body content if modal.body is provided', () => {
199-
const content = component.findByType(ModalDialog.Body)[0].children[0];
200-
expect(content.matches(shallow(<div className="unit-modal">{modalOptions.withBody.body}</div>))).toEqual(true);
175+
const dialog = screen.getByRole('dialog');
176+
expect(dialog).toBeInTheDocument();
177+
const modalBody = screen.getByText(modalOptions.withBody.body);
178+
expect(modalBody).toBeInTheDocument();
201179
});
202180
testModalOpenAndHandleClose();
203181
});
204182
describe('url modal', () => {
205183
beforeEach(() => {
206184
hooks.useModalIFrameData.mockReturnValueOnce({ ...modalIFrameData, modalOptions: modalOptions.withUrl });
207-
el = shallow(<ContentIFrame {...props} />);
208-
[component] = el.instance.findByType(ModalDialog);
185+
render(<ContentIFrame {...props} />);
209186
});
210-
testModalOpenAndHandleClose();
211187
it('displays Modal with iframe to provided url if modal.body is not provided', () => {
212-
const content = component.findByType(ModalDialog.Body)[0].children[0];
213-
expect(content.matches(shallow(
214-
<iframe
215-
title={modalOptions.withUrl.title}
216-
allow={IFRAME_FEATURE_POLICY}
217-
frameBorder="0"
218-
src={modalOptions.withUrl.url}
219-
style={{ width: '100%', height: modalOptions.withUrl.height }}
220-
/>,
221-
))).toEqual(true);
188+
const iframe = screen.getByTitle(modalOptions.withUrl.title);
189+
expect(iframe).toBeInTheDocument();
190+
expect(iframe).toHaveAttribute('allow', IFRAME_FEATURE_POLICY);
191+
expect(iframe).toHaveAttribute('src', modalOptions.withUrl.url);
222192
});
193+
testModalOpenAndHandleClose();
223194
});
224195
});
225196
});

src/courseware/course/sequence/Unit/UnitSuspense.test.jsx

Lines changed: 23 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,25 @@
1-
import React from 'react';
2-
3-
import { formatMessage, shallow } from '@edx/react-unit-test-utils';
1+
import { render, screen } from '@testing-library/react';
2+
import { IntlProvider } from '@edx/frontend-platform/i18n';
43

54
import { useModel } from '@src/generic/model-store';
6-
import PageLoading from '@src/generic/PageLoading';
7-
8-
import { GatedUnitContentMessageSlot } from '@src/plugin-slots/GatedUnitContentMessageSlot';
9-
import messages from '../messages';
10-
import HonorCode from '../honor-code';
11-
import LockPaywall from '../lock-paywall';
125
import hooks from './hooks';
136
import { modelKeys } from './constants';
147

158
import UnitSuspense from './UnitSuspense';
169

1710
jest.mock('@edx/frontend-platform/i18n', () => ({
11+
...jest.requireActual('@edx/frontend-platform/i18n'),
1812
defineMessages: m => m,
19-
useIntl: () => ({ formatMessage: jest.requireActual('@edx/react-unit-test-utils').formatMessage }),
2013
}));
2114

2215
jest.mock('react', () => ({
2316
...jest.requireActual('react'),
2417
Suspense: 'Suspense',
2518
}));
2619

27-
jest.mock('../honor-code', () => 'HonorCode');
28-
jest.mock('../lock-paywall', () => 'LockPaywall');
20+
jest.mock('../honor-code', () => jest.fn(() => <div>HonorCode</div>));
21+
jest.mock('../lock-paywall', () => jest.fn(() => <div>LockPaywall</div>));
2922
jest.mock('@src/generic/model-store', () => ({ useModel: jest.fn() }));
30-
jest.mock('@src/generic/PageLoading', () => 'PageLoading');
3123

3224
jest.mock('./hooks', () => ({
3325
useShouldDisplayHonorCode: jest.fn(() => false),
@@ -46,15 +38,14 @@ const props = {
4638
id: 'test-id',
4739
};
4840

49-
let el;
5041
describe('UnitSuspense component', () => {
5142
beforeEach(() => {
5243
jest.clearAllMocks();
5344
mockModels(false, false);
5445
});
5546
describe('behavior', () => {
5647
it('initializes models', () => {
57-
el = shallow(<UnitSuspense {...props} />);
48+
render(<IntlProvider locale="en"><UnitSuspense {...props} /></IntlProvider>);
5849
const { calls } = useModel.mock;
5950
const [unitCall] = calls.filter(call => call[0] === modelKeys.units);
6051
const [metaCall] = calls.filter(call => call[0] === modelKeys.coursewareMeta);
@@ -66,8 +57,9 @@ describe('UnitSuspense component', () => {
6657
describe('LockPaywall', () => {
6758
const testNoPaywall = () => {
6859
it('does not display LockPaywall', () => {
69-
el = shallow(<UnitSuspense {...props} />);
70-
expect(el.instance.findByType(LockPaywall).length).toEqual(0);
60+
render(<IntlProvider locale="en"><UnitSuspense {...props} /></IntlProvider>);
61+
const lockPaywall = screen.queryByText('LockPaywall');
62+
expect(lockPaywall).toBeNull();
7163
});
7264
};
7365
describe('gating not enabled', () => { testNoPaywall(); });
@@ -78,29 +70,29 @@ describe('UnitSuspense component', () => {
7870
describe('gating enabled, gated content included', () => {
7971
beforeEach(() => { mockModels(true, true); });
8072
it('displays LockPaywall in Suspense wrapper with PageLoading fallback', () => {
81-
el = shallow(<UnitSuspense {...props} />);
82-
const [component] = el.instance.findByType(GatedUnitContentMessageSlot);
83-
expect(component.parent.type).toEqual('Suspense');
84-
expect(component.parent.props.fallback)
85-
.toEqual(<PageLoading srMessage={formatMessage(messages.loadingLockedContent)} />);
86-
expect(component.props.courseId).toEqual(props.courseId);
73+
hooks.useShouldDisplayHonorCode.mockReturnValueOnce(false);
74+
render(<IntlProvider locale="en"><UnitSuspense {...props} /></IntlProvider>);
75+
const lockPaywall = screen.getByText('LockPaywall');
76+
expect(lockPaywall).toBeInTheDocument();
77+
const suspenseWrapper = lockPaywall.closest('suspense');
78+
expect(suspenseWrapper).toBeInTheDocument();
8779
});
8880
});
8981
});
9082
describe('HonorCode', () => {
9183
it('does not display HonorCode if useShouldDisplayHonorCode => false', () => {
9284
hooks.useShouldDisplayHonorCode.mockReturnValueOnce(false);
93-
el = shallow(<UnitSuspense {...props} />);
94-
expect(el.instance.findByType(HonorCode).length).toEqual(0);
85+
render(<IntlProvider locale="en"><UnitSuspense {...props} /></IntlProvider>);
86+
const honorCode = screen.queryByText('HonorCode');
87+
expect(honorCode).toBeNull();
9588
});
9689
it('displays HonorCode component in Suspense wrapper with PageLoading fallback if shouldDisplayHonorCode', () => {
9790
hooks.useShouldDisplayHonorCode.mockReturnValueOnce(true);
98-
el = shallow(<UnitSuspense {...props} />);
99-
const [component] = el.instance.findByType(HonorCode);
100-
expect(component.parent.type).toEqual('Suspense');
101-
expect(component.parent.props.fallback)
102-
.toEqual(<PageLoading srMessage={formatMessage(messages.loadingHonorCode)} />);
103-
expect(component.props.courseId).toEqual(props.courseId);
91+
render(<IntlProvider locale="en"><UnitSuspense {...props} /></IntlProvider>);
92+
const honorCode = screen.getByText('HonorCode');
93+
expect(honorCode).toBeInTheDocument();
94+
const suspenseWrapper = honorCode.closest('suspense');
95+
expect(suspenseWrapper).toBeInTheDocument();
10496
});
10597
});
10698
});

0 commit comments

Comments
 (0)