Skip to content

Commit e13f0d2

Browse files
authored
test: deprecate react-unit-test-utils 1/14 (#336)
1 parent 4b2ea07 commit e13f0d2

File tree

10 files changed

+254
-332
lines changed

10 files changed

+254
-332
lines changed

src/components/ActionButton.test.jsx

Lines changed: 26 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,40 @@
1-
import { shallow } from '@edx/react-unit-test-utils';
1+
import { render, screen } from '@testing-library/react';
2+
import '@testing-library/jest-dom';
23

34
import ActionButton from './ActionButton';
45

6+
jest.unmock('@openedx/paragon');
7+
jest.unmock('react');
8+
jest.unmock('@edx/frontend-platform/i18n');
9+
510
describe('<ActionButton />', () => {
611
const props = {
712
state: 'arbitraryState',
813
};
914

10-
it('render empty when no onClick or href', () => {
11-
const wrapper = shallow(<ActionButton {...props} />);
12-
expect(wrapper.isEmptyRender()).toBe(true);
15+
it('renders nothing when no onClick or href is provided', () => {
16+
const { container } = render(<ActionButton {...props} />);
17+
expect(container.firstChild).toBeNull();
1318
});
1419

15-
it('render StatefulButton when state is provided', () => {
16-
const wrapper = shallow(<ActionButton href="some-href" state="loading" />);
17-
expect(wrapper.snapshot).toMatchSnapshot();
18-
expect(wrapper.instance.findByType('StatefulButton')).toHaveLength(1);
19-
expect(wrapper.instance.findByType('Button')).toHaveLength(0);
20+
it('renders StatefulButton when state is provided', () => {
21+
const labels = {
22+
default: 'Default',
23+
loading: 'Loading...',
24+
};
25+
render(
26+
<ActionButton href="some-href" state="loading" labels={labels}>
27+
Button Text
28+
</ActionButton>,
29+
);
30+
expect(screen.getByRole('link')).toBeInTheDocument();
31+
expect(screen.getByRole('link')).toHaveClass('btn');
2032
});
2133

22-
it('render Button when state is not provided', () => {
23-
const wrapper = shallow(<ActionButton onClick={jest.fn().mockName('onClick')} />);
24-
expect(wrapper.snapshot).toMatchSnapshot();
25-
expect(wrapper.instance.findByType('StatefulButton')).toHaveLength(0);
26-
expect(wrapper.instance.findByType('Button')).toHaveLength(1);
34+
it('renders Button when state is not provided', () => {
35+
const onClick = jest.fn();
36+
render(<ActionButton onClick={onClick}>Button Text</ActionButton>);
37+
expect(screen.getByRole('button')).toBeInTheDocument();
38+
expect(screen.getByRole('button')).toHaveClass('btn');
2739
});
2840
});

src/components/ConfirmDialog/__snapshots__/index.test.jsx.snap

Lines changed: 0 additions & 27 deletions
This file was deleted.
Lines changed: 46 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,57 @@
1-
import { shallow } from '@edx/react-unit-test-utils';
1+
import { render, screen } from '@testing-library/react';
2+
import '@testing-library/jest-dom';
3+
import userEvent from '@testing-library/user-event';
4+
import { IntlProvider } from '@edx/frontend-platform/i18n';
25

36
import ConfirmDialog from './index';
47

8+
jest.unmock('@openedx/paragon');
9+
jest.unmock('react');
10+
jest.unmock('@edx/frontend-platform/i18n');
11+
512
describe('<ConfirmDialog />', () => {
613
const props = {
7-
title: 'Title',
8-
description: 'Description',
14+
title: 'Test Title',
15+
description: 'Test Description',
916
action: {
10-
onClick: jest.fn().mockName('onClick'),
17+
onClick: jest.fn(),
1118
},
1219
isOpen: true,
13-
close: jest.fn().mockName('close'),
20+
close: jest.fn(),
1421
};
15-
it('renders correctly', () => {
16-
const wrapper = shallow(<ConfirmDialog {...props} />);
17-
expect(wrapper.snapshot).toMatchSnapshot();
22+
23+
const renderWithIntl = (component) => render(<IntlProvider locale="en">{component}</IntlProvider>);
24+
25+
it('renders title and description when isOpen is true', () => {
26+
renderWithIntl(<ConfirmDialog {...props} />);
27+
28+
expect(screen.getByText('Test Title')).toBeInTheDocument();
29+
expect(screen.getByText('Test Description')).toBeInTheDocument();
30+
});
31+
32+
it('renders action buttons', () => {
33+
renderWithIntl(<ConfirmDialog {...props} />);
34+
35+
expect(
36+
screen.getByRole('button', { name: /go back/i }),
37+
).toBeInTheDocument();
38+
expect(screen.getAllByRole('button')).toHaveLength(2);
39+
});
40+
41+
it('calls close function when go back button is clicked', async () => {
42+
const user = userEvent.setup();
43+
renderWithIntl(<ConfirmDialog {...props} />);
44+
45+
const goBackButton = screen.getByRole('button', { name: /go back/i });
46+
await user.click(goBackButton);
47+
48+
expect(props.close).toHaveBeenCalledTimes(1);
49+
});
50+
51+
it('does not render when isOpen is false', () => {
52+
renderWithIntl(<ConfirmDialog {...props} isOpen={false} />);
53+
54+
expect(screen.queryByText('Test Title')).not.toBeInTheDocument();
55+
expect(screen.queryByText('Test Description')).not.toBeInTheDocument();
1856
});
1957
});
Lines changed: 94 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,53 +1,119 @@
1-
import { shallow } from '@edx/react-unit-test-utils';
2-
1+
import { render, screen } from '@testing-library/react';
2+
import '@testing-library/jest-dom';
3+
import { IntlProvider } from '@edx/frontend-platform/i18n';
34
import { useORAConfigData } from 'hooks/app';
45
import { useCloseModalAction } from 'hooks/actions';
56
import ModalContainer from './ModalContainer';
67

8+
jest.unmock('@openedx/paragon');
9+
jest.unmock('react');
10+
jest.unmock('@edx/frontend-platform/i18n');
11+
12+
jest.mock('@edx/frontend-lib-special-exams', () => {
13+
// eslint-disable-next-line react/prop-types
14+
const OuterExamTimer = ({ courseId }) => (
15+
<div data-testid="outer-exam-timer">ExamTimer for {courseId}</div>
16+
);
17+
return { OuterExamTimer };
18+
});
19+
20+
jest.mock('data/redux', () => ({
21+
selectors: {
22+
specialExams: {
23+
activeExam: jest.fn(() => null),
24+
},
25+
},
26+
}));
27+
728
jest.mock('hooks/app', () => ({
829
useORAConfigData: jest.fn(),
30+
useIsPageDataLoaded: jest.fn(),
31+
useHasReceivedFinalGrade: jest.fn(),
32+
useGlobalState: jest.fn(),
33+
useAssessmentStepOrder: jest.fn(),
34+
useStepInfo: jest.fn(),
935
}));
1036
jest.mock('hooks/actions', () => ({
1137
useCloseModalAction: jest.fn(),
1238
}));
13-
jest.mock('components/ConfirmDialog', () => 'ConfirmDialog');
14-
jest.mock('components/ProgressBar', () => 'ProgressBar');
15-
jest.mock('react-router', () => ({
16-
useParams: jest.fn().mockReturnValue({ courseId: 'courseId' }),
39+
jest.mock('hooks/routing', () => ({
40+
useViewStep: jest.fn(),
1741
}));
18-
jest.mock('@edx/frontend-lib-special-exams', () => ({
19-
OuterExamTimer: () => 'OuterExamTimer',
42+
jest.mock('hooks/modal', () => ({
43+
useOpenModal: jest.fn(),
2044
}));
45+
jest.mock('react-router', () => ({
46+
useParams: jest.fn().mockReturnValue({ courseId: 'test-course-id' }),
47+
}));
48+
49+
const {
50+
useIsPageDataLoaded,
51+
useHasReceivedFinalGrade,
52+
useGlobalState,
53+
useAssessmentStepOrder,
54+
useStepInfo,
55+
} = require('hooks/app');
56+
const { useViewStep } = require('hooks/routing');
57+
const { useOpenModal } = require('hooks/modal');
2158

2259
describe('<ModalContainer />', () => {
23-
useORAConfigData.mockReturnValue({ title: 'title' });
24-
useCloseModalAction.mockReturnValue({
25-
confirmProps: {
26-
abc: 'def',
27-
},
28-
action: { onClick: jest.fn().mockName('closeModalAction') },
60+
beforeEach(() => {
61+
useORAConfigData.mockReturnValue({ title: 'Test Title' });
62+
useIsPageDataLoaded.mockReturnValue(true);
63+
useHasReceivedFinalGrade.mockReturnValue(false);
64+
useGlobalState.mockReturnValue({ activeStepName: 'submission' });
65+
useAssessmentStepOrder.mockReturnValue(['peer', 'self']);
66+
useViewStep.mockReturnValue('submission');
67+
useStepInfo.mockReturnValue({
68+
peer: { numberOfReceivedAssessments: 0, isWaitingForSubmissions: false },
69+
});
70+
useOpenModal.mockReturnValue(jest.fn());
71+
useCloseModalAction.mockReturnValue({
72+
confirmProps: {
73+
isOpen: true,
74+
title: 'Confirm Dialog',
75+
description: 'Are you sure?',
76+
close: jest.fn(),
77+
},
78+
action: { onClick: jest.fn() },
79+
});
2980
});
30-
const renderComponent = () => shallow(
31-
<ModalContainer>
32-
<div>children</div>
33-
</ModalContainer>,
34-
);
3581

36-
it('render default', () => {
37-
const wrapper = renderComponent();
38-
expect(wrapper.snapshot).toMatchSnapshot();
82+
it('renders with ConfirmDialog when confirmProps are provided', () => {
83+
render(
84+
<IntlProvider locale="en">
85+
<ModalContainer>
86+
<div>Test children</div>
87+
</ModalContainer>
88+
</IntlProvider>,
89+
);
3990

40-
expect(wrapper.instance.findByType('ConfirmDialog')).toHaveLength(1);
91+
expect(screen.getByText('Confirm Dialog')).toBeInTheDocument();
92+
expect(screen.getByText('Are you sure?')).toBeInTheDocument();
93+
94+
expect(screen.getByText('Test Title')).toBeInTheDocument();
95+
expect(screen.getByText('Test children')).toBeInTheDocument();
96+
expect(screen.getByTestId('outer-exam-timer')).toBeInTheDocument();
4197
});
4298

43-
it('render without confirmProps', () => {
99+
it('renders without ConfirmDialog when confirmProps is null', () => {
44100
useCloseModalAction.mockReturnValue({
45101
confirmProps: null,
46-
action: { onClick: jest.fn().mockName('closeModalAction') },
102+
action: { onClick: jest.fn() },
47103
});
48-
const wrapper = renderComponent();
49-
expect(wrapper.snapshot).toMatchSnapshot();
104+
render(
105+
<IntlProvider locale="en">
106+
<ModalContainer>
107+
<div>Test children</div>
108+
</ModalContainer>
109+
</IntlProvider>,
110+
);
111+
112+
expect(screen.queryByText('Confirm Dialog')).not.toBeInTheDocument();
113+
expect(screen.queryByText('Are you sure?')).not.toBeInTheDocument();
50114

51-
expect(wrapper.instance.findByType('ConfirmDialog')).toHaveLength(0);
115+
expect(screen.getByText('Test Title')).toBeInTheDocument();
116+
expect(screen.getByText('Test children')).toBeInTheDocument();
117+
expect(screen.getByTestId('outer-exam-timer')).toBeInTheDocument();
52118
});
53119
});

src/components/PageRoute.test.jsx

Lines changed: 35 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,53 +1,50 @@
11
import React from 'react';
2+
import { render, screen } from '@testing-library/react';
3+
import '@testing-library/jest-dom';
24

3-
import { shallow } from '@edx/react-unit-test-utils';
4-
import { AuthenticatedPageRoute } from '@edx/frontend-platform/react';
5-
import { SkeletonTheme } from '@openedx/paragon';
5+
import PageRoute from './PageRoute';
66

7-
import AppContainer from 'components/AppContainer';
8-
import ModalContainer from 'components/ModalContainer';
9-
import PageRoute, { skeletonTheme } from './PageRoute';
7+
jest.unmock('@openedx/paragon');
8+
jest.unmock('react');
9+
jest.unmock('@edx/frontend-platform/i18n');
1010

1111
jest.mock('react-router-dom', () => ({ Route: 'Route' }));
1212
jest.mock('@edx/frontend-platform/react', () => ({
13-
AuthenticatedPageRoute: 'AuthenticatedPageRoute',
13+
// eslint-disable-next-line react/prop-types
14+
AuthenticatedPageRoute: ({ children }) => (
15+
<div data-testid="authenticated-page-route">{children}</div>
16+
),
1417
}));
15-
jest.mock('components/AppContainer', () => 'AppContainer');
16-
jest.mock('components/ModalContainer', () => 'ModalContainer');
18+
// eslint-disable-next-line react/prop-types
19+
jest.mock('components/AppContainer', () => ({ children }) => (
20+
<div data-testid="app-container">{children}</div>
21+
));
22+
// eslint-disable-next-line react/prop-types
23+
jest.mock('components/ModalContainer', () => ({ children }) => (
24+
<div data-testid="modal-container">{children}</div>
25+
));
1726

1827
const props = {
1928
route: 'test-route',
20-
children: <b>test children</b>,
29+
children: <div data-testid="test-children">test children</div>,
2130
};
31+
2232
describe('PageRoute component', () => {
23-
test('modal snapshot', () => {
24-
const el = shallow(<PageRoute {...props} isModal />);
25-
expect(el.snapshot).toMatchSnapshot();
26-
const expectedElement = shallow(
27-
<AuthenticatedPageRoute>
28-
<AppContainer>
29-
<SkeletonTheme {...skeletonTheme}>
30-
<ModalContainer>
31-
{props.children}
32-
</ModalContainer>
33-
</SkeletonTheme>
34-
</AppContainer>
35-
</AuthenticatedPageRoute>,
36-
);
37-
expect(el.instance.matches(expectedElement)).toEqual(true);
33+
it('renders with ModalContainer when isModal is true', () => {
34+
render(<PageRoute {...props} isModal />);
35+
36+
expect(screen.getByTestId('authenticated-page-route')).toBeInTheDocument();
37+
expect(screen.getByTestId('app-container')).toBeInTheDocument();
38+
expect(screen.getByTestId('modal-container')).toBeInTheDocument();
39+
expect(screen.getByTestId('test-children')).toBeInTheDocument();
3840
});
39-
test('non-modal snapshot', () => {
40-
const el = shallow(<PageRoute {...props} />);
41-
expect(el.snapshot).toMatchSnapshot();
42-
const expectedElement = shallow(
43-
<AuthenticatedPageRoute>
44-
<AppContainer>
45-
<SkeletonTheme {...skeletonTheme}>
46-
{props.children}
47-
</SkeletonTheme>
48-
</AppContainer>
49-
</AuthenticatedPageRoute>,
50-
);
51-
expect(el.instance.matches(expectedElement)).toEqual(true);
41+
42+
it('renders without ModalContainer when isModal is false', () => {
43+
render(<PageRoute {...props} />);
44+
45+
expect(screen.getByTestId('authenticated-page-route')).toBeInTheDocument();
46+
expect(screen.getByTestId('app-container')).toBeInTheDocument();
47+
expect(screen.queryByTestId('modal-container')).not.toBeInTheDocument();
48+
expect(screen.getByTestId('test-children')).toBeInTheDocument();
5249
});
5350
});

0 commit comments

Comments
 (0)