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
This commit is contained in:
Raymond Zhou
2022-02-25 12:15:13 -05:00
committed by GitHub
parent 1a1900f213
commit 042246be86
10 changed files with 284 additions and 64 deletions

View File

@@ -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(<module.EditableHeader {...props} />);
});
describe('snapshot', () => {
test('snapshot', () => {
expect(el).toMatchSnapshot();
});
test('displays Edit Icon', () => {
const formControl = el.find(Form.Control);
expect(formControl.props().trailingInputElement).toMatchObject(<Icon src={Edit} />);
});
});
});

View File

@@ -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 <FormattedMessage {...messages.loading} />; }
console.log('HeaderTitle');
const {
inputRef,
isEditing,
@@ -53,13 +52,13 @@ export const HeaderTitle = ({
{localTitle}
</div>
<IconButton
iconAs={Icon}
src={Edit}
onClick={startEditing}
alt="Edit"
aria-label="Edit Title"
className="mr-2"
iconAs={Icon}
onClick={startEditing}
size="sm"
src={Edit}
/>
</div>
);

View File

@@ -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(<module.HeaderTitle {...props} isInitialized />);
expect(localTitleHooks).toHaveBeenCalledWith({
editorRef: props.editorRef,
setBlockTitle: props.setBlockTitle,
typeHeader: props.typeHeader,
});
});
});
describe('snapshots', () => {
test('not initialized', () => {
expect(shallow(<module.HeaderTitle {...props} />)).toMatchSnapshot();
});
test('initialized', () => {
localTitleHooks.mockReturnValue(hookProps);
expect(shallow(<module.HeaderTitle {...props} isInitialized />)).toMatchSnapshot();
});
test('editing', () => {
localTitleHooks.mockReturnValue({ ...hookProps, isEditing: true });
expect(shallow(<module.HeaderTitle {...props} isInitialized />)).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);
});
});
});

View File

@@ -0,0 +1,37 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`EditableHeader snapshot 1`] = `
<Form.Group>
<Form.Control
autoFocus={true}
onBlur={[MockFunction args.updateTitle]}
onChange={[MockFunction args.handleChange]}
onKeyDown={[MockFunction args.handleKeyDown]}
placeholder="Title"
trailingInputElement={
<Icon
src={[MockFunction icons.Edit]}
/>
}
value="test-title-text"
/>
</Form.Group>
`;
exports[`EditableHeader snapshot snapshot 1`] = `
<Form.Group>
<Form.Control
autoFocus={true}
onBlur={[MockFunction args.updateTitle]}
onChange={[MockFunction args.handleChange]}
onKeyDown={[MockFunction args.handleKeyDown]}
placeholder="Title"
trailingInputElement={
<Icon
src={[MockFunction icons.Edit]}
/>
}
value="test-title-text"
/>
</Form.Group>
`;

View File

@@ -0,0 +1,45 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`HeaderTitle snapshots editing 1`] = `
<EditableHeader
handleChange={[MockFunction titleHooks.handleChange]}
handleKeyDown={[MockFunction titleHooks.handleKeyDown]}
inputRef={[MockFunction titleHooks.inputRef]}
localTitle="TeST LocALtitLE"
updateTitle={[MockFunction titleHooks.updateTitle]}
/>
`;
exports[`HeaderTitle snapshots initialized 1`] = `
<div
className="d-flex"
>
<div
style={
Object {
"lineHeight": "1.5",
"paddingRight": ".25em",
}
}
>
TeST LocALtitLE
</div>
<IconButton
alt="Edit"
aria-label="Edit Title"
className="mr-2"
iconAs="Icon"
onClick={[MockFunction titleHooks.startEditing]}
size="sm"
src={[MockFunction icons.Edit]}
/>
</div>
`;
exports[`HeaderTitle snapshots not initialized 1`] = `
<FormattedMessage
defaultMessage="Loading..."
description="Message displayed while loading content"
id="authoring.texteditor.title.loading"
/>
`;

View File

@@ -0,0 +1,24 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[` 1`] = `
<div
className="editor-header"
>
<ModalDialog.Header>
<ActionRow>
<ModalDialog.Title>
<HeaderTitle />
</ModalDialog.Title>
<ActionRow.Spacer />
<IconButton
alt="Close"
aria-label="Cancel Changes and Return to Learning Context"
className="mr-2"
iconAs="Icon"
src={[MockFunction icons.Close]}
variant="light"
/>
</ActionRow>
</ModalDialog.Header>
</div>
`;

View File

@@ -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,
}) => (
<div className="editor-header">

View File

@@ -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(
<EditorPageContext.Provider value={context}>
<EditorHeader title={title} />
</EditorPageContext.Provider>,
);
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(
<EditorPageContext.Provider value={context}>
<EditorHeader title={title} />
</EditorPageContext.Provider>,
);
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(<EditorHeader {...props} />);
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));
});
});
});

View File

@@ -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 = ({
</div>
)
: (
<Editor {...editorConfig({ setEditorRef, blockValue, openModal, initializeEditor })} />
<Editor {...editorConfig({
setEditorRef, blockValue, openModal, initializeEditor,
})}
/>
)}
</div>
);
@@ -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);

View File

@@ -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',