Skip to content

Commit c25782b

Browse files
authored
test: deprecate react-unit-test-utils 5/14 (#341)
* test: deprecate react-unit-test-utils 5/14 * test: addressed feedback
1 parent c785c36 commit c25782b

File tree

10 files changed

+206
-202
lines changed

10 files changed

+206
-202
lines changed
Lines changed: 23 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,48 @@
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 { IntlProvider } from '@edx/frontend-platform/i18n';
24

35
import { usePrompts } from 'hooks/app';
46

57
import StudioViewPrompt from './StudioViewPrompt';
68

9+
jest.unmock('@openedx/paragon');
10+
jest.unmock('react');
11+
jest.unmock('@edx/frontend-platform/i18n');
12+
713
jest.mock('hooks/app', () => ({
814
usePrompts: jest.fn(),
915
}));
1016
jest.mock('./XBlockStudioViewProvider', () => ({
1117
useXBlockStudioViewContext: () => ({
1218
promptIsOpen: true,
13-
togglePrompt: jest.fn().mockName('togglePrompt'),
19+
togglePrompt: jest.fn(),
1420
}),
1521
}));
16-
jest.mock('components/Prompt', () => 'Prompt');
22+
jest.mock('components/Prompt', () => {
23+
// eslint-disable-next-line react/prop-types
24+
const Prompt = ({ prompt }) => <div data-testid="prompt">{prompt}</div>;
25+
return Prompt;
26+
});
1727

1828
describe('<StudioViewPrompt />', () => {
19-
it('render with prompt', () => {
29+
const renderWithIntl = (component) => render(<IntlProvider locale="en">{component}</IntlProvider>);
30+
31+
it('renders prompts when prompts array has items', () => {
2032
usePrompts.mockReturnValue(['prompt1', 'prompt2']);
2133

22-
const wrapper = shallow(<StudioViewPrompt />);
23-
expect(wrapper.snapshot).toMatchSnapshot();
34+
renderWithIntl(<StudioViewPrompt />);
2435

25-
expect(wrapper.instance.findByType('Prompt')).toHaveLength(2);
36+
expect(screen.getAllByTestId('prompt')).toHaveLength(2);
37+
expect(screen.getByText('prompt1')).toBeInTheDocument();
38+
expect(screen.getByText('prompt2')).toBeInTheDocument();
2639
});
2740

28-
it('render without prompt', () => {
41+
it('renders no prompts when prompts array is empty', () => {
2942
usePrompts.mockReturnValue([]);
3043

31-
const wrapper = shallow(<StudioViewPrompt />);
32-
expect(wrapper.snapshot).toMatchSnapshot();
44+
renderWithIntl(<StudioViewPrompt />);
3345

34-
expect(wrapper.instance.findByType('Prompt')).toHaveLength(0);
46+
expect(screen.queryByTestId('prompt')).not.toBeInTheDocument();
3547
});
3648
});
Lines changed: 55 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,80 @@
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 { IntlProvider } from '@edx/frontend-platform/i18n';
24

35
import { useFileUploadConfig } from 'hooks/app';
46

57
import FileUploadConfig from './FileUploadConfig';
68

9+
jest.unmock('@openedx/paragon');
10+
jest.unmock('react');
11+
jest.unmock('@edx/frontend-platform/i18n');
12+
713
jest.mock('hooks/app', () => ({
814
useFileUploadConfig: jest.fn(),
915
}));
10-
jest.mock('./RequiredConfig', () => 'RequiredConfig');
16+
jest.mock('./RequiredConfig', () => {
17+
// eslint-disable-next-line react/prop-types
18+
const RequiredConfig = ({ required }) => (
19+
<span data-testid="required-config">
20+
{required ? 'Required' : 'Optional'}
21+
</span>
22+
);
23+
return RequiredConfig;
24+
});
1125

1226
describe('<FileUploadConfig />', () => {
13-
it('should render', () => {
27+
const renderWithIntl = (component) => render(<IntlProvider locale="en">{component}</IntlProvider>);
28+
29+
it('renders file upload configuration when enabled', () => {
1430
useFileUploadConfig.mockReturnValue({
1531
enabled: true,
1632
fileUploadLimit: 10,
1733
required: true,
1834
});
1935

20-
const wrapper = shallow(<FileUploadConfig />);
21-
expect(wrapper.snapshot).toMatchSnapshot();
36+
renderWithIntl(<FileUploadConfig />);
37+
38+
expect(screen.getByText('File uploads:')).toBeInTheDocument();
39+
expect(screen.getByText('File upload limit:')).toBeInTheDocument();
40+
// Check for the upload limit number in the context of the upload limit label
41+
expect(
42+
screen.getByText('File upload limit:').closest('p'),
43+
).toHaveTextContent('10');
44+
expect(screen.getByTestId('required-config')).toBeInTheDocument();
2245
});
2346

24-
it('should not render', () => {
47+
it('does not render when file upload is disabled', () => {
2548
useFileUploadConfig.mockReturnValue({
2649
enabled: false,
2750
});
2851

29-
const wrapper = shallow(<FileUploadConfig />);
30-
expect(wrapper.snapshot).toMatchSnapshot();
52+
const { container } = renderWithIntl(<FileUploadConfig />);
53+
54+
expect(container.firstChild).toBeNull();
55+
});
56+
57+
it('handles null config gracefully', () => {
58+
useFileUploadConfig.mockReturnValue(null);
59+
60+
const { container } = renderWithIntl(<FileUploadConfig />);
61+
62+
expect(container.firstChild).toBeNull();
63+
});
64+
65+
it('renders with different file upload limit', () => {
66+
useFileUploadConfig.mockReturnValue({
67+
enabled: true,
68+
fileUploadLimit: 5,
69+
required: false,
70+
});
71+
72+
renderWithIntl(<FileUploadConfig />);
3173

32-
expect(wrapper.isEmptyRender()).toBe(true);
74+
// Check for the upload limit number in the context of the upload limit label
75+
expect(
76+
screen.getByText('File upload limit:').closest('p'),
77+
).toHaveTextContent('5');
78+
expect(screen.getByTestId('required-config')).toHaveTextContent('Optional');
3379
});
3480
});

src/views/XBlockStudioView/components/StudioViewSettings/__snapshots__/FileUploadConfig.test.jsx.snap

Lines changed: 0 additions & 24 deletions
This file was deleted.
Lines changed: 38 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,72 @@
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 { IntlProvider } from '@edx/frontend-platform/i18n';
24

35
import { useORAConfigData } from 'hooks/app';
46
import { stepNames } from 'constants/index';
57

68
import StudioViewSteps from './StudioViewSteps';
79

10+
jest.unmock('@openedx/paragon');
11+
jest.unmock('react');
12+
jest.unmock('@edx/frontend-platform/i18n');
13+
814
jest.mock('hooks/app', () => ({
915
useORAConfigData: jest.fn(),
1016
}));
1117
jest.mock('./XBlockStudioViewProvider', () => ({
1218
useXBlockStudioViewContext: () => ({
1319
assessmentStepsIsOpen: true,
14-
toggleAssessmentSteps: jest.fn().mockName('toggleAssessmentSteps'),
20+
toggleAssessmentSteps: jest.fn(),
1521
}),
1622
}));
1723

1824
describe('<StudioViewSteps />', () => {
19-
it('render without steps', () => {
25+
const renderWithIntl = (component) => render(<IntlProvider locale="en">{component}</IntlProvider>);
26+
27+
it('renders without steps when order is empty', () => {
2028
useORAConfigData.mockReturnValue({
2129
assessmentSteps: {
2230
order: [],
2331
},
2432
});
2533

26-
const wrapper = shallow(<StudioViewSteps />);
27-
expect(wrapper.snapshot).toMatchSnapshot();
34+
renderWithIntl(<StudioViewSteps />);
2835

29-
expect(wrapper.instance.findByType('p')).toHaveLength(0);
36+
expect(screen.getByText('Assessment steps')).toBeInTheDocument();
37+
expect(screen.queryByText(/Step \d+:/)).not.toBeInTheDocument();
3038
});
3139

32-
it('render with steps', () => {
40+
it('renders with steps when order has items', () => {
3341
useORAConfigData.mockReturnValue({
3442
assessmentSteps: {
3543
order: [stepNames.self, stepNames.peer],
3644
},
3745
});
3846

39-
const wrapper = shallow(<StudioViewSteps />);
40-
expect(wrapper.snapshot).toMatchSnapshot();
47+
renderWithIntl(<StudioViewSteps />);
48+
49+
expect(screen.getByText('Assessment steps')).toBeInTheDocument();
50+
expect(screen.getByText('Step 1:')).toBeInTheDocument();
51+
expect(screen.getByText('Step 2:')).toBeInTheDocument();
52+
expect(screen.getByText('Self assessment')).toBeInTheDocument();
53+
expect(screen.getByText('Peer assessment')).toBeInTheDocument();
54+
});
55+
56+
it('renders correct number of step paragraphs', () => {
57+
useORAConfigData.mockReturnValue({
58+
assessmentSteps: {
59+
order: [stepNames.self, stepNames.peer, stepNames.staff],
60+
},
61+
});
62+
63+
renderWithIntl(<StudioViewSteps />);
4164

42-
expect(wrapper.instance.findByType('p')).toHaveLength(2);
65+
expect(screen.getByText('Step 1:')).toBeInTheDocument();
66+
expect(screen.getByText('Step 2:')).toBeInTheDocument();
67+
expect(screen.getByText('Step 3:')).toBeInTheDocument();
68+
expect(screen.getByText('Self assessment')).toBeInTheDocument();
69+
expect(screen.getByText('Peer assessment')).toBeInTheDocument();
70+
expect(screen.getByText('Staff assessment')).toBeInTheDocument();
4371
});
4472
});
Lines changed: 52 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,17 @@
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 { IntlProvider } from '@edx/frontend-platform/i18n';
4+
import userEvent from '@testing-library/user-event';
25

36
import { useORAConfigData } from 'hooks/app';
4-
57
import { useXBlockStudioViewContext } from './XBlockStudioViewProvider';
6-
import messages from './messages';
78

89
import StudioViewTitle from './StudioViewTitle';
910

11+
jest.unmock('@openedx/paragon');
12+
jest.unmock('react');
13+
jest.unmock('@edx/frontend-platform/i18n');
14+
1015
jest.mock('hooks/app', () => ({
1116
useORAConfigData: jest.fn(),
1217
}));
@@ -15,30 +20,59 @@ jest.mock('./XBlockStudioViewProvider', () => ({
1520
}));
1621

1722
describe('<StudioViewTitle />', () => {
18-
const mockIsAllClosed = jest.fn().mockName('isAllClosed');
19-
useXBlockStudioViewContext.mockReturnValue({
20-
isAllClosed: mockIsAllClosed,
21-
toggleAll: jest.fn().mockName('toggleAll'),
22-
});
23-
useORAConfigData.mockReturnValue({
24-
title: 'Test Title',
23+
const mockIsAllClosed = jest.fn();
24+
const mockToggleAll = jest.fn();
25+
26+
const renderWithIntl = (component) => render(<IntlProvider locale="en">{component}</IntlProvider>);
27+
28+
beforeEach(() => {
29+
useXBlockStudioViewContext.mockReturnValue({
30+
isAllClosed: mockIsAllClosed,
31+
toggleAll: mockToggleAll,
32+
});
33+
useORAConfigData.mockReturnValue({
34+
title: 'Test Title',
35+
});
2536
});
2637

27-
it('render title and button', () => {
38+
it('renders title and expand button when all is closed', () => {
2839
mockIsAllClosed.mockReturnValue(true);
2940

30-
const wrapper = shallow(<StudioViewTitle />);
31-
expect(wrapper.snapshot).toMatchSnapshot();
41+
renderWithIntl(<StudioViewTitle />);
3242

33-
expect(wrapper.instance.findByType('Button')[0].children[0].el).toBe(messages.expandAllButton.defaultMessage);
43+
expect(screen.getByRole('heading', { level: 2 })).toHaveTextContent(
44+
'Test Title',
45+
);
46+
expect(screen.getByRole('button')).toHaveTextContent('Expand all');
3447
});
3548

36-
it('render when all is not closed', () => {
49+
it('renders title and collapse button when all is not closed', () => {
3750
mockIsAllClosed.mockReturnValue(false);
3851

39-
const wrapper = shallow(<StudioViewTitle />);
40-
expect(wrapper.snapshot).toMatchSnapshot();
52+
renderWithIntl(<StudioViewTitle />);
53+
54+
expect(screen.getByRole('heading', { level: 2 })).toHaveTextContent(
55+
'Test Title',
56+
);
57+
expect(screen.getByRole('button')).toHaveTextContent('Collapse all');
58+
});
59+
60+
it('calls toggleAll when button is clicked', async () => {
61+
const user = userEvent.setup();
62+
mockIsAllClosed.mockReturnValue(true);
63+
64+
renderWithIntl(<StudioViewTitle />);
65+
66+
const button = screen.getByRole('button');
67+
await user.click(button);
68+
69+
expect(mockToggleAll).toHaveBeenCalledTimes(1);
70+
});
71+
72+
it('has correct CSS class on container', () => {
73+
mockIsAllClosed.mockReturnValue(true);
74+
const { container } = renderWithIntl(<StudioViewTitle />);
4175

42-
expect(wrapper.instance.findByType('Button')[0].children[0].el).toBe(messages.collapseAllButton.defaultMessage);
76+
expect(container.querySelector('.block-title')).toBeInTheDocument();
4377
});
4478
});

src/views/XBlockStudioView/components/__snapshots__/StudioViewPrompt.test.jsx.snap

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

0 commit comments

Comments
 (0)