-`;
diff --git a/src/data/store.js b/src/data/store.js
index dfb73b4..47e401e 100755
--- a/src/data/store.js
+++ b/src/data/store.js
@@ -11,7 +11,7 @@ import selectors from './selectors';
import reducers from './reducers';
import eventsMap from './services/segment/mapping';
-export const createStore = () => {
+export const createStore = (preloadedState = undefined) => {
const loggerMiddleware = createLogger();
const middleware = [thunkMiddleware, loggerMiddleware];
@@ -22,6 +22,7 @@ export const createStore = () => {
const store = redux.createStore(
reducers,
composeWithDevTools(redux.applyMiddleware(...middleware)),
+ preloadedState,
);
/**
diff --git a/src/head/Head.test.jsx b/src/head/Head.test.jsx
index c765c05..11bcdef 100644
--- a/src/head/Head.test.jsx
+++ b/src/head/Head.test.jsx
@@ -1,29 +1,24 @@
import React from 'react';
-import { shallow } from '@edx/react-unit-test-utils';
-import { getConfig } from '@edx/frontend-platform';
+import { mockConfigs } from 'setupTest';
+import { initializeMocks, render, waitFor } from 'testUtilsExtra';
+
import Head from './Head';
-jest.mock('react-helmet', () => ({
- Helmet: () => 'Helmet',
-}));
-jest.mock('@edx/frontend-platform', () => ({
- getConfig: jest.fn(),
-}));
-
-const config = {
- SITE_NAME: 'test-site-name',
- FAVICON_URL: 'test-favicon-url',
-};
-
-getConfig.mockReturnValue(config);
+jest.unmock('@openedx/paragon');
+jest.unmock('@edx/frontend-platform/i18n');
+jest.unmock('react');
describe('Head', () => {
- it('should match render title tag and favicon with the site configuration values', () => {
- const el = shallow();
- const title = el.instance.findByType('title')[0];
- const link = el.instance.findByType('link')[0];
- expect(title.children[0].el).toEqual(`Gradebook | ${config.SITE_NAME}`);
- expect(link.props.rel).toEqual('shortcut icon');
- expect(link.props.href).toEqual(config.FAVICON_URL);
+ it('should match render title tag and favicon with the site configuration values', async () => {
+ initializeMocks();
+ render(
);
+
+ await waitFor(() => {
+ expect(document.title).toBe(`Gradebook | ${mockConfigs.SITE_NAME}`);
+ });
+
+ const favicon = document.querySelector('link[rel="shortcut icon"]');
+ expect(favicon).toBeInTheDocument();
+ expect(favicon.href).toBe(mockConfigs.FAVICON_URL);
});
});
diff --git a/src/setupTest.js b/src/setupTest.js
index 4aa6180..e8b5b1d 100755
--- a/src/setupTest.js
+++ b/src/setupTest.js
@@ -1,10 +1,22 @@
import '@testing-library/jest-dom';
+export const mockConfigs = {
+ SITE_NAME: 'test-site-name',
+ FAVICON_URL: 'http://localhost:18000/favicon.ico',
+ LMS_BASE_URL: 'http://localhost:18000',
+};
// 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
-process.env.LMS_BASE_URL = 'http://localhost:18000';
-process.env.SITE_NAME = 'localhost';
-process.env.FAVICON_URL = 'http://localhost:18000/favicon.ico';
+// many are here to prevent warnings on the tests
+process.env.LMS_BASE_URL = mockConfigs.LMS_BASE_URL;
+process.env.SITE_NAME = mockConfigs.SITE_NAME;
+process.env.FAVICON_URL = mockConfigs.FAVICON_URL;
+process.env.BASE_URL = mockConfigs.LMS_BASE_URL;
+process.env.LOGIN_URL = `${mockConfigs.LMS_BASE_URL}/login`;
+process.env.LOGOUT_URL = `${mockConfigs.LMS_BASE_URL}/logout`;
+process.env.REFRESH_ACCESS_TOKEN_ENDPOINT = `${mockConfigs.LMS_BASE_URL}/refresh_access_token`;
+process.env.ACCESS_TOKEN_COOKIE_NAME = 'edx';
+process.env.CSRF_TOKEN_API_PATH = 'TOKEN_PATH';
jest.mock('@edx/frontend-platform/i18n', () => {
const i18n = jest.requireActual('@edx/frontend-platform/i18n');
diff --git a/src/testUtilsExtra.jsx b/src/testUtilsExtra.jsx
new file mode 100644
index 0000000..d89b7fb
--- /dev/null
+++ b/src/testUtilsExtra.jsx
@@ -0,0 +1,145 @@
+/* eslint-disable import/no-extraneous-dependencies */
+
+// This a file with extra things required for being able to mock services etc...
+// Normally this is on the `testUtils`file, but given the current state of the tests
+// It creates a non trivial circular dependency, which is avoided by not having the
+// mocks that currently exists on testUtils, and that will be gone after the DEPR of react-unit-test-utils
+// so to wrapup the migration this file needs to be integrated in testUtils as the last step.
+import React from 'react';
+import PropTypes from 'prop-types';
+import {
+ MemoryRouter, Route, Routes, generatePath,
+} from 'react-router';
+import { AppProvider } from '@edx/frontend-platform/react';
+import { render } from '@testing-library/react';
+import { IntlProvider } from '@edx/frontend-platform/i18n';
+import { initializeMockApp } from '@edx/frontend-platform';
+
+import { createStore } from './data/store';
+
+/** @deprecated Use React Query and/or regular React Context instead of redux */
+let reduxStore;
+
+/**
+ * This component works together with the custom `render()` method we have in
+ * this file to provide whatever react-router context you need for your
+ * component.
+ *
+ * In the simplest case, you don't need to worry about the router at all, so
+ * just render your component using `render()`.
+ *
+ * The next simplest way to use it is to specify `path` (the route matching rule
+ * that is normally used to determine when to show the component or its parent
+ * page) and `params` like this:
+ *
+ * ```
+ * render(, { path: '/library/:libraryId/*', params: { libraryId: 'lib:Axim:testlib' } });
+ * ```
+ *
+ * In this case, components that use the `useParams` hook will get the right
+ * library ID, and we don't even have to mock anything.
+ *
+ * In other cases, such as when you have routes inside routes, you'll need to
+ * set the router's `initialEntries` (URL history) prop yourself, like this:
+ *
+ * ```
+ * render(, {
+ * path: '/library/:libraryId/*',
+ * // The root component is mounted on the above path, as it is in the "real"
+ * // MFE. But to access the 'settings' sub-route/component for this test, we
+ * // need tospecify the URL like this:
+ * routerProps: { initialEntries: [`/library/${libraryId}/settings`] },
+ * });
+ * ```
+ */
+const RouterAndRoute = ({
+ children,
+ path = '/',
+ params = {},
+ routerProps = {},
+}) => {
+ if (Object.entries(params).length > 0 || path !== '/') {
+ const newRouterProps = { ...routerProps };
+ if (!routerProps.initialEntries) {
+ // Substitute the params into the URL so '/library/:libraryId' becomes '/library/lib:org:123'
+ let pathWithParams = generatePath(path, params);
+ if (pathWithParams.endsWith('/*')) {
+ // Some routes (that contain child routes) need to end with /* in the but not in the router
+ pathWithParams = pathWithParams.substring(0, pathWithParams.length - 1);
+ }
+ newRouterProps.initialEntries = [pathWithParams];
+ }
+ return (
+
+
+
+
+
+ );
+ }
+ return (
+ {children}
+ );
+};
+
+RouterAndRoute.propTypes = {
+ children: PropTypes.node,
+ path: PropTypes.string,
+ params: PropTypes.shape({}),
+ routerProps: PropTypes.shape({}),
+};
+
+export const makeWrapper = ({ extraWrapper, ...routeArgs } = {}) => {
+ // eslint-disable-next-line react/prop-types
+ const AllTheProviders = ({ children }) => (
+
+
+
+ {extraWrapper ? React.createElement(extraWrapper, undefined, children) : children}
+
+
+
+ );
+ return AllTheProviders;
+};
+
+/**
+ * Same as render() from `@testing-library/react` but this one provides all the
+ * wrappers our React components need to render properly.
+ */
+function customRender(ui, options = {}) {
+ return render(ui, { wrapper: makeWrapper(options) });
+}
+
+const defaultUser = {
+ userId: 3,
+ username: 'abc123',
+ administrator: true,
+ roles: [],
+};
+
+/**
+ * Initialize common mocks that many of our React components will require.
+ *
+ * This should be called within each test case, or in `beforeEach()`.
+ *
+ * Returns the new `axiosMock` in case you need to mock out axios requests.
+ */
+export function initializeMocks({ user = defaultUser, initialState = undefined } = {}) {
+ initializeMockApp({
+ authenticatedUser: user,
+ });
+ reduxStore = createStore(initialState);
+
+ // Clear the call counts etc. of all mocks. This doesn't remove the mock's effects; just clears their history.
+ jest.clearAllMocks();
+
+ return {
+ reduxStore,
+ };
+}
+
+export * from '@testing-library/react';
+export {
+ customRender as render,
+};