Skip to content

Commit 5074c81

Browse files
committed
test: deprecate react-unit-test-utils 10/14
1 parent 0c1be3a commit 5074c81

File tree

10 files changed

+237
-601
lines changed

10 files changed

+237
-601
lines changed

src/App.test.jsx

Lines changed: 44 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -1,117 +1,68 @@
11
import React from 'react';
2-
import { when } from 'jest-when';
3-
import { Route, Routes } from 'react-router-dom';
4-
5-
import { ErrorPage } from '@edx/frontend-platform/react';
6-
import { useIntl } from '@edx/frontend-platform/i18n';
7-
import { formatMessage, shallow } from '@edx/react-unit-test-utils';
8-
9-
import AssessmentView from 'views/AssessmentView';
10-
import SubmissionView from 'views/SubmissionView';
11-
import XBlockView from 'views/XBlockView';
12-
import XBlockStudioView from 'views/XBlockStudioView';
13-
import GradeView from 'views/GradeView';
14-
15-
import PageRoute from 'components/PageRoute';
2+
import { render, screen } from '@testing-library/react';
3+
import '@testing-library/jest-dom';
4+
import { IntlProvider } from '@edx/frontend-platform/i18n';
5+
import { MemoryRouter } from 'react-router-dom';
166

177
import { useHandleModalCloseEvent } from 'hooks/modal';
188

19-
import messages from './messages';
20-
import routes from './routes';
21-
229
import App from './App';
2310

24-
jest.mock('react-router-dom', () => ({
25-
Routes: 'Routes',
26-
Route: 'Route',
27-
}));
11+
/* eslint-disable react/prop-types */
2812

29-
jest.mock('@edx/frontend-platform/react', () => ({
30-
AuthenticatedPageRoute: 'AuthenticatedPageRoute',
31-
ErrorPage: 'ErrorPage',
32-
}));
33-
jest.mock('views/AssessmentView', () => 'AssessmentView');
34-
jest.mock('views/SubmissionView', () => 'SubmissionView');
35-
jest.mock('views/XBlockView', () => 'XBlockView');
36-
jest.mock('views/XBlockStudioView', () => 'XBlockStudioView');
37-
jest.mock('views/GradeView', () => 'GradeView');
38-
jest.mock('components/PageRoute', () => 'PageRoute');
13+
jest.unmock('@openedx/paragon');
14+
jest.unmock('react');
15+
jest.unmock('@edx/frontend-platform/i18n');
3916

4017
jest.mock('hooks/modal', () => ({
4118
useHandleModalCloseEvent: jest.fn(),
4219
}));
4320

21+
jest.mock('@edx/frontend-platform/react', () => ({
22+
ErrorPage: ({ message }) => <div role="alert">{message || 'Error Page'}</div>,
23+
}));
24+
4425
const handleModalClose = jest.fn();
45-
when(useHandleModalCloseEvent).calledWith().mockReturnValue(handleModalClose);
4626
const addEventListener = jest.fn();
4727
const removeEventListener = jest.fn();
4828

