diff --git a/src/editors/Editor.test.jsx b/src/editors/Editor.test.jsx
new file mode 100644
index 000000000..8fe08893e
--- /dev/null
+++ b/src/editors/Editor.test.jsx
@@ -0,0 +1,59 @@
+import React from 'react';
+import { mount, shallow } from 'enzyme';
+import { Editor, mapDispatchToProps, supportedEditors } from './Editor';
+import { thunkActions } from './data/redux';
+import * as hooks from './hooks';
+import { blockTypes } from './data/constants/app';
+
+jest.mock('./hooks', () => ({
+ initializeApp: jest.fn(),
+ prepareEditorRef: jest.fn().mockName('prepareEditorRef'),
+}));
+
+jest.mock('./containers/TextEditor/TextEditor', () => 'TextEditor');
+jest.mock('./containers/VideoEditor/VideoEditor', () => 'VideoEditor');
+jest.mock('./containers/ProblemEditor/ProblemEditor', () => 'ProblemEditor');
+jest.mock('./components/EditorFooter', () => 'EditorFooter');
+jest.mock('./components/EditorHeader', () => 'EditorHeader');
+
+const props = {
+ courseId: 'course-v1:edX+DemoX+Demo_Course',
+ blockId: 'block-v1:edX+DemoX+Demo_Course+type@html+block@030e35c4756a4ddc8d40b95fbbfff4d4',
+ studioEndpointUrl: 'fakeurl.com',
+ initialize: jest.fn(),
+};
+
+describe('Editor', () => {
+ describe('snapshots', () => {
+ test('renders no editor when ref isnt ready', () => {
+ hooks.prepareEditorRef.mockImplementationOnce(
+ () => ({ editorRef: null, refReady: false, setEditorRef: jest.fn() }),
+ );
+ expect(shallow()).toMatchSnapshot();
+ });
+ test.each(Object.values(blockTypes))('renders %p editor when ref is ready', (blockType) => {
+ hooks.prepareEditorRef.mockImplementationOnce(
+ () => ({ editorRef: { current: 'ref' }, refReady: true, setEditorRef: jest.fn().mockName('setEditorRef') }),
+ );
+ const wrapper = shallow();
+ if(blockType == 'html'){ // snap just one editor to make viewing easier
+ expect(wrapper).toMatchSnapshot();
+ };
+ expect(wrapper.children().children().at(1).is(supportedEditors[blockType])).toBe(true);
+ });
+ test('presents error message if no relevant editor found and ref ready', () => {
+ hooks.prepareEditorRef.mockImplementationOnce(
+ () => ({ editorRef: { current: 'ref' }, refReady: true, setEditorRef: jest.fn().mockName('setEditorRef') }),
+ );
+ expect(shallow()).toMatchSnapshot();
+ });
+ });
+ describe('mapDispatchToProps', () => {
+ test('initialize from thunkActions.app.initialize', () => {
+ expect(mapDispatchToProps.initialize).toEqual(thunkActions.app.initialize);
+ });
+ });
+});
diff --git a/src/editors/EditorPage.test.jsx b/src/editors/EditorPage.test.jsx
index 155ebbcc5..2cf56dcf5 100644
--- a/src/editors/EditorPage.test.jsx
+++ b/src/editors/EditorPage.test.jsx
@@ -1,39 +1,22 @@
import React from 'react';
-import { render, screen } from '@testing-library/react';
+import { shallow } from 'enzyme';
import EditorPage from './EditorPage';
-test('rendering correctly with expected Input', () => {
- const courseId = 'course-v1:edX+DemoX+Demo_Course';
- const blockType = 'html';
- const blockId = 'block-v1:edX+DemoX+Demo_Course+type@html+block@030e35c4756a4ddc8d40b95fbbfff4d4';
- const studioEndpointUrl = 'fakeurl.com';
- render();
- expect(screen.getByText('Text')).toBeTruthy();
- expect(screen.getByText('Cancel')).toBeTruthy();
- expect(screen.getAllByLabelText('Close')).toBeTruthy();
- expect(screen.getByText('Add To Course')).toBeTruthy();
- expect(screen.getByText('Error: Could Not Load Text Content')).toBeTruthy();
-});
+const props = {
+ courseId: 'course-v1:edX+DemoX+Demo_Course',
+ blockType: 'html',
+ blockId: 'block-v1:edX+DemoX+Demo_Course+type@html+block@030e35c4756a4ddc8d40b95fbbfff4d4',
+ studioEndpointUrl: 'fakeurl.com',
+};
+jest.mock('react-redux', () => ({
+ Provider: 'Provider',
+}));
+jest.mock('./Editor', () => 'Editor');
-test('rendering correctly with expected Error', () => {
- const courseId = 'course-v1:edX+DemoX+Demo_Course';
- const blockType = 'Smelly Garbage Xblock';
- const blockId = 'BadGarbadioU@Garbagefha4521ea ';
- const studioEndpointUrl = 'fakeurl.com';
- render();
- expect(screen.getByText(blockType)).toBeTruthy();
- expect(screen.getByText('Cancel')).toBeTruthy();
- expect(screen.getAllByLabelText('Close')).toBeTruthy();
- expect(screen.getByText('Add To Course')).toBeTruthy();
- expect(screen.getByText('Error: Could Not find Editor')).toBeTruthy();
+describe('Editor Page', () => {
+ describe('snapshots', () => {
+ test('rendering correctly with expected Input', () => {
+ expect(shallow()).toMatchSnapshot();
+ });
+ });
});
diff --git a/src/editors/EditorPageTest.jsx b/src/editors/EditorPageTest.jsx
deleted file mode 100644
index e69de29bb..000000000
diff --git a/src/editors/__snapshots__/Editor.test.jsx.snap b/src/editors/__snapshots__/Editor.test.jsx.snap
new file mode 100644
index 000000000..2cb55231d
--- /dev/null
+++ b/src/editors/__snapshots__/Editor.test.jsx.snap
@@ -0,0 +1,75 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Editor snapshots presents error message if no relevant editor found and ref ready 1`] = `
+
+`;
+
+exports[`Editor snapshots renders "html" editor when ref is ready 1`] = `
+
+`;
+
+exports[`Editor snapshots renders no editor when ref isnt ready 1`] = `
+
+`;
diff --git a/src/editors/__snapshots__/EditorPage.test.jsx.snap b/src/editors/__snapshots__/EditorPage.test.jsx.snap
new file mode 100644
index 000000000..ad05865d2
--- /dev/null
+++ b/src/editors/__snapshots__/EditorPage.test.jsx.snap
@@ -0,0 +1,22 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Editor Page snapshots rendering correctly with expected Input 1`] = `
+
+
+
+`;
diff --git a/src/editors/components/EditorFooter/index.jsx b/src/editors/components/EditorFooter/index.jsx
index c2b3de3ca..fa918f3df 100644
--- a/src/editors/components/EditorFooter/index.jsx
+++ b/src/editors/components/EditorFooter/index.jsx
@@ -10,7 +10,7 @@ import {
Toast,
} from '@edx/paragon';
import { FormattedMessage } from '@edx/frontend-platform/i18n';
-import { nullMethod, saveTextBlock, navigateCallback } from '../../hooks';
+import { nullMethod, saveBlock, navigateCallback } from '../../hooks';
import { RequestKeys } from '../../data/constants/requests';
import { selectors, thunkActions } from '../../data/redux';
@@ -18,7 +18,7 @@ import { selectors, thunkActions } from '../../data/redux';
import messages from '../messages';
import * as module from '.';
-export const handleSaveClicked = (props) => () => saveTextBlock(props);
+export const handleSaveClicked = (props) => () => saveBlock(props);
export const handleCancelClicked = ({ returnUrl }) => navigateCallback(returnUrl);
export const EditorFooter = ({
diff --git a/src/editors/components/EditorFooter/index.test.jsx b/src/editors/components/EditorFooter/index.test.jsx
index b5e6cb9b2..98073d3ce 100644
--- a/src/editors/components/EditorFooter/index.test.jsx
+++ b/src/editors/components/EditorFooter/index.test.jsx
@@ -3,7 +3,7 @@ import { shallow } from 'enzyme';
import * as module from './index';
import { selectors, thunkActions } from '../../data/redux';
import { RequestKeys } from '../../data/constants/requests';
-import { saveTextBlock, navigateCallback } from '../../hooks';
+import { saveBlock, navigateCallback } from '../../hooks';
jest.mock('../../data/redux', () => ({
thunkActions: {
@@ -30,7 +30,7 @@ jest.mock('.', () => ({
}));
jest.mock('../../hooks', () => ({
- saveTextBlock: jest.fn(),
+ saveBlock: jest.fn(),
navigateCallback: jest.fn(),
nullMethod: jest.fn().mockName('nullMethod'),
}));
@@ -45,10 +45,10 @@ describe('EditorFooter', () => {
};
describe('behavior', () => {
const realmodule = jest.requireActual('./index');
- test('handleSaveClicked calls saveTextBlock', () => {
+ test('handleSaveClicked calls saveBlock', () => {
const createdCallback = realmodule.handleSaveClicked(props);
createdCallback();
- expect(saveTextBlock).toHaveBeenCalled();
+ expect(saveBlock).toHaveBeenCalled();
});
test('handleCancelClicked calls navigateCallback', () => {
realmodule.handleCancelClicked({ returnUrl: props.returnUrl });
diff --git a/src/editors/hooks.js b/src/editors/hooks.js
index e9f6fcea9..6e6c9d69c 100644
--- a/src/editors/hooks.js
+++ b/src/editors/hooks.js
@@ -1,6 +1,7 @@
import {
useRef, useEffect, useCallback, useState,
} from 'react';
+import * as module from './hooks';
export const initializeApp = ({ initialize, data }) => useEffect(() => initialize(data), []);
@@ -18,14 +19,14 @@ export const navigateTo = (destination) => {
window.location.assign(destination);
};
-export const navigateCallback = (destination) => () => navigateTo(destination);
+export const navigateCallback = (destination) => () => module.navigateTo(destination);
-export const saveTextBlock = ({
+export const saveBlock = ({
editorRef,
returnUrl,
- saveBlock,
+ saveFunction,
}) => {
- saveBlock({
+ saveFunction({
returnToUnit: module.navigateCallback(returnUrl),
content: editorRef.current.getContent(),
});
diff --git a/src/editors/hooks.test.jsx b/src/editors/hooks.test.jsx
new file mode 100644
index 000000000..a81e7586d
--- /dev/null
+++ b/src/editors/hooks.test.jsx
@@ -0,0 +1,101 @@
+import { useEffect, updateState } from 'react';
+import * as module from './hooks';
+
+jest.mock('react', () => {
+ const updateStateMock = jest.fn();
+ return {
+ updateState: updateStateMock,
+ useState: jest.fn(val => ([{ state: val }, (newVal) => updateStateMock({ val, newVal })])),
+ useRef: jest.fn(val => ({ current: val })),
+ useEffect: jest.fn(),
+ useCallback: (cb, prereqs) => ({ cb, prereqs }),
+ };
+});
+describe('hooks', () => {
+ const locationTemp = window.location;
+ beforeAll(() => {
+ delete window.location;
+ window.location = {
+ assign: jest.fn(),
+ };
+ });
+ afterAll(() => {
+ window.location = locationTemp;
+ });
+ describe('initializeApp', () => {
+ test('calls provided function with provided data as args when useEffect is called', () => {
+ const mockIntialize = jest.fn(val => (val));
+ const fakedata = { some: 'data' };
+ module.initializeApp({ initialize: mockIntialize, data: fakedata });
+ expect(mockIntialize).not.toHaveBeenCalledWith(fakedata);
+ const [cb, prereqs] = useEffect.mock.calls[0];
+ expect(prereqs).toStrictEqual([]);
+ cb();
+ expect(mockIntialize).toHaveBeenCalledWith(fakedata);
+ });
+ });
+ describe('prepareEditorRef', () => {
+ let output;
+ beforeEach(() => {
+ output = module.prepareEditorRef();
+ });
+ afterEach(() => {
+ jest.clearAllMocks();
+ });
+ test('sets refReady to false by default, ref is null', () => {
+ expect(output.refReady.state).toBe(false);
+ expect(output.editorRef.current).toBe(null);
+ });
+ test('when useEffect triggers, refReady is set to true', () => {
+ expect(updateState).not.toHaveBeenCalled();
+ const [cb, prereqs] = useEffect.mock.calls[0];
+ expect(prereqs).toStrictEqual([]);
+ cb();
+ expect(updateState).toHaveBeenCalledWith({ newVal: true, val: false });
+ });
+ test('calling setEditorRef sets the ref value', () => {
+ const fakeEditor = { editor: 'faKe Editor' };
+ expect(output.editorRef.current).not.toBe(fakeEditor);
+ output.setEditorRef.cb(fakeEditor);
+ expect(output.editorRef.current).toBe(fakeEditor);
+ });
+ });
+ describe('navigateTo', () => {
+ const destination = 'HoME';
+ beforeEach(() => {
+ module.navigateTo(destination);
+ });
+ test('it calls window assign', () => {
+ expect(window.location.assign).toHaveBeenCalled();
+ });
+ });
+ describe('navigateCallback', () => {
+ let output;
+ const destination = 'hOmE';
+ beforeEach(() => {
+ output = module.navigateCallback(destination);
+ });
+ test('it calls navigateTo with output destination', () => {
+ const spy = jest.spyOn(module, 'navigateTo');
+ output();
+ expect(spy).toHaveBeenCalledWith(destination);
+ });
+ });
+ describe('saveBlock', () => {
+ test('saveBlock calls the save function provided with created nav callback and content', () => {
+ const mockNavCallback = (returnUrl) => ({ navigateCallback: returnUrl });
+ jest.spyOn(module, 'navigateCallback').mockImplementationOnce(mockNavCallback);
+ const content = { some: 'content' };
+ const args = {
+ editorRef: { current: { getContent: () => content } },
+ returnUrl: 'rEtUrNUrl',
+ saveFunction: jest.fn(),
+ };
+ module.saveBlock(args);
+ expect(args.saveFunction).toHaveBeenCalledWith({
+ returnToUnit: mockNavCallback(args.returnUrl),
+ content,
+ });
+ });
+ });
+});