From 042246be86f0b226c5439801effe58669c74087a Mon Sep 17 00:00:00 2001
From: Raymond Zhou <56318341+rayzhou-bit@users.noreply.github.com>
Date: Fri, 25 Feb 2022 12:15:13 -0500
Subject: [PATCH] Test: editor header component (#20)
* test: header tests start
* test: EditableHeader test ready for review 1
* test: editor header tests complete
* test: fixing up nits
* test: ben's corrections
---
.../EditorHeader/EditableHeader.test.jsx | 29 +++++
.../components/EditorHeader/HeaderTitle.jsx | 9 +-
.../EditorHeader/HeaderTitle.test.jsx | 86 +++++++++++++++
.../EditableHeader.test.jsx.snap | 37 +++++++
.../__snapshots__/HeaderTitle.test.jsx.snap | 45 ++++++++
.../__snapshots__/index.test.jsx.snap | 24 +++++
src/editors/components/EditorHeader/index.jsx | 6 +-
.../components/EditorHeader/index.test.jsx | 100 +++++++++---------
.../containers/TextEditor/TextEditor.jsx | 8 +-
src/setupTest.js | 4 +-
10 files changed, 284 insertions(+), 64 deletions(-)
create mode 100644 src/editors/components/EditorHeader/EditableHeader.test.jsx
create mode 100644 src/editors/components/EditorHeader/HeaderTitle.test.jsx
create mode 100644 src/editors/components/EditorHeader/__snapshots__/EditableHeader.test.jsx.snap
create mode 100644 src/editors/components/EditorHeader/__snapshots__/HeaderTitle.test.jsx.snap
create mode 100644 src/editors/components/EditorHeader/__snapshots__/index.test.jsx.snap
diff --git a/src/editors/components/EditorHeader/EditableHeader.test.jsx b/src/editors/components/EditorHeader/EditableHeader.test.jsx
new file mode 100644
index 000000000..31cad7204
--- /dev/null
+++ b/src/editors/components/EditorHeader/EditableHeader.test.jsx
@@ -0,0 +1,29 @@
+import React from 'react';
+import { shallow } from 'enzyme';
+import { Icon, Form } from '@edx/paragon';
+import { Edit } from '@edx/paragon/icons';
+import * as module from './EditableHeader';
+
+describe('EditableHeader', () => {
+ const props = {
+ handleChange: jest.fn().mockName('args.handleChange'),
+ updateTitle: jest.fn().mockName('args.updateTitle'),
+ handleKeyDown: jest.fn().mockName('args.handleKeyDown'),
+ inputRef: jest.fn().mockName('args.inputRef'),
+ localTitle: 'test-title-text',
+ };
+ let el;
+ beforeEach(() => {
+ el = shallow();
+ });
+
+ describe('snapshot', () => {
+ test('snapshot', () => {
+ expect(el).toMatchSnapshot();
+ });
+ test('displays Edit Icon', () => {
+ const formControl = el.find(Form.Control);
+ expect(formControl.props().trailingInputElement).toMatchObject();
+ });
+ });
+});
diff --git a/src/editors/components/EditorHeader/HeaderTitle.jsx b/src/editors/components/EditorHeader/HeaderTitle.jsx
index 49c3020f1..7d0ac0939 100644
--- a/src/editors/components/EditorHeader/HeaderTitle.jsx
+++ b/src/editors/components/EditorHeader/HeaderTitle.jsx
@@ -7,9 +7,9 @@ import { Edit } from '@edx/paragon/icons';
import { FormattedMessage } from '@edx/frontend-platform/i18n';
import { actions, selectors } from '../../data/redux';
+import { localTitleHooks } from './hooks';
import messages from '../messages';
import EditableHeader from './EditableHeader';
-import { localTitleHooks } from './hooks';
export const HeaderTitle = ({
editorRef,
@@ -19,7 +19,6 @@ export const HeaderTitle = ({
}) => {
if (!isInitialized) { return ; }
- console.log('HeaderTitle');
const {
inputRef,
isEditing,
@@ -53,13 +52,13 @@ export const HeaderTitle = ({
{localTitle}
);
diff --git a/src/editors/components/EditorHeader/HeaderTitle.test.jsx b/src/editors/components/EditorHeader/HeaderTitle.test.jsx
new file mode 100644
index 000000000..6ff64689a
--- /dev/null
+++ b/src/editors/components/EditorHeader/HeaderTitle.test.jsx
@@ -0,0 +1,86 @@
+import React from 'react';
+import { shallow } from 'enzyme';
+
+import * as module from './HeaderTitle';
+import { actions, selectors } from '../../data/redux';
+import { localTitleHooks } from './hooks';
+
+jest.mock('../../data/redux', () => ({
+ actions: {
+ app: {
+ setBlockTitle: jest.fn().mockName('actions.app.setBlockTitle'),
+ },
+ },
+ selectors: {
+ app: {
+ typeHeader: jest.fn(state => ({ typeHeader: state })),
+ isInitialized: jest.fn(state => ({ studioEndpointUrl: state })),
+ },
+ },
+}));
+
+jest.mock('./hooks', () => ({
+ localTitleHooks: jest.fn(),
+}));
+
+describe('HeaderTitle', () => {
+ const props = {
+ editorRef: jest.fn().mockName('args.editorRef'),
+ isInitialized: false,
+ setBlockTitle: jest.fn().mockName('args.setBlockTitle'),
+ typeHeader: 'html',
+ };
+ const localTitleHooksProps = {
+ inputRef: jest.fn().mockName('localTitleHooks.inputRef'),
+ isEditing: false,
+ handleChange: jest.fn().mockName('localTitleHooks.handleChange'),
+ handleKeyDown: jest.fn().mockName('localTitleHooks.handleKeyDown'),
+ localTitle: 'TeST LocALtitLE',
+ startEditing: jest.fn().mockName('localTitleHooks.startEditing'),
+ updateTitle: jest.fn().mockName('localTitleHooks.updateTitle'),
+ };
+
+ describe('behavior', () => {
+ it(' calls localTitleHooks with initialization args', () => {
+ localTitleHooks.mockReturnValue(localTitleHooksProps);
+ shallow();
+ expect(localTitleHooks).toHaveBeenCalledWith({
+ editorRef: props.editorRef,
+ setBlockTitle: props.setBlockTitle,
+ typeHeader: props.typeHeader,
+ });
+ });
+ });
+
+ describe('snapshots', () => {
+ test('not initialized', () => {
+ expect(shallow()).toMatchSnapshot();
+ });
+ test('initialized', () => {
+ localTitleHooks.mockReturnValue(hookProps);
+ expect(shallow()).toMatchSnapshot();
+ });
+ test('editing', () => {
+ localTitleHooks.mockReturnValue({ ...hookProps, isEditing: true });
+ expect(shallow()).toMatchSnapshot();
+ });
+ });
+
+ describe('mapStateToProps', () => {
+ const testState = { T: 'esting', S: 'tate' };
+ test('typeHeader from app.typeHeader', () => {
+ expect(module.mapStateToProps(testState).typeHeader)
+ .toEqual(selectors.app.typeHeader(testState));
+ });
+ test('isInitialized from app.isInitialized', () => {
+ expect(module.mapStateToProps(testState).isInitialized)
+ .toEqual(selectors.app.isInitialized(testState));
+ });
+ });
+
+ describe('mapDispatchToProps', () => {
+ test('setBlockTitle from actions.app.setBlockTitle', () => {
+ expect(module.mapDispatchToProps.setBlockTitle).toEqual(actions.app.setBlockTitle);
+ });
+ });
+});
diff --git a/src/editors/components/EditorHeader/__snapshots__/EditableHeader.test.jsx.snap b/src/editors/components/EditorHeader/__snapshots__/EditableHeader.test.jsx.snap
new file mode 100644
index 000000000..bf9018fed
--- /dev/null
+++ b/src/editors/components/EditorHeader/__snapshots__/EditableHeader.test.jsx.snap
@@ -0,0 +1,37 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`EditableHeader snapshot 1`] = `
+
+
+ }
+ value="test-title-text"
+ />
+
+`;
+
+exports[`EditableHeader snapshot snapshot 1`] = `
+
+
+ }
+ value="test-title-text"
+ />
+
+`;
diff --git a/src/editors/components/EditorHeader/__snapshots__/HeaderTitle.test.jsx.snap b/src/editors/components/EditorHeader/__snapshots__/HeaderTitle.test.jsx.snap
new file mode 100644
index 000000000..a9ef5e0c6
--- /dev/null
+++ b/src/editors/components/EditorHeader/__snapshots__/HeaderTitle.test.jsx.snap
@@ -0,0 +1,45 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`HeaderTitle snapshots editing 1`] = `
+
+`;
+
+exports[`HeaderTitle snapshots initialized 1`] = `
+
+
+ TeST LocALtitLE
+
+
+
+`;
+
+exports[`HeaderTitle snapshots not initialized 1`] = `
+
+`;
diff --git a/src/editors/components/EditorHeader/__snapshots__/index.test.jsx.snap b/src/editors/components/EditorHeader/__snapshots__/index.test.jsx.snap
new file mode 100644
index 000000000..f806986ed
--- /dev/null
+++ b/src/editors/components/EditorHeader/__snapshots__/index.test.jsx.snap
@@ -0,0 +1,24 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[` 1`] = `
+
+`;
diff --git a/src/editors/components/EditorHeader/index.jsx b/src/editors/components/EditorHeader/index.jsx
index f8f0179f9..f94db3baa 100644
--- a/src/editors/components/EditorHeader/index.jsx
+++ b/src/editors/components/EditorHeader/index.jsx
@@ -2,9 +2,7 @@ import React from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
-import {
- ActionRow, IconButton, Icon, ModalDialog,
-} from '@edx/paragon';
+import { ActionRow, IconButton, Icon, ModalDialog } from '@edx/paragon';
import { Close } from '@edx/paragon/icons';
import { selectors } from '../../data/redux';
@@ -12,7 +10,7 @@ import * as appHooks from '../../hooks';
import HeaderTitle from './HeaderTitle';
-const EditorHeader = ({
+export const EditorHeader = ({
returnUrl,
}) => (
diff --git a/src/editors/components/EditorHeader/index.test.jsx b/src/editors/components/EditorHeader/index.test.jsx
index f9acbd507..d599e27d9 100644
--- a/src/editors/components/EditorHeader/index.test.jsx
+++ b/src/editors/components/EditorHeader/index.test.jsx
@@ -1,58 +1,56 @@
import React from 'react';
-import { render, screen } from '@testing-library/react';
-import userEvent from '@testing-library/user-event';
-import EditorHeader from './EditorHeader';
-import EditorPageContext from './EditorPageContext';
-import { ActionStates } from './data/constants';
+import { shallow } from 'enzyme';
-const locationTemp = window.location;
-beforeEach(() => {
- delete window.location;
- window.location = {
- assign: jest.fn(),
- };
-});
-afterAll(() => {
- window.location = locationTemp;
-});
+import { IconButton } from '@edx/paragon';
+import * as module from './index';
+import { selectors } from '../../data/redux';
+import * as appHooks from '../../hooks';
-test('Rendering And Click Close Button: Does not Navigate off of Page When Loading', () => {
- const title = 'An Awesome Block';
- const context = {
- unitUrlLoading: ActionStates.IN_PROGRESS,
- };
- render(
-
-
- ,
- );
- expect(screen.getByText(title)).toBeTruthy();
- expect(screen.getByLabelText('Close')).toBeTruthy();
- userEvent.click(screen.getByLabelText('Close'));
- expect(window.location.assign).not.toHaveBeenCalled();
-});
+jest.mock('.', () => ({
+ __esModule: true, // Use it when dealing with esModules
+ ...jest.requireActual('./index'),
+ handleCloseClicked: jest.fn(args => ({ handleCloseClicked: args })),
+}));
-test('Rendering And Click Button: Loaded Navigates Away', () => {
- const title = 'An Awesome Block';
- const context = {
- unitUrlLoading: ActionStates.FINISHED,
- unitUrl: {
- data: {
- ancestors:
- [
- { id: 'fakeblockid' },
- ],
- },
+jest.mock('../../data/redux', () => ({
+ selectors: {
+ app: {
+ returnUrl: jest.fn().mockName('actions.app.returnUrl'),
},
- studioEndpointUrl: 'Testurl',
+ },
+}));
+
+jest.mock('../../hooks', () => ({
+ navigateCallback: jest.fn(),
+}));
+
+jest.mock('./HeaderTitle', () => 'HeaderTitle');
+
+describe('Editor Header index', () => {
+ const props = {
+ returnUrl: 'TeST-ReTurNurL',
};
- render(
-
-
- ,
- );
- expect(screen.getByText(title)).toBeTruthy();
- expect(screen.getByLabelText('Close')).toBeTruthy();
- userEvent.click(screen.getByLabelText('Close'));
- expect(window.location.assign).toHaveBeenCalled();
+ const { EditorHeader } = module;
+ let el;
+ el = shallow();
+
+ describe('behavior', () => {
+ test('IconButton onClick calls navigateCallback', () => {
+ const iconButtonControl = el.find(IconButton);
+ iconButtonControl.simulate('click');
+ expect(appHooks.navigateCallback).toHaveBeenCalledWith(props.returnUrl);
+ });
+ });
+
+ describe('snapshot', () => {
+ expect(el).toMatchSnapshot();
+ });
+
+ describe('mapStateToProps', () => {
+ const testState = { T: 'est', S: 'tate' };
+ test('returnUrl from app.returnUrl', () => {
+ expect(module.mapStateToProps(testState).returnUrl)
+ .toEqual(selectors.app.returnUrl(testState));
+ });
+ });
});
diff --git a/src/editors/containers/TextEditor/TextEditor.jsx b/src/editors/containers/TextEditor/TextEditor.jsx
index c4b9a4163..bb8727e9f 100644
--- a/src/editors/containers/TextEditor/TextEditor.jsx
+++ b/src/editors/containers/TextEditor/TextEditor.jsx
@@ -40,7 +40,6 @@ export const TextEditor = ({
blockFinished,
initializeEditor,
}) => {
- console.log({ blockValue, blockFailed, blockFinished, test: 1 });
const { isOpen, openModal, closeModal } = modalToggle();
return (
@@ -61,7 +60,10 @@ export const TextEditor = ({
)
: (
-
+
)}
);
@@ -87,7 +89,7 @@ export const mapStateToProps = (state) => ({
});
export const mapDispatchToProps = {
- initializeEditor: actions.app.initializeEditor,
+ initializeEditor: actions.app.initializeEditor,
};
export default connect(mapStateToProps, mapDispatchToProps)(TextEditor);
diff --git a/src/setupTest.js b/src/setupTest.js
index be8991ff4..d13ce2788 100644
--- a/src/setupTest.js
+++ b/src/setupTest.js
@@ -58,7 +58,9 @@ jest.mock('@edx/frontend-platform/i18n', () => {
});
jest.mock('@edx/paragon', () => jest.requireActual('testUtils').mockNestedComponents({
- ActionRow: 'ActionRow',
+ ActionRow: {
+ Spacer: 'ActionRow.Spacer',
+ },
Button: 'Button',
Icon: 'Icon',
IconButton: 'IconButton',