Skip to content

Commit

Permalink
feat: migrate enzyme with RTL (#615)
Browse files Browse the repository at this point in the history
  • Loading branch information
Syed-Ali-Abbas-Zaidi authored Dec 26, 2023
1 parent 683f57d commit cdbd00d
Show file tree
Hide file tree
Showing 10 changed files with 11,493 additions and 7,160 deletions.
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');

module.exports = createConfig('jest', {
setupFiles: [
setupFilesAfterEnv: [
'<rootDir>/src/setupTest.js',
],
testTimeout: 20000,
Expand Down
18,535 changes: 11,434 additions & 7,101 deletions package-lock.json

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,11 @@
"@edx/browserslist-config": "1.2.0",
"@edx/frontend-build": "13.0.14",
"@edx/paragon": "21.5.6",
"@testing-library/jest-dom": "6.1.5",
"@testing-library/react": "12.1.5",
"@testing-library/react-hooks": "^8.0.1",
"@wojtekmaj/enzyme-adapter-react-17": "0.8.0",
"axios-mock-adapter": "^1.21.3",
"core-js": "3.34.0",
"enzyme": "3.11.0",
"husky": "8.0.3",
"jsdoc": "^4.0.0",
"nodemon": "3.0.2",
Expand Down
4 changes: 3 additions & 1 deletion src/react/AppProvider.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,9 @@ export default function AppProvider({ store, children, wrapWithRouter }) {
<OptionalReduxProvider store={store}>
{wrapWithRouter ? (
<Router basename={basename}>
{children}
<div data-testid="browser-router">
{children}
</div>
</Router>
) : children}
</OptionalReduxProvider>
Expand Down
56 changes: 28 additions & 28 deletions src/react/AppProvider.test.jsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import React from 'react';
import { createStore } from 'redux';
import { mount } from 'enzyme';
import { BrowserRouter as Router } from 'react-router-dom';
import { render } from '@testing-library/react';
import AppProvider from './AppProvider';
import { initialize } from '../initialize';

Expand Down Expand Up @@ -52,56 +51,57 @@ describe('AppProvider', () => {
it('should render its children with a router', () => {
const component = (
<AppProvider store={createStore(state => state)}>
<div>Child One</div>
<div>Child Two</div>
<div className="child">Child One</div>
<div className="child">Child Two</div>
</AppProvider>
);

const wrapper = mount(component);
const list = wrapper.find('div');
expect(wrapper.find(Router).length).toEqual(1);
const wrapper = render(component);
const list = wrapper.container.querySelectorAll('div.child');

expect(wrapper.getByTestId('browser-router')).toBeInTheDocument();
expect(list.length).toEqual(2);
expect(list.at(0).text()).toEqual('Child One');
expect(list.at(1).text()).toEqual('Child Two');
expect(list[0].textContent).toEqual('Child One');
expect(list[1].textContent).toEqual('Child Two');

const reduxProvider = wrapper.find('Provider');
expect(reduxProvider.length).toEqual(1);
const reduxProvider = wrapper.getByTestId('redux-provider');
expect(reduxProvider).toBeInTheDocument();
});

it('should render its children without a router', () => {
const component = (
<AppProvider store={createStore(state => state)} wrapWithRouter={false}>
<div>Child One</div>
<div>Child Two</div>
<div className="child">Child One</div>
<div className="child">Child Two</div>
</AppProvider>
);

const wrapper = mount(component);
const list = wrapper.find('div');
expect(wrapper.find(Router).length).toEqual(0);
const wrapper = render(component);
const list = wrapper.container.querySelectorAll('div.child');
expect(wrapper.queryByTestId('browser-router')).not.toBeInTheDocument();
expect(list.length).toEqual(2);
expect(list.at(0).text()).toEqual('Child One');
expect(list.at(1).text()).toEqual('Child Two');
expect(list[0].textContent).toEqual('Child One');
expect(list[1].textContent).toEqual('Child Two');

const reduxProvider = wrapper.find('Provider');
expect(reduxProvider.length).toEqual(1);
const reduxProvider = wrapper.getByTestId('redux-provider');
expect(reduxProvider).toBeInTheDocument();
});

it('should skip redux Provider if not given a store', () => {
const component = (
<AppProvider>
<div>Child One</div>
<div>Child Two</div>
<div className="child">Child One</div>
<div className="child">Child Two</div>
</AppProvider>
);

const wrapper = mount(component);
const list = wrapper.find('div');
const wrapper = render(component);
const list = wrapper.container.querySelectorAll('div.child');
expect(list.length).toEqual(2);
expect(list.at(0).text()).toEqual('Child One');
expect(list.at(1).text()).toEqual('Child Two');
expect(list[0].textContent).toEqual('Child One');
expect(list[1].textContent).toEqual('Child Two');

const reduxProvider = wrapper.find('Provider');
expect(reduxProvider.length).toEqual(0);
const reduxProvider = wrapper.queryByTestId('redux-provider');
expect(reduxProvider).not.toBeInTheDocument();
});
});
18 changes: 9 additions & 9 deletions src/react/AuthenticatedPageRoute.test.jsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/* eslint-disable react/jsx-no-constructed-context-values */
import React from 'react';
import { mount } from 'enzyme';
import { render } from '@testing-library/react';
import { Route, Routes, MemoryRouter } from 'react-router-dom';
import { getAuthenticatedUser, getLoginRedirectUrl } from '../auth';
import AuthenticatedPageRoute from './AuthenticatedPageRoute';
Expand Down Expand Up @@ -47,7 +47,7 @@ describe('AuthenticatedPageRoute', () => {
</AppContext.Provider>
);
global.location.href = 'http://localhost/authenticated';
mount(component);
render(component);
expect(getLoginRedirectUrl).toHaveBeenCalledWith('http://localhost/authenticated');
expect(sendPageEvent).not.toHaveBeenCalled();
expect(global.location.assign).toHaveBeenCalledWith('http://localhost/login?next=http%3A%2F%2Flocalhost%2Fauthenticated');
Expand Down Expand Up @@ -76,7 +76,7 @@ describe('AuthenticatedPageRoute', () => {
</MemoryRouter>
</AppContext.Provider>
);
mount(component);
render(component);
expect(getLoginRedirectUrl).not.toHaveBeenCalled();
expect(sendPageEvent).not.toHaveBeenCalled();
expect(global.location.assign).toHaveBeenCalledWith('http://localhost/elsewhere');
Expand All @@ -100,13 +100,13 @@ describe('AuthenticatedPageRoute', () => {
</MemoryRouter>
</AppContext.Provider>
);
const wrapper = mount(component);
const wrapper = render(component);

expect(getLoginRedirectUrl).not.toHaveBeenCalled();
expect(global.location.assign).not.toHaveBeenCalled();
expect(sendPageEvent).not.toHaveBeenCalled();
const element = wrapper.find('p');
expect(element.text()).toEqual('Anonymous'); // This is just a sanity check on our setup.
const element = wrapper.container.querySelector('p');
expect(element.textContent).toEqual('Anonymous'); // This is just a sanity check on our setup.
});

it('should render authenticated route if authenticated', () => {
Expand All @@ -125,11 +125,11 @@ describe('AuthenticatedPageRoute', () => {
</MemoryRouter>
</AppContext.Provider>
);
const wrapper = mount(component);
const wrapper = render(component);
expect(getLoginRedirectUrl).not.toHaveBeenCalled();
expect(global.location.assign).not.toHaveBeenCalled();
expect(sendPageEvent).toHaveBeenCalled();
const element = wrapper.find('p');
expect(element.text()).toEqual('Authenticated');
const element = wrapper.container.querySelector('p');
expect(element.textContent).toEqual('Authenticated');
});
});
22 changes: 11 additions & 11 deletions src/react/ErrorBoundary.test.jsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import React from 'react';
import { mount } from 'enzyme';
import { render } from '@testing-library/react';

import ErrorBoundary from './ErrorBoundary';
import ErrorPage from './ErrorPage';
import { initializeMockApp } from '..';

describe('ErrorBoundary', () => {
Expand All @@ -28,10 +27,10 @@ describe('ErrorBoundary', () => {
<div>Yay</div>
</ErrorBoundary>
);
const wrapper = mount(component);
const { container: wrapper } = render(component);

const element = wrapper.find('div');
expect(element.text()).toEqual('Yay');
const element = wrapper.querySelector('div');
expect(element.textContent).toEqual('Yay');
});

it('should render ErrorPage if it has an error', () => {
Expand All @@ -45,7 +44,7 @@ describe('ErrorBoundary', () => {
</ErrorBoundary>
);

mount(component);
render(component);

expect(logError).toHaveBeenCalledTimes(1);
expect(logError).toHaveBeenCalledWith(
Expand All @@ -57,28 +56,29 @@ describe('ErrorBoundary', () => {
});
it('should render the fallback component when an error occurs', () => {
function FallbackComponent() {
return <div>Oops, something went wrong!</div>;
return <div data-testid="fallback-component">Oops, something went wrong!</div>;
}
function ComponentError() {
throw new Error('An error occurred during the click event!');
}
const wrapper = mount(
const wrapper = render(
<ErrorBoundary fallbackComponent={<FallbackComponent />}>
<ComponentError />
</ErrorBoundary>,
);
expect(wrapper.contains(<FallbackComponent />)).toBe(true);

expect(wrapper.queryByTestId('fallback-component')).toBeInTheDocument();
});

it('should render the ErrorPage fallbackComponent is null', () => {
function ComponentError() {
throw new Error('An error occurred during the click event!');
}
const wrapper = mount(
const wrapper = render(
<ErrorBoundary fallbackComponent={null}>
<ComponentError />
</ErrorBoundary>,
);
expect(wrapper.contains(<ErrorPage />)).toBe(true);
expect(wrapper.queryByTestId('error-page')).toBeInTheDocument();
});
});
2 changes: 1 addition & 1 deletion src/react/ErrorPage.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ function ErrorPage({

return (
<IntlProvider locale={locale} messages={getMessages()}>
<Container fluid className="py-5 justify-content-center align-items-start text-center">
<Container fluid className="py-5 justify-content-center align-items-start text-center" data-testid="error-page">
<Row>
<Col>
<p className="text-muted">
Expand Down
4 changes: 3 additions & 1 deletion src/react/OptionalReduxProvider.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@ export default function OptionalReduxProvider({ store, children }) {

return (
<Provider store={store}>
{children}
<div data-testid="redux-provider">
{children}
</div>
</Provider>
);
}
Expand Down
6 changes: 1 addition & 5 deletions src/setupTest.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,7 @@
/* eslint-disable import/no-extraneous-dependencies */
import 'core-js/stable';
import 'regenerator-runtime/runtime';

import Enzyme from 'enzyme';
import Adapter from '@wojtekmaj/enzyme-adapter-react-17';

Enzyme.configure({ adapter: new Adapter() });
import '@testing-library/jest-dom';

// These configuration values are usually set in webpack's EnvironmentPlugin however
// Jest does not use webpack so we need to set these so for testing
Expand Down

0 comments on commit cdbd00d

Please sign in to comment.