49-
let el;
5029
describe('App component', () => {
30+
const renderWithProviders = (component) => render(
31+
<MemoryRouter>
32+
<IntlProvider locale="en" messages={{}}>
33+
{component}
34+
</IntlProvider>
35+
</MemoryRouter>,
36+
);
37+
5138
beforeEach(() => {
5239
jest.clearAllMocks();
40+
useHandleModalCloseEvent.mockReturnValue(handleModalClose);
5341
jest.spyOn(window, 'addEventListener').mockImplementation(addEventListener);
54-
jest.spyOn(window, 'removeEventListener').mockImplementation(removeEventListener);
55-
el = shallow(<App />);
42+
jest
43+
.spyOn(window, 'removeEventListener')
44+
.mockImplementation(removeEventListener);
45+
});
46+
47+
it('renders app with accessible error page fallback', () => {
48+
renderWithProviders(<App />);
49+
50+
expect(screen.getByRole('alert')).toHaveTextContent('Page not found');
5651
});
57-
describe('behavior', () => {
58-
it('initializes i18n and refresh event from hooks', () => {
59-
expect(useIntl).toHaveBeenCalled();
60-
expect(useHandleModalCloseEvent).toHaveBeenCalled();
61-
});
62-
it('adds handler for modal close event that refreshes page data', () => {
63-
expect(React.useEffect.mock.calls.length).toEqual(1);
64-
const [[effect, prereqs]] = React.useEffect.mock.calls;
65-
expect(prereqs).toEqual([handleModalClose]);
66-
const out = effect();
67-
expect(addEventListener).toHaveBeenCalledWith('message', handleModalClose);
68-
out();
69-
expect(removeEventListener).toHaveBeenCalledWith('message', handleModalClose);
70-
});
52+
53+
it('calls useHandleModalCloseEvent hook and sets up event listeners', () => {
54+
renderWithProviders(<App />);
55+
expect(useHandleModalCloseEvent).toHaveBeenCalled();
56+
expect(addEventListener).toHaveBeenCalledWith('message', handleModalClose);
7157
});
72-
describe('render', () => {
73-
test('snapshot', () => {
74-
expect(el.snapshot).toMatchSnapshot();
75-
});
76-
const testComponent = (toTest, { route, Component, isModal }) => {
77-
expect(toTest.type).toEqual(Route);
78-
expect(toTest.props.path).toEqual(route);
79-
const { element } = toTest.props;
80-
expect(toTest.props.element.type).toEqual(PageRoute);
81-
if (isModal) {
82-
expect(toTest.props.element.props.isModal).toEqual(true);
83-
}
84-
const expectedElement = shallow(<PageRoute><Component /></PageRoute>);
85-
expect(shallow(element)).toMatchObject(expectedElement);
86-
};
87-
const testAssessmentRoute = (toTest, { route }) => {
88-
testComponent(toTest, { route, Component: AssessmentView, isModal: true });
89-
};
90-
test('route order', () => {
91-
const renderedRoutes = el.instance.findByType(Routes)[0].children;
92-
testComponent(renderedRoutes[0], { route: routes.xblock, Component: XBlockView });
93-
testComponent(renderedRoutes[1], { route: routes.xblockStudio, Component: XBlockStudioView });
94-
testComponent(renderedRoutes[2], { route: routes.xblockPreview, Component: XBlockView });
95-
testAssessmentRoute(renderedRoutes[3], { route: routes.peerAssessment });
96-
testAssessmentRoute(renderedRoutes[4], { route: routes.selfAssessment });
97-
testAssessmentRoute(renderedRoutes[5], { route: routes.studentTraining });
98-
testComponent(renderedRoutes[6], {
99-
route: routes.submission,
100-
Component: SubmissionView,
101-
isModal: true,
102-
});
103-
testComponent(renderedRoutes[7], {
104-
route: routes.graded,
105-
Component: GradeView,
106-
isModal: true,
107-
});
108-
expect(renderedRoutes[8].matches(shallow(
109-
<Route
110-
key="error"
111-
path={routes.root}
112-
element={<ErrorPage message={formatMessage(messages.error404Message)} />}
113-
/>,
114-
)));
115-
});
58+
59+
it('removes event listener on unmount', () => {
60+
const { unmount } = renderWithProviders(<App />);
61+
62+
unmount();
63+
expect(removeEventListener).toHaveBeenCalledWith(
64+
'message',
65+
handleModalClose,
66+
);
11667
});
11768
});

src/__snapshots__/App.test.jsx.snap

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

src/components/Assessment/EditableAssessment/OverallFeedback/__snapshots__/index.test.jsx.snap

Lines changed: 0 additions & 31 deletions
This file was deleted.
Lines changed: 51 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,58 +1,83 @@
1-
import { shallow } from '@edx/react-unit-test-utils';
1+
import React from 'react';
2+
import { render, screen } from '@testing-library/react';
3+
import '@testing-library/jest-dom';
4+
import { IntlProvider } from '@edx/frontend-platform/i18n';
25

36
import { useOverallFeedbackPrompt, useOverallFeedbackFormFields } from 'hooks/assessment';
47
import { useViewStep } from 'hooks/routing';
58
import { stepNames } from 'constants/index';
69
import OverallFeedback from '.';
710

11+
jest.unmock('@openedx/paragon');
12+
jest.unmock('react');
13+
jest.unmock('@edx/frontend-platform/i18n');
14+
815
jest.mock('hooks/assessment', () => ({
916
useOverallFeedbackPrompt: jest.fn(),
1017
useOverallFeedbackFormFields: jest.fn(),
1118
}));
1219

13-
jest.mock('components/InfoPopover', () => 'InfoPopover');
20+
jest.mock('components/InfoPopover', () => ({
21+
__esModule: true,
22+
default: ({ children }) => (
23+
<div role="button" aria-label="Help information">
24+
{children}
25+
</div>
26+
),
27+
}));
1428

1529
jest.mock('hooks/routing', () => ({
16-
useViewStep: jest.fn().mockReturnValue('step'),
30+
useViewStep: jest.fn(),
1731
}));
1832

33+
const messages = {
34+
'frontend-app-ora.EditableAssessment.overallComments': 'Overall comments',
35+
'frontend-app-ora.EditableAssessment.addComments': 'Add comments (Optional)',
36+
};
37+
1938
describe('<OverallFeedback />', () => {
20-
const mockOnChange = jest
21-
.fn()
22-
.mockName('useOverallFeedbackFormFields.onChange');
23-
const mockFeedbackValue = 'useOverallFeedbackFormFields.value';
24-
const mockPrompt = 'useOverallFeedbackPrompt';
39+
const renderWithIntl = (component) => render(
40+
<IntlProvider locale="en" messages={messages}>
41+
{component}
42+
</IntlProvider>,
43+
);
44+
45+
const mockOnChange = jest.fn();
46+
const mockFeedbackValue = 'Test feedback content';
47+
const mockPrompt = 'Please provide overall feedback';
2548

26-
beforeAll(() => {
49+
beforeEach(() => {
50+
jest.clearAllMocks();
2751
useOverallFeedbackPrompt.mockReturnValue(mockPrompt);
2852
useOverallFeedbackFormFields.mockReturnValue({
2953
value: mockFeedbackValue,
3054
onChange: mockOnChange,
3155
});
56+
useViewStep.mockReturnValue('assessment');
3257
});
3358

34-
it('render default', () => {
35-
const wrapper = shallow(<OverallFeedback />);
36-
expect(wrapper.snapshot).toMatchSnapshot();
59+
it('renders overall feedback form with prompt and textarea', () => {
60+
renderWithIntl(<OverallFeedback />);
61+
62+
expect(screen.getByText('Overall comments')).toBeInTheDocument();
63+
expect(screen.getByText('Please provide overall feedback')).toBeInTheDocument();
64+
expect(screen.getByRole('textbox')).toBeInTheDocument();
65+
expect(screen.getByRole('button', { name: 'Help information' })).toBeInTheDocument();
3766
});
3867

39-
it('render empty on studentTraining', () => {
40-
useViewStep.mockReturnValueOnce(stepNames.studentTraining);
41-
const wrapper = shallow(<OverallFeedback />);
42-
expect(wrapper.snapshot).toMatchSnapshot();
68+
it('renders nothing when step is studentTraining', () => {
69+
useViewStep.mockReturnValue(stepNames.studentTraining);
4370

44-
expect(wrapper.isEmptyRender()).toBe(true);
45-
});
71+
const { container } = renderWithIntl(<OverallFeedback />);
4672

47-
it('has correct mock value', () => {
48-
const wrapper = shallow(<OverallFeedback />);
73+
expect(container.firstChild).toBeNull();
74+
});
4975

50-
expect(wrapper.instance.findByTestId('prompt-test-id')[0].children[0].el).toBe(
51-
mockPrompt,
52-
);
76+
it('displays correct form field values from hooks', () => {
77+
renderWithIntl(<OverallFeedback />);
5378

54-
const { props } = wrapper.instance.findByType('Form.Control')[0];
55-
expect(props.value).toBe(mockFeedbackValue);
56-
expect(props.onChange).toBe(mockOnChange);
79+
const textarea = screen.getByRole('textbox');
80+
expect(textarea).toHaveValue(mockFeedbackValue);
81+
expect(screen.getByText('Please provide overall feedback')).toBeInTheDocument();
5782
});
5883
});

0 commit comments

Comments
 (0)