Skip to content
This repository has been archived by the owner on Sep 11, 2024. It is now read-only.

feat: migrated tests from enzyme to RTL #160

Merged
merged 3 commits into from
Jan 31, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion jest.config.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
const { createConfig } = require('@edx/frontend-build');

const config = createConfig('jest', {
setupFiles: [
setupFilesAfterEnv: [
'<rootDir>/src/setupTest.js',
],
});
Expand Down
1,599 changes: 1,252 additions & 347 deletions package-lock.json

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -71,13 +71,13 @@
"devDependencies": {
"@edx/browserslist-config": "^1.2.0",
"@edx/frontend-build": "13.0.1",
"@edx/react-unit-test-utils": "1.7.0",
"@edx/reactifex": "1.0.3",
"@wojtekmaj/enzyme-adapter-react-17": "^0.8.0",
"@testing-library/jest-dom": "5.17.0",
"@testing-library/react": "12.1.5",
"autoprefixer": "10.2.6",
"axios-mock-adapter": "^1.15.0",
"enzyme": "^3.3.0",
"husky": "^0.14.3",
"react-test-renderer": "^17.0.2",
"travis-deploy-once": "^5.0.9"
}
}
7 changes: 6 additions & 1 deletion src/console/ConsolePage.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ export class ConsolePage extends React.Component {
<Collapsible
title="Manage Enrollments"
defaultOpen
data-testid="collapsible"
>
<div className="container p-0">
<div className={`${rowClasses} mt-2`}>
Expand Down Expand Up @@ -117,6 +118,7 @@ export class ConsolePage extends React.Component {
variant="danger"
dismissible={false}
show={!!this.props.loadingError}
data-testid="alert-danger"
>
<div>
<p>
Expand All @@ -132,6 +134,7 @@ export class ConsolePage extends React.Component {
dismissible={false}
show={!this.props.authorized && !this.props.loadingError}
variant="warning"
data-testid="alert-warning"
>
<p>
It appears you do not have proper permissions to access this application.
Expand All @@ -151,7 +154,7 @@ export class ConsolePage extends React.Component {
variant="danger"
dismissible
show={!!this.props.filterError}
data-testid="filter-alert"
data-testid="error-alert"
>
<p>Invalid program title.</p>
</Alert>
Expand All @@ -174,6 +177,7 @@ export class ConsolePage extends React.Component {
key={banner.id}
variant={banner.bannerType}
onClose={() => this.props.removeBanner(program.programKey, banner.id)}
data-testid="alert-info"
>
<div className="modal-alert">
{`${banner.message} `}
Expand All @@ -187,6 +191,7 @@ export class ConsolePage extends React.Component {
<ConnectedReportSection
programKey={program.programKey}
isFirstSection={!program.areEnrollmentsWritable}
data-testid="report-section"
/>
)}
</div>
Expand Down
172 changes: 78 additions & 94 deletions src/console/ConsolePage.test.jsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
import { mount, shallow } from 'enzyme';
import { Collapsible } from '@edx/paragon';
/* eslint-disable import/no-extraneous-dependencies */
import { fireEvent, render, screen } from '@testing-library/react';
import { shallow } from '@edx/react-unit-test-utils';
import React from 'react';
import renderer from 'react-test-renderer';
import { IntlProvider } from 'react-intl';
import { ConsolePage } from './ConsolePage';
import ConnectedReportSection from '../report/reportSection';

let apiData = [];

Expand Down Expand Up @@ -41,13 +40,11 @@ describe('ConsolePage', () => {
/>
</IntlProvider>
);
const wrapper = mount(consolePageComponent);
const tree = renderer.create(consolePageComponent);
const { container } = render(consolePageComponent);

expect(tree).toMatchSnapshot();
expect(wrapper.exists('.alert.alert-warning.show')).toEqual(false);
expect(wrapper.exists('.alert.alert-danger.show')).toEqual(false);
wrapper.unmount();
expect(container).toMatchSnapshot();
expect(container.querySelector('.alert-warning.show')).toBeNull();
expect(container.querySelector('.alert-danger.show')).toBeNull();
});

it('renders a warning banner if there is not an authorized user', () => {
Expand All @@ -66,13 +63,11 @@ describe('ConsolePage', () => {
/>
</IntlProvider>
);
const wrapper = mount(consolePageComponent);
const tree = renderer.create(consolePageComponent);
const { container } = render(consolePageComponent);

expect(tree).toMatchSnapshot();
expect(wrapper.exists('.alert.alert-warning.show')).toEqual(true);
expect(wrapper.exists('.alert.alert-danger.show')).toEqual(false);
wrapper.unmount();
expect(container).toMatchSnapshot();
expect(container.querySelector('.alert-warning.show')).toBeInTheDocument();
expect(container.querySelector('.alert-danger.show')).toBeNull();
});

it('renders an error banner when there was an error loading programs', () => {
Expand All @@ -92,13 +87,11 @@ describe('ConsolePage', () => {
/>
</IntlProvider>
);
const wrapper = mount(consolePageComponent);
const tree = renderer.create(consolePageComponent);
const { container } = render(consolePageComponent);

expect(tree).toMatchSnapshot();
expect(wrapper.exists('.alert.alert-warning.show')).toEqual(false);
expect(wrapper.exists('.alert.alert-danger.show')).toEqual(true);
wrapper.unmount();
expect(container).toMatchSnapshot();
expect(container.querySelector('.alert-warning.show')).toBeNull();
expect(container.querySelector('.alert-danger.show')).toBeInTheDocument();
});

it('renders programs when there is data passed in', () => {
Expand All @@ -117,20 +110,17 @@ describe('ConsolePage', () => {
/>
</IntlProvider>
);
const wrapper = mount(consolePageComponent);
const tree = renderer.create(consolePageComponent).toJSON();
const { container } = render(consolePageComponent);

expect(tree).toMatchSnapshot();
expect(container).toMatchSnapshot();
apiData.forEach((program, idx) => {
expect(wrapper.find('h2').at(idx).text()).toEqual(program.programTitle);
expect(wrapper.find(Collapsible).at(idx).prop('defaultOpen')).toEqual(true);
expect(screen.getByText(program.programTitle)).toBeInTheDocument();
expect(container.querySelectorAll('.pgn_collapsible')[idx]).toHaveClass('is-open');
});

expect(wrapper.exists('.alert-danger.show')).toEqual(false);
expect(wrapper.exists('.alert-info.show')).toEqual(false);
expect(wrapper.exists('.alert-warning.show')).toEqual(false);

wrapper.unmount();
expect(container.querySelector('.alert-danger.show')).toBeNull();
expect(container.querySelector('.alert-info.show')).toBeNull();
expect(container.querySelector('.alert-warning.show')).toBeNull();
});

it('passes isFirstSection=true to report section when there is no enrollment section', () => {
Expand All @@ -157,20 +147,18 @@ describe('ConsolePage', () => {

// shallow render ConsolePage to avoid fully rendering the ConnectedReportSection,
// which requires a Redux store
const wrapper = shallow(consolePageComponent);
const { instance } = shallow(consolePageComponent);

expect(wrapper.find('h2').text()).toEqual(apiData[0].programTitle);
expect(instance.findByType('h2')[0].el.children[0]).toEqual(apiData[0].programTitle);

// we don't expect to see the enrollment section
expect(wrapper.exists(Collapsible)).toEqual(false);

expect(wrapper.find(ConnectedReportSection).prop('isFirstSection')).toEqual(true);
expect(instance.findByTestId('collapsible')).toEqual([]);

expect(wrapper.exists('.alert-danger')).toEqual(false);
expect(wrapper.exists('.alert-info')).toEqual(false);
expect(wrapper.exists('.alert-warning.show')).toEqual(false);
expect(instance.findByTestId('report-section')[0].props.isFirstSection).toEqual(true);

wrapper.unmount();
expect(instance.findByTestId('alert-danger')[0].props.show).toEqual(false);
expect(instance.findByTestId('alert-info')).toEqual([]);
expect(instance.findByTestId('alert-warning')[0].props.show).toEqual(false);
});

it('passes isFirstSection=false to report section when there is an enrollment section', () => {
Expand All @@ -197,21 +185,19 @@ describe('ConsolePage', () => {

// shallow render ConsolePage to avoid fully rendering the ConnectedReportSection,
// which requires a Redux store
const wrapper = shallow(consolePageComponent);

expect(wrapper.find('h2').text()).toEqual(apiData[0].programTitle);
const { instance } = shallow(consolePageComponent);

const collapsible = wrapper.find(Collapsible);
expect(collapsible.prop('title')).toEqual('Manage Enrollments');
expect(collapsible.prop('defaultOpen')).toEqual(true);
expect(instance.findByType('h2')[0].el.children[0]).toEqual(apiData[0].programTitle);

expect(wrapper.find(ConnectedReportSection).prop('isFirstSection')).toEqual(false);
const collapsible = instance.findByTestId('collapsible');
expect(collapsible[0].props.title).toEqual('Manage Enrollments');
expect(collapsible[0].props.defaultOpen).toEqual(true);

expect(wrapper.exists('.alert-danger')).toEqual(false);
expect(wrapper.exists('.alert-info')).toEqual(false);
expect(wrapper.exists('.alert-warning.show')).toEqual(false);
expect(instance.findByTestId('report-section')[0].props.isFirstSection).toEqual(false);

wrapper.unmount();
expect(instance.findByTestId('alert-danger')[0].props.show).toEqual(false);
expect(instance.findByTestId('alert-info')).toEqual([]);
expect(instance.findByTestId('alert-warning')[0].props.show).toEqual(false);
});

it('renders program banners when they are included', () => {
Expand Down Expand Up @@ -242,22 +228,19 @@ describe('ConsolePage', () => {
/>
</IntlProvider>
);
const wrapper = mount(consolePageComponent);
const tree = renderer.create(consolePageComponent).toJSON();
const { container } = render(consolePageComponent);

expect(tree).toMatchSnapshot();
expect(wrapper.find('.alert-danger.show .modal-alert').at(0).text()).toEqual('Sorry something went wrong ');
expect(wrapper.find('.alert-success.show .modal-alert').at(0).text()).toEqual('You did it! ');

wrapper.unmount();
expect(container).toMatchSnapshot();
expect(container.querySelector('.alert-danger.show')).toHaveTextContent('Sorry something went wrong ');
expect(container.querySelector('.alert-success.show')).toHaveTextContent('You did it! ');
});

it('calls the fetchPrograms function on pageload', () => {
const mock = jest.fn();

expect(mock).not.toHaveBeenCalled();

mount(
render(
<IntlProvider locale="en">
<ConsolePage
authorized
Expand All @@ -281,7 +264,7 @@ describe('ConsolePage', () => {

expect(mock).not.toHaveBeenCalled();

const wrapper = mount(
const { container } = render(
<IntlProvider locale="en">
<ConsolePage
authorized
Expand All @@ -297,8 +280,8 @@ describe('ConsolePage', () => {
</IntlProvider>,
);

const filterForm = wrapper.find('form');
filterForm.simulate('submit');
const filterForm = container.querySelector('form');
fireEvent.submit(filterForm);
expect(mock).toHaveBeenCalled();
});

Expand All @@ -319,19 +302,17 @@ describe('ConsolePage', () => {
/>
</IntlProvider>
);
const wrapper = mount(consolePageComponent);
const tree = renderer.create(consolePageComponent);
const { container: tree } = render(consolePageComponent);

expect(tree).toMatchSnapshot();
const alert = wrapper.find('[data-testid="filter-alert"]').first();
expect(alert.text()).toContain('Invalid');
wrapper.unmount();
const alert = screen.getByTestId('error-alert');
expect(alert).toHaveTextContent('Invalid');
});

it('calls the correct action with the correct program key on download button clicks', () => {
const mock = jest.fn();

const wrapper = mount(
const { container } = render(
<IntlProvider locale="en">
<ConsolePage
authorized
Expand All @@ -347,31 +328,31 @@ describe('ConsolePage', () => {
</IntlProvider>,
);

const programADownloadProgramButton = wrapper.find('button.btn.btn-outline-primary').at(0);
expect(programADownloadProgramButton.text()).toEqual('Download Program Enrollments');
programADownloadProgramButton.simulate('click');
const programADownloadProgramButton = container.querySelectorAll('button.btn.btn-outline-primary')[0];
expect(programADownloadProgramButton).toHaveTextContent('Download Program Enrollments');
fireEvent.click(programADownloadProgramButton);
expect(mock).toHaveBeenCalledWith('a', false);

const programADownloadCourseButton = wrapper.find('button.btn.btn-outline-primary').at(1);
expect(programADownloadCourseButton.text()).toEqual('Download Course Enrollments');
programADownloadCourseButton.simulate('click');
const programADownloadCourseButton = container.querySelectorAll('button.btn.btn-outline-primary')[1];
expect(programADownloadCourseButton).toHaveTextContent('Download Course Enrollments');
fireEvent.click(programADownloadCourseButton);
expect(mock).toHaveBeenCalledWith('a', true);

const programBDownloadProgramButton = wrapper.find('button.btn.btn-outline-primary').at(2);
expect(programBDownloadProgramButton.text()).toEqual('Download Program Enrollments');
programBDownloadProgramButton.simulate('click');
const programBDownloadProgramButton = container.querySelectorAll('button.btn.btn-outline-primary')[2];
expect(programBDownloadProgramButton).toHaveTextContent('Download Program Enrollments');
fireEvent.click(programBDownloadProgramButton);
expect(mock).toHaveBeenCalledWith('b', false);

const programBDownloadCourseButton = wrapper.find('button.btn.btn-outline-primary').at(3);
expect(programBDownloadCourseButton.text()).toEqual('Download Course Enrollments');
programBDownloadCourseButton.simulate('click');
const programBDownloadCourseButton = container.querySelectorAll('button.btn.btn-outline-primary')[3];
expect(programBDownloadCourseButton).toHaveTextContent('Download Course Enrollments');
fireEvent.click(programBDownloadCourseButton);
expect(mock).toHaveBeenCalledWith('b', true);
});

it('calls the correct action with the correct program key onchange of the file inputs', () => {
const mock = jest.fn();

const wrapper = mount(
const { container } = render(
<IntlProvider locale="en">
<ConsolePage
authorized
Expand All @@ -390,13 +371,18 @@ describe('ConsolePage', () => {
const file = new File([], 'test');

expect(mock).not.toHaveBeenCalled();
wrapper.find('.input-overlay-hack').at(0).simulate('change', { target: { name: 'pollName', files: [file] } });
const fileInputs = container.querySelectorAll('.input-overlay-hack');

fireEvent.change(fileInputs[0], { target: { files: [file] } });
expect(mock).toHaveBeenCalledWith('a', false, file);
wrapper.find('.input-overlay-hack').at(1).simulate('change', { target: { name: 'pollName', files: [file] } });

fireEvent.change(fileInputs[1], { target: { files: [file] } });
expect(mock).toHaveBeenCalledWith('a', true, file);
wrapper.find('.input-overlay-hack').at(2).simulate('change', { target: { name: 'pollName', files: [file] } });

fireEvent.change(fileInputs[2], { target: { files: [file] } });
expect(mock).toHaveBeenCalledWith('b', false, file);
wrapper.find('.input-overlay-hack').at(3).simulate('change', { target: { name: 'pollName', files: [file] } });

fireEvent.change(fileInputs[3], { target: { files: [file] } });
expect(mock).toHaveBeenCalledWith('b', true, file);
});

Expand Down Expand Up @@ -428,10 +414,9 @@ describe('ConsolePage', () => {
/>
</IntlProvider>
);
const wrapperOne = mount(consolePageComponentOne);
const programTitleZero = wrapperOne.find('h2').first();
expect(programTitleZero.text()).toEqual('program 0');
wrapperOne.unmount();
const wrapperOne = render(consolePageComponentOne);
const programTitleZero = wrapperOne.container.querySelector('h2');
expect(programTitleZero).toHaveTextContent('program 0');

const consolePageComponentTwo = (
<IntlProvider locale="en">
Expand All @@ -449,9 +434,8 @@ describe('ConsolePage', () => {
/>
</IntlProvider>
);
const wrapperTwo = mount(consolePageComponentTwo);
const programTitleTen = wrapperTwo.find('h2').first();
expect(programTitleTen.text()).toEqual('program 10');
wrapperTwo.unmount();
const wrapperTwo = render(consolePageComponentTwo);
const programTitleTen = wrapperTwo.container.querySelector('h2');
expect(programTitleTen).toHaveTextContent('program 10');
});
});
Loading