Skip to content

Commit 0151db2

Browse files
chore(tests): migrate test cases from Enzyme to React Testing Library
1 parent 4e29750 commit 0151db2

File tree

9 files changed

+6119
-5124
lines changed

9 files changed

+6119
-5124
lines changed

jest.config.js

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,15 @@
11
const { createConfig } = require('@openedx/frontend-build');
2-
2+
const { TestEnvironment } = require('jest-environment-jsdom');
33
module.exports = createConfig('jest', {
44
setupFiles: ['<rootDir>/src/setupTest.js'],
5+
testEnvironment: 'jsdom',
6+
7+
8+
9+
setupFilesAfterEnv: ['@testing-library/jest-dom'],
10+
11+
12+
513
collectCoverage: true,
614
collectCoverageFrom: ['src/**/*.{js,jsx}'],
715
coveragePathIgnorePatterns: [

package-lock.json

Lines changed: 5927 additions & 4912 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 15 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
"lint:fix": "fedx-scripts eslint --fix --ext .js --ext .jsx .",
1717
"start": "fedx-scripts webpack-dev-server --progress",
1818
"debug-test": "node --inspect-brk node_modules/.bin/jest --coverage --runInBand",
19-
"test": "TZ=UTC fedx-scripts jest --coverage --maxWorkers=2",
19+
"test": "fedx-scripts jest --coverage --maxWorkers=2",
2020
"test:watch": "npm run test -- --watch",
2121
"snapshot": "fedx-scripts jest --updateSnapshot"
2222
},
@@ -31,15 +31,15 @@
3131
},
3232
"dependencies": {
3333
"@edx/brand": "npm:@openedx/brand-openedx@^1.2.2",
34-
"@edx/frontend-enterprise-utils": "9.1.0",
35-
"@edx/frontend-platform": "^8.3.2",
34+
"@edx/frontend-enterprise-utils": "^10.0.0",
35+
"@edx/frontend-platform": "^8.5.0",
3636
"@edx/openedx-atlas": "^0.6.0",
3737
"@fortawesome/fontawesome-svg-core": "1.2.32",
3838
"@fortawesome/free-brands-svg-icons": "5.15.1",
3939
"@fortawesome/free-regular-svg-icons": "5.15.1",
4040
"@fortawesome/free-solid-svg-icons": "5.15.1",
4141
"@fortawesome/react-fontawesome": "^0.1.14",
42-
"@openedx/paragon": "^23.4.2",
42+
"@openedx/paragon": "^22.17.0",
4343
"axios": "^1.7.7",
4444
"babel-polyfill": "6.26.0",
4545
"classnames": "2.2.6",
@@ -48,36 +48,34 @@
4848
"lodash.snakecase": "4.1.1",
4949
"moment": "2.29.4",
5050
"prop-types": "15.7.2",
51-
"react": "17.0.2",
52-
"react-dom": "17.0.2",
53-
"react-helmet": "^6.1.0",
54-
"react-redux": "^7.2.9",
51+
"react": "18.3.1",
52+
"react-dom": "18.3.1",
53+
"react-helmet-async": "^2.0.4",
54+
"react-redux": "^8.1.3",
5555
"react-responsive": "^8.2.0",
5656
"react-router": "6.15.0",
5757
"react-router-dom": "6.15.0",
5858
"react-table": "^7.6.3",
5959
"react-transition-group": "4.4.1",
60-
"redux": "4.0.5",
60+
"redux": "^4.2.1",
6161
"use-context-selector": "1.4.1",
6262
"uuid": "9.0.0"
6363
},
6464
"devDependencies": {
6565
"@edx/browserslist-config": "^1.1.0",
6666
"@edx/reactifex": "^1.0.3",
67-
"@openedx/frontend-build": "^14.3.3",
68-
"@testing-library/dom": "^9.3.4",
69-
"@testing-library/jest-dom": "^5.17.0",
70-
"@testing-library/react": "12.1.4",
71-
"@testing-library/react-hooks": "^8.0.1",
67+
"@emotion/jest": "^11.13.0",
68+
"@openedx/frontend-build": "^14.6.0",
69+
"@testing-library/jest-dom": "^6.6.4",
70+
"@testing-library/react": "^14.3.1",
7271
"@testing-library/user-event": "^14.5.2",
7372
"@types/react-table": "^7.7.2",
74-
"@wojtekmaj/enzyme-adapter-react-17": "^0.8.0",
7573
"axios-mock-adapter": "^1.19.0",
76-
"enzyme": "3.11.0",
7774
"glob": "7.1.6",
7875
"jest": "^29.7.0",
76+
"jest-emotion": "^11.0.0",
7977
"jest-environment-jsdom": "^29.7.0",
80-
"react-test-renderer": "^17.0.2",
78+
"react-test-renderer": "^18.3.1",
8179
"reactifex": "1.1.1"
8280
}
8381
}
Lines changed: 41 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
1-
import { mount } from 'enzyme';
21
import React from 'react';
3-
import { waitFor } from '@testing-library/react';
2+
import { render,screen,waitFor } from '@testing-library/react';
3+
4+
import '@testing-library/jest-dom';
5+
6+
7+
48
import FeatureBasedEnrollment from './FeatureBasedEnrollment';
59
import UserMessagesProvider from '../userMessages/UserMessagesProvider';
6-
import { fbeEnabledResponse } from './data/test/featureBasedEnrollment';
10+
711

812
import * as api from './data/api';
913

@@ -19,67 +23,49 @@ describe('Feature Based Enrollment', () => {
1923
apiFetchSignal: true,
2024
};
2125

22-
let wrapper;
23-
24-
beforeEach(async () => {
25-
// api file has only one default export, so that will be spied-on
26-
jest.spyOn(api, 'default').mockImplementationOnce(() => Promise.resolve(fbeEnabledResponse));
27-
wrapper = mount(<FeatureBasedEnrollmentWrapper {...props} />);
28-
});
26+
it('renders title when FBE data is fetched', async () => {
27+
render(<FeatureBasedEnrollmentWrapper {...props} />);
28+
await waitFor(() => {
29+
expect(screen.getByText('Feature Based Enrollment Configuration')).toBeInTheDocument();
30+
});
2931

30-
afterEach(() => {
31-
wrapper.unmount();
3232
});
33+
it('shows no record message when no FBE data',async () => {
34+
jest.spyOn(api,'default').mockImplementationOnce(() => Promise.resolve({}));
35+
render(<FeatureBasedEnrollmentWrapper {...props} />);
36+
await waitFor(() => {
37+
expect(screen.getByText('No Feature Based Enrollment Configurations were found.')).toBeInTheDocument();
38+
});
39+
});
40+
it('shows loading message initially', () => {
41+
render(<FeatureBasedEnrollmentWrapper {...props} />);
42+
expect(screen.getByText(/Loading/i)).toBeInTheDocument();
43+
});
3344

34-
it('default props', () => {
35-
const courseId = wrapper.prop('courseId');
36-
expect(courseId).toEqual(props.courseId);
37-
});
45+
it('shows error alert an API error', async () => {
46+
const fbeErrors = {
47+
errors: [
48+
{
49+
code: null,
50+
dismissible: true,
51+
text: 'Error fetching FBE Data',
52+
type: 'error',
53+
topic:'featureBasedEnrollment',
54+
},
55+
],
56+
};
3857

39-
it('Successful fetch for FBE data', async () => {
40-
const cardList = wrapper.find('Card');
41-
const courseTitle = wrapper.find('h4');
4258

43-
waitFor(() => {
44-
expect(cardList).toHaveLength(2);
45-
expect(wrapper.find('h3#fbe-title-header').text()).toEqual('Feature Based Enrollment Configuration');
46-
expect(courseTitle.text()).toEqual('Course Title: test course');
59+
jest.spyOn(api,'default').mockImplementationOnce(() => Promise.resolve(fbeErrors));
60+
render(<FeatureBasedEnrollmentWrapper {...props} />);
61+
await waitFor(() => {
62+
expect(screen.getByText('Error fetching FBE Data')).toBeInTheDocument();
4763
});
48-
});
64+
});
65+
});
4966

50-
it('No FBE Data', async () => {
51-
jest.spyOn(api, 'default').mockImplementationOnce(() => Promise.resolve({}));
52-
wrapper = mount(<FeatureBasedEnrollmentWrapper {...props} />);
5367

54-
const cardList = wrapper.find('Card');
55-
const noRecordMessage = wrapper.find('p');
5668

57-
expect(cardList).toHaveLength(0);
58-
expect(wrapper.find('h3#fbe-title-header').text()).toEqual('Feature Based Enrollment Configuration');
59-
waitFor(() => expect(noRecordMessage.text()).toEqual('No Feature Based Enrollment Configurations were found.'));
60-
});
6169

62-
it('Page Loading component render', async () => {
63-
wrapper = mount(<FeatureBasedEnrollmentWrapper {...props} />);
64-
expect(wrapper.find('PageLoading').html()).toEqual(expect.stringContaining('Loading'));
65-
});
6670

67-
it('Error fetching FBE data', async () => {
68-
const fbeErrors = {
69-
errors: [
70-
{
71-
code: null,
72-
dismissible: true,
73-
text: 'Error fetching FBE Data',
74-
type: 'error',
75-
topic: 'featureBasedEnrollment',
76-
},
77-
],
78-
};
79-
jest.spyOn(api, 'default').mockImplementationOnce(() => Promise.resolve(fbeErrors));
80-
wrapper = mount(<FeatureBasedEnrollmentWrapper {...props} />);
8171

82-
const alert = wrapper.find('.alert');
83-
waitFor(() => expect(alert.text()).toEqual('Error fetching FBE Data'));
84-
});
85-
});
Lines changed: 57 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import { mount } from 'enzyme';
21
import React from 'react';
2+
import { render, screen, within, cleanup } from '@testing-library/react';
33
import FeatureBasedEnrollmentCard from './FeatureBasedEnrollmentCard';
44
import {
55
fbeDurationConfigEnabled,
@@ -9,77 +9,79 @@ import {
99
} from './data/test/featureBasedEnrollment';
1010

1111
describe('Feature Based Enrollment Card Component', () => {
12-
let wrapper;
12+
afterEach(cleanup);
1313

14-
afterEach(() => {
15-
wrapper.unmount();
16-
});
14+
describe('Gating Config Enabled', () => {
15+
const title = 'Gating Config Enabled';
16+
17+
it('Gating Config Enabled', () => {
18+
render(<FeatureBasedEnrollmentCard title="Gating Config Enabled" fbeData={fbeGatingConfigEnabled} />);
1719

18-
describe('Gating config', () => {
19-
const title = 'Gating Config';
20+
expect(screen.getByText('Gating Config Enabled')).toBeInTheDocument();
2021

21-
it('Gating config enabled', () => {
22-
wrapper = mount(<FeatureBasedEnrollmentCard title={title} fbeData={fbeGatingConfigEnabled} />);
23-
const header = wrapper.find('.card-title');
24-
const dataTable = wrapper.find('table.fbe-table tr');
25-
const dateRow = dataTable.at(0);
26-
const reasonRow = dataTable.at(1);
22+
const rows = screen.getAllByRole('row');
23+
const dateRow = within(rows[0]);
24+
const reasonRow = within(rows[1]);
2725

28-
expect(header.text()).toEqual('Gating Config Enabled');
29-
expect(dateRow.find('th').at(0).text()).toEqual('Enabled As Of');
30-
expect(dateRow.find('td').at(0).text()).toEqual('Jan 1, 2020 12:00 AM');
26+
expect(dateRow.getByText('Enabled As Of')).toBeInTheDocument();
27+
expect(dateRow.getByText('Jan 1, 2020 12:00 AM')).toBeInTheDocument();
3128

32-
expect(reasonRow.find('th').at(0).text()).toEqual('Reason');
33-
expect(reasonRow.find('td').at(0).text()).toEqual('Site');
29+
expect(reasonRow.getByText('Reason')).toBeInTheDocument();
30+
expect(reasonRow.getByText('Site')).toBeInTheDocument();
3431
});
3532

36-
it('Gating config disabled', () => {
37-
wrapper = mount(<FeatureBasedEnrollmentCard title={title} fbeData={fbeGatingConfigDisabled} />);
38-
const header = wrapper.find('.card-title');
39-
const dataTable = wrapper.find('table.fbe-table tr');
40-
const dateRow = dataTable.at(0);
41-
const reasonRow = dataTable.at(1);
33+
it("Gating config disabled", () => {
34+
render(<FeatureBasedEnrollmentCard title="Gating config disabled" fbeData={fbeGatingConfigDisabled} />);
35+
36+
expect(screen.getByText("Gating config disabled")).toBeInTheDocument();
4237

43-
expect(header.text()).toEqual('Gating Config Disabled');
44-
expect(dateRow.find('th').at(0).text()).toEqual('Enabled As Of');
45-
expect(dateRow.find('td').at(0).text()).toEqual('N/A');
38+
const rows = screen.getAllByRole('row');
39+
const dateRow = within(rows[0]);
40+
const reasonRow = within(rows[1]);
4641

47-
expect(reasonRow.find('th').at(0).text()).toEqual('Reason');
48-
expect(reasonRow.find('td').at(0).text()).toEqual('');
42+
expect(dateRow.getByText('Enabled As Of')).toBeInTheDocument();
43+
expect(dateRow.getByText('N/A')).toBeInTheDocument();
44+
45+
expect(reasonRow.getByText('Reason')).toBeInTheDocument();
46+
expect(reasonRow.queryByText('Site')).not.toBeInTheDocument();
4947
});
5048
});
5149

52-
describe('Duration config', () => {
53-
const title = 'Duration Config';
50+
describe('Duration Config Enabled', () => {
51+
const title = 'Duration Config Enabled';
5452

5553
it('Duration config enabled', () => {
56-
wrapper = mount(<FeatureBasedEnrollmentCard title={title} fbeData={fbeDurationConfigEnabled} />);
57-
const header = wrapper.find('.card-title');
58-
const dataTable = wrapper.find('table.fbe-table tr');
59-
const dateRow = dataTable.at(0);
60-
const reasonRow = dataTable.at(1);
61-
62-
expect(header.text()).toEqual('Duration Config Enabled');
63-
expect(dateRow.find('th').at(0).text()).toEqual('Enabled As Of');
64-
expect(dateRow.find('td').at(0).text()).toEqual('Feb 1, 2020 12:00 AM');
65-
66-
expect(reasonRow.find('th').at(0).text()).toEqual('Reason');
67-
expect(reasonRow.find('td').at(0).text()).toEqual('Site Config');
54+
render(<FeatureBasedEnrollmentCard title="Duration Config Enabled" fbeData={fbeDurationConfigEnabled} />);
55+
56+
expect(screen.getByText('Duration Config Enabled')).toBeInTheDocument();
57+
58+
const rows = screen.getAllByRole('row');
59+
const dateRow = within(rows[0]);
60+
const reasonRow = within(rows[1]);
61+
62+
expect(dateRow.getByText('Enabled As Of')).toBeInTheDocument();
63+
expect(dateRow.getByText('Feb 1, 2020 12:00 AM')).toBeInTheDocument();
64+
65+
expect(reasonRow.getByText('Reason')).toBeInTheDocument();
66+
expect(reasonRow.getByText('Site Config')).toBeInTheDocument();
6867
});
6968

70-
it('Duration config disabled', () => {
71-
wrapper = mount(<FeatureBasedEnrollmentCard title={title} fbeData={fbeDurationConfigDisabled} />);
72-
const header = wrapper.find('.card-title');
73-
const dataTable = wrapper.find('table.fbe-table tr');
74-
const dateRow = dataTable.at(0);
75-
const reasonRow = dataTable.at(1);
69+
70+
71+
it('Duration Config Disabled', () => {
72+
render(<FeatureBasedEnrollmentCard title="Duration Config Disabled" fbeData={fbeDurationConfigDisabled} />);
73+
74+
expect(screen.getByText('Duration Config Disabled')).toBeInTheDocument();
75+
76+
const rows = screen.getAllByRole('row');
77+
const dateRow = within(rows[0]);
78+
const reasonRow = within(rows[1]);
7679

77-
expect(header.text()).toEqual('Duration Config Disabled');
78-
expect(dateRow.find('th').at(0).text()).toEqual('Enabled As Of');
79-
expect(dateRow.find('td').at(0).text()).toEqual('N/A');
80+
expect(dateRow.getByText('Enabled As Of')).toBeInTheDocument();
81+
expect(dateRow.getByText('N/A')).toBeInTheDocument();
8082

81-
expect(reasonRow.find('th').at(0).text()).toEqual('Reason');
82-
expect(reasonRow.find('td').at(0).text()).toEqual('');
83+
expect(reasonRow.getByText('Reason')).toBeInTheDocument();
84+
expect(reasonRow.queryByText('Site Config')).not.toBeInTheDocument();
8385
});
8486
});
85-
});
87+
});

0 commit comments

Comments
 (0)