diff --git a/package-lock.json b/package-lock.json index 6d4708ae2..605c13a07 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3714,14 +3714,15 @@ } }, "@edx/frontend-lib-content-components": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@edx/frontend-lib-content-components/-/frontend-lib-content-components-1.1.1.tgz", - "integrity": "sha512-mWfWCKj+eKgWhjgoOIEye/0+kZwWRVxXhC4NwCtgW+NHfFI/rHVPOraE2NOoNH+ml4XDLmVEjz7s93OIyyV8Nw==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@edx/frontend-lib-content-components/-/frontend-lib-content-components-1.2.0.tgz", + "integrity": "sha512-I3FY2qxzxNTvs+snltbZ/QIFl+oTNTb9pXUOAZx+ObKEoHjFvgVwpXhjbMOM5ZFGErpUfTDfTzkW0vpyB9854w==", "requires": { "@tinymce/tinymce-react": "^3.13.0", "babel-polyfill": "6.26.0", "react-responsive": "8.2.0", - "react-transition-group": "4.4.2" + "react-transition-group": "4.4.2", + "tinymce": "^5.10.2" }, "dependencies": { "react-responsive": { @@ -24068,9 +24069,9 @@ "integrity": "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==" }, "tinymce": { - "version": "5.10.2", - "resolved": "https://registry.npmjs.org/tinymce/-/tinymce-5.10.2.tgz", - "integrity": "sha512-5QhnZ6c8F28fYucLLc00MM37fZoAZ4g7QCYzwIl38i5TwJR5xGqzOv6YMideyLM4tytCzLCRwJoQen2LI66p5A==" + "version": "5.10.3", + "resolved": "https://registry.npmjs.org/tinymce/-/tinymce-5.10.3.tgz", + "integrity": "sha512-O59ssHNnujWvSk5Gt8hIGrdNCMKVWVQv9F8siAgLTRgTh0t3NDHrP1UlLtCxArUi9DPWZvlBeUz8D5fJTu7vnA==" }, "tmp": { "version": "0.0.33", diff --git a/package.json b/package.json index bef6051a1..09367f968 100644 --- a/package.json +++ b/package.json @@ -37,7 +37,7 @@ "dependencies": { "@edx/brand": "npm:@edx/brand-openedx@1.1.0", "@edx/frontend-component-footer": "10.1.6", - "@edx/frontend-lib-content-components": "1.1.1", + "@edx/frontend-lib-content-components": "1.2.0", "@edx/frontend-platform": "1.14.0", "@edx/paragon": "16.17.0", "@fortawesome/fontawesome-svg-core": "1.2.28", diff --git a/src/CourseAuthoringPage.jsx b/src/CourseAuthoringPage.jsx index 17a076259..ad1c548df 100644 --- a/src/CourseAuthoringPage.jsx +++ b/src/CourseAuthoringPage.jsx @@ -3,6 +3,9 @@ import PropTypes from 'prop-types'; import Footer from '@edx/frontend-component-footer'; import { useDispatch, useSelector } from 'react-redux'; +import { + useLocation, +} from 'react-router-dom'; import Header from './studio-header/Header'; import { fetchCourseDetail } from './data/thunks'; import { useModel } from './generic/model-store'; @@ -46,9 +49,14 @@ export default function CourseAuthoringPage({ courseId, children }) { ); + const { pathname } = useLocation(); return (
- {inProgress ? : } + {/* While V2 Editors are tempoarily served from thier own pages + using url pattern containing /editor/, + we shouldn't have the header and footer on these pages. + This functionality will be removed in TNL-9591 */} + {inProgress ? !pathname.includes('/editor/') && : } {children} {!inProgress && }
diff --git a/src/CourseAuthoringPage.test.jsx b/src/CourseAuthoringPage.test.jsx index d3953d9e1..d2f74e97f 100644 --- a/src/CourseAuthoringPage.test.jsx +++ b/src/CourseAuthoringPage.test.jsx @@ -14,6 +14,13 @@ import { executeThunk } from './utils'; import { fetchCourseApps } from './pages-and-resources/data/thunks'; const courseId = 'course-v1:edX+TestX+Test_Course'; +let mockPathname = '/evilguy/'; +jest.mock('react-router-dom', () => ({ + ...jest.requireActual('react-router-dom'), + useLocation: () => ({ + pathname: mockPathname, + }), +})); let axiosMock; let store; let container; @@ -61,3 +68,56 @@ describe('DiscussionsSettings', () => { expect(queryByTestId(container, 'permissionDeniedAlert')).toBeInTheDocument(); }); }); + +describe('Editor Pages Load no header', () => { + const mockStoreSuccess = async () => { + const apiBaseUrl = getConfig().STUDIO_BASE_URL; + const courseAppsApiUrl = `${apiBaseUrl}/api/course_apps/v1/apps`; + axiosMock.onGet(`${courseAppsApiUrl}/${courseId}`).reply(200, { + response: { status: 200 }, + }); + await executeThunk(fetchCourseApps(courseId), store.dispatch); + }; + beforeEach(() => { + initializeMockApp({ + authenticatedUser: { + userId: 3, + username: 'abc123', + administrator: true, + roles: [], + }, + }); + store = initializeStore(); + axiosMock = new MockAdapter(getAuthenticatedHttpClient()); + }); + test('renders no loading wheel on editor pages', async () => { + mockPathname = '/editor/'; + await mockStoreSuccess(); + const wrapper = render( + + + + + + + + , + ); + expect(wrapper.queryByRole('status')).not.toBeInTheDocument(); + }); + test('renders loading wheel on non editor pages', async () => { + mockPathname = '/evilguy/'; + await mockStoreSuccess(); + const wrapper = render( + + + + + + + + , + ); + expect(wrapper.queryByRole('status')).toBeInTheDocument(); + }); +}); diff --git a/src/setupTest.js b/src/setupTest.js index 5bffda04c..061bc866c 100755 --- a/src/setupTest.js +++ b/src/setupTest.js @@ -4,6 +4,22 @@ import '@testing-library/jest-dom'; import '@testing-library/jest-dom/extend-expect'; import ReactDOM from 'react-dom'; +/* need to mock window for tinymce on import, as it is JSDOM incompatible */ + +Object.defineProperty(window, 'matchMedia', { + writable: true, + value: jest.fn().mockImplementation(query => ({ + matches: false, + media: query, + onchange: null, + addListener: jest.fn(), // Deprecated + removeListener: jest.fn(), // Deprecated + addEventListener: jest.fn(), + removeEventListener: jest.fn(), + dispatchEvent: jest.fn(), + })), +}); + // Modal creates a portal. Overriding ReactDOM.createPortal allows portals to be tested in jest. ReactDOM.createPortal = node => node;