mirror of
https://github.com/Hopiu/wagtail.git
synced 2026-04-16 04:51:01 +00:00
Add missing unit tests for Draftail JS code
This commit is contained in:
parent
d77f8681e0
commit
e3ab5c5ff5
19 changed files with 893 additions and 88 deletions
|
|
@ -0,0 +1,49 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Draftail #initEditor options 1`] = `
|
||||
Object {
|
||||
"autoCapitalize": null,
|
||||
"autoComplete": null,
|
||||
"autoCorrect": null,
|
||||
"blockTypes": Array [],
|
||||
"decorators": Array [],
|
||||
"enableHorizontalRule": Object {
|
||||
"description": "Horizontal line",
|
||||
},
|
||||
"enableLineBreak": Object {
|
||||
"description": "Line break",
|
||||
},
|
||||
"entityTypes": Array [
|
||||
Object {
|
||||
"block": [Function],
|
||||
"decorator": undefined,
|
||||
"source": [Function],
|
||||
"type": "Image",
|
||||
},
|
||||
],
|
||||
"inlineStyles": Array [],
|
||||
"maxListNesting": 4,
|
||||
"onSave": [Function],
|
||||
"placeholder": "Write here…",
|
||||
"rawContentState": null,
|
||||
"showRedoControl": Object {
|
||||
"description": "Redo",
|
||||
},
|
||||
"showUndoControl": Object {
|
||||
"description": "Undo",
|
||||
},
|
||||
"spellCheck": true,
|
||||
"stateSaveInterval": 250,
|
||||
"stripPastedStyles": false,
|
||||
"textAlignment": null,
|
||||
"textDirectionality": null,
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`Draftail #wrapWagtailIcon works 1`] = `
|
||||
<Icon
|
||||
className={null}
|
||||
name="media"
|
||||
title={null}
|
||||
/>
|
||||
`;
|
||||
|
|
@ -21,7 +21,7 @@ class ImageBlock extends Component {
|
|||
const { editorState, onChange } = blockProps;
|
||||
|
||||
const data = {
|
||||
alt: e.currentTarget.value,
|
||||
alt: e.target.value,
|
||||
};
|
||||
|
||||
onChange(DraftUtils.updateBlockEntity(editorState, block, data));
|
||||
|
|
|
|||
|
|
@ -65,8 +65,7 @@ describe('ImageBlock', () => {
|
|||
).toMatchSnapshot();
|
||||
});
|
||||
|
||||
// Alt field is readonly for now.
|
||||
it.skip('changeAlt', () => {
|
||||
it('changeAlt', () => {
|
||||
jest.spyOn(DraftUtils, 'updateBlockEntity');
|
||||
DraftUtils.updateBlockEntity.mockImplementation(e => e);
|
||||
|
||||
|
|
@ -88,11 +87,17 @@ describe('ImageBlock', () => {
|
|||
/>
|
||||
);
|
||||
|
||||
wrapper.find('[type="text"]').simulate('change', {
|
||||
currentTarget: {
|
||||
// // Alt field is readonly for now.
|
||||
wrapper.instance().changeAlt({
|
||||
target: {
|
||||
value: 'new alt',
|
||||
},
|
||||
}
|
||||
});
|
||||
// wrapper.find('[type="text"]').simulate('change', {
|
||||
// target: {
|
||||
// value: 'new alt',
|
||||
// },
|
||||
// });
|
||||
|
||||
expect(onChange).toHaveBeenCalled();
|
||||
expect(DraftUtils.updateBlockEntity).toHaveBeenCalledWith(
|
||||
|
|
|
|||
|
|
@ -86,7 +86,7 @@ describe('MediaBlock', () => {
|
|||
).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it.skip('large viewport', () => {
|
||||
it('large viewport', () => {
|
||||
const target = document.createElement('div');
|
||||
document.body.appendChild(target);
|
||||
target.getBoundingClientRect = () => ({
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ class TooltipEntity extends Component {
|
|||
closeOnResize
|
||||
>
|
||||
<Tooltip target={showTooltipAt} direction="top">
|
||||
{url ? (
|
||||
{(
|
||||
<a
|
||||
href={url}
|
||||
title={url}
|
||||
|
|
@ -71,7 +71,7 @@ class TooltipEntity extends Component {
|
|||
>
|
||||
{shortenLabel(label)}
|
||||
</a>
|
||||
) : null}
|
||||
)}
|
||||
|
||||
<button
|
||||
className="button Tooltip__button"
|
||||
|
|
|
|||
|
|
@ -0,0 +1,85 @@
|
|||
import React from 'react';
|
||||
import { shallow } from 'enzyme';
|
||||
|
||||
import TooltipEntity from './TooltipEntity';
|
||||
|
||||
describe('TooltipEntity', () => {
|
||||
it('works', () => {
|
||||
expect(shallow((
|
||||
<TooltipEntity
|
||||
entityKey="1"
|
||||
onEdit={() => {}}
|
||||
onRemove={() => {}}
|
||||
icon="#icon-test"
|
||||
url="https://www.example.com/"
|
||||
label="www.example.com"
|
||||
>
|
||||
test
|
||||
</TooltipEntity>
|
||||
))).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('shortened label', () => {
|
||||
expect(shallow((
|
||||
<TooltipEntity
|
||||
entityKey="1"
|
||||
onEdit={() => {}}
|
||||
onRemove={() => {}}
|
||||
icon="#icon-test"
|
||||
url="https://www.example.com/"
|
||||
label="www.example.example.example.com"
|
||||
>
|
||||
test
|
||||
</TooltipEntity>
|
||||
)).setState({
|
||||
showTooltipAt: document.createElement('div').getBoundingClientRect(),
|
||||
}).find('Tooltip a')
|
||||
.text()).toBe('www.example.example.…');
|
||||
});
|
||||
|
||||
it('#openTooltip', () => {
|
||||
const wrapper = shallow((
|
||||
<TooltipEntity
|
||||
entityKey="1"
|
||||
onEdit={() => {}}
|
||||
onRemove={() => {}}
|
||||
icon="#icon-test"
|
||||
url="https://www.example.com/"
|
||||
label="www.example.com"
|
||||
>
|
||||
test
|
||||
</TooltipEntity>
|
||||
));
|
||||
|
||||
wrapper.find('.TooltipEntity').simulate('mouseup', {
|
||||
target: document.createElement('div'),
|
||||
});
|
||||
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('#closeTooltip', () => {
|
||||
const wrapper = shallow((
|
||||
<TooltipEntity
|
||||
entityKey="1"
|
||||
onEdit={() => {}}
|
||||
onRemove={() => {}}
|
||||
icon="#icon-test"
|
||||
url="https://www.example.com/"
|
||||
label="www.example.com"
|
||||
>
|
||||
test
|
||||
</TooltipEntity>
|
||||
));
|
||||
|
||||
wrapper.find('.TooltipEntity').simulate('mouseup', {
|
||||
target: document.createElement('div'),
|
||||
});
|
||||
|
||||
wrapper.instance().closeTooltip();
|
||||
|
||||
expect(wrapper.state()).toEqual({
|
||||
showTooltipAt: null,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,73 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`TooltipEntity #openTooltip 1`] = `
|
||||
<a
|
||||
className="TooltipEntity"
|
||||
onMouseUp={[Function]}
|
||||
role="button"
|
||||
>
|
||||
<Icon
|
||||
className="TooltipEntity__icon"
|
||||
icon="#icon-test"
|
||||
title={null}
|
||||
/>
|
||||
test
|
||||
<Portal
|
||||
closeOnClick={true}
|
||||
closeOnResize={true}
|
||||
closeOnType={true}
|
||||
onClose={[Function]}
|
||||
>
|
||||
<Tooltip
|
||||
direction="top"
|
||||
target={
|
||||
Object {
|
||||
"bottom": 0,
|
||||
"height": 0,
|
||||
"left": 0,
|
||||
"right": 0,
|
||||
"top": 0,
|
||||
"width": 0,
|
||||
}
|
||||
}
|
||||
>
|
||||
<a
|
||||
className="Tooltip__link"
|
||||
href="https://www.example.com/"
|
||||
rel="noopener noreferrer"
|
||||
target="_blank"
|
||||
title="https://www.example.com/"
|
||||
>
|
||||
www.example.com
|
||||
</a>
|
||||
<button
|
||||
className="button Tooltip__button"
|
||||
onClick={[Function]}
|
||||
>
|
||||
Edit
|
||||
</button>
|
||||
<button
|
||||
className="button button-secondary no Tooltip__button"
|
||||
onClick={[Function]}
|
||||
>
|
||||
Remove
|
||||
</button>
|
||||
</Tooltip>
|
||||
</Portal>
|
||||
</a>
|
||||
`;
|
||||
|
||||
exports[`TooltipEntity works 1`] = `
|
||||
<a
|
||||
className="TooltipEntity"
|
||||
onMouseUp={[Function]}
|
||||
role="button"
|
||||
>
|
||||
<Icon
|
||||
className="TooltipEntity__icon"
|
||||
icon="#icon-test"
|
||||
title={null}
|
||||
/>
|
||||
test
|
||||
</a>
|
||||
`;
|
||||
|
|
@ -6,16 +6,18 @@ import { IS_IE11, STRINGS } from '../../config/wagtailConfig';
|
|||
|
||||
import Icon from '../Icon/Icon';
|
||||
|
||||
import Link from './decorators/Link';
|
||||
import Document from './decorators/Document';
|
||||
import ImageBlock from './blocks/ImageBlock';
|
||||
import EmbedBlock from './blocks/EmbedBlock';
|
||||
|
||||
import ModalWorkflowSource from './sources/ModalWorkflowSource';
|
||||
|
||||
import registry from './registry';
|
||||
|
||||
const wrapWagtailIcon = type => {
|
||||
export { registry };
|
||||
|
||||
export { default as Link } from './decorators/Link';
|
||||
export { default as Document } from './decorators/Document';
|
||||
export { default as ImageBlock } from './blocks/ImageBlock';
|
||||
export { default as EmbedBlock } from './blocks/EmbedBlock';
|
||||
|
||||
export { default as ModalWorkflowSource } from './sources/ModalWorkflowSource';
|
||||
|
||||
export const wrapWagtailIcon = type => {
|
||||
const isIconFont = type.icon && typeof type.icon === 'string';
|
||||
if (isIconFont) {
|
||||
return Object.assign(type, {
|
||||
|
|
@ -26,7 +28,12 @@ const wrapWagtailIcon = type => {
|
|||
return type;
|
||||
};
|
||||
|
||||
export const initEditor = (fieldName, options = {}) => {
|
||||
/**
|
||||
* Initialises the DraftailEditor for a given field.
|
||||
* @param {string} fieldName
|
||||
* @param {Object} options
|
||||
*/
|
||||
export const initEditor = (fieldName, options) => {
|
||||
const field = document.querySelector(`[name="${fieldName}"]`);
|
||||
const editorWrapper = document.createElement('div');
|
||||
field.parentNode.appendChild(editorWrapper);
|
||||
|
|
@ -35,29 +42,19 @@ export const initEditor = (fieldName, options = {}) => {
|
|||
field.value = JSON.stringify(rawContentState);
|
||||
};
|
||||
|
||||
let blockTypes;
|
||||
let inlineStyles;
|
||||
let entityTypes;
|
||||
const blockTypes = options.blockTypes || [];
|
||||
const inlineStyles = options.inlineStyles || [];
|
||||
let entityTypes = options.entityTypes || [];
|
||||
|
||||
if (options && options.blockTypes) {
|
||||
blockTypes = options.blockTypes.map(wrapWagtailIcon);
|
||||
}
|
||||
entityTypes = entityTypes.map(wrapWagtailIcon).map(type =>
|
||||
Object.assign(type, {
|
||||
source: registry.getSource(type.source),
|
||||
decorator: registry.getDecorator(type.decorator),
|
||||
block: registry.getBlock(type.block),
|
||||
})
|
||||
);
|
||||
|
||||
if (options && options.inlineStyles) {
|
||||
inlineStyles = options.inlineStyles.map(wrapWagtailIcon);
|
||||
}
|
||||
|
||||
if (options && options.entityTypes) {
|
||||
entityTypes = options.entityTypes.map(wrapWagtailIcon).map(type =>
|
||||
Object.assign(type, {
|
||||
source: registry.getSource(type.source),
|
||||
decorator: registry.getDecorator(type.decorator),
|
||||
block: registry.getBlock(type.block),
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
const enableHorizontalRule = options && options.enableHorizontalRule ? {
|
||||
const enableHorizontalRule = options.enableHorizontalRule ? {
|
||||
description: STRINGS.HORIZONTAL_LINE,
|
||||
} : false;
|
||||
|
||||
|
|
@ -77,8 +74,8 @@ export const initEditor = (fieldName, options = {}) => {
|
|||
// Draft.js + IE 11 presents some issues with pasting rich text. Disable rich paste there.
|
||||
stripPastedStyles={IS_IE11}
|
||||
{...options}
|
||||
blockTypes={blockTypes}
|
||||
inlineStyles={inlineStyles}
|
||||
blockTypes={blockTypes.map(wrapWagtailIcon)}
|
||||
inlineStyles={inlineStyles.map(wrapWagtailIcon)}
|
||||
entityTypes={entityTypes}
|
||||
enableHorizontalRule={enableHorizontalRule}
|
||||
/>
|
||||
|
|
@ -89,24 +86,3 @@ export const initEditor = (fieldName, options = {}) => {
|
|||
// Bind editor instance to its field so it can be accessed imperatively elsewhere.
|
||||
field.draftailEditor = draftailEditor;
|
||||
};
|
||||
|
||||
registry.registerSources({
|
||||
ModalWorkflowSource,
|
||||
});
|
||||
registry.registerDecorators({
|
||||
Link,
|
||||
Document,
|
||||
});
|
||||
registry.registerBlocks({
|
||||
ImageBlock,
|
||||
EmbedBlock,
|
||||
});
|
||||
|
||||
const draftail = Object.assign(
|
||||
{
|
||||
initEditor,
|
||||
},
|
||||
registry
|
||||
);
|
||||
|
||||
export default draftail;
|
||||
|
|
|
|||
89
client/src/components/Draftail/index.test.js
Normal file
89
client/src/components/Draftail/index.test.js
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
import {
|
||||
wrapWagtailIcon,
|
||||
initEditor,
|
||||
registry,
|
||||
ModalWorkflowSource,
|
||||
Link,
|
||||
Document,
|
||||
ImageBlock,
|
||||
EmbedBlock,
|
||||
} from './index';
|
||||
|
||||
describe('Draftail', () => {
|
||||
describe('#initEditor', () => {
|
||||
beforeEach(() => {
|
||||
document.body.innerHTML = '';
|
||||
});
|
||||
|
||||
it('works', () => {
|
||||
const field = document.createElement('input');
|
||||
field.name = 'test';
|
||||
field.value = 'null';
|
||||
document.body.appendChild(field);
|
||||
|
||||
initEditor('test', {});
|
||||
|
||||
expect(field.draftailEditor).toBeDefined();
|
||||
});
|
||||
|
||||
it('onSave', () => {
|
||||
const field = document.createElement('input');
|
||||
field.name = 'test';
|
||||
field.value = 'null';
|
||||
document.body.appendChild(field);
|
||||
|
||||
initEditor('test', {});
|
||||
|
||||
field.draftailEditor.saveState();
|
||||
|
||||
expect(field.value).toBe('null');
|
||||
});
|
||||
|
||||
it('options', () => {
|
||||
const field = document.createElement('input');
|
||||
field.name = 'test';
|
||||
field.value = 'null';
|
||||
document.body.appendChild(field);
|
||||
|
||||
registry.registerSources({
|
||||
ModalWorkflowSource: () => {},
|
||||
});
|
||||
|
||||
registry.registerBlocks({
|
||||
ImageBlock: () => {},
|
||||
});
|
||||
|
||||
initEditor('test', {
|
||||
entityTypes: [
|
||||
{ type: 'Image', source: 'ModalWorkflowSource', block: 'ImageBlock' },
|
||||
],
|
||||
enableHorizontalRule: true,
|
||||
});
|
||||
|
||||
expect(field.draftailEditor.props).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
||||
describe('#wrapWagtailIcon', () => {
|
||||
it('works', () => {
|
||||
expect(wrapWagtailIcon({ icon: 'media' }).icon).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('no icon', () => {
|
||||
const type = {};
|
||||
expect(wrapWagtailIcon(type)).toBe(type);
|
||||
});
|
||||
|
||||
it('array icon', () => {
|
||||
const type = { icon: ['M10 10 H 90 V 90 H 10 Z'] };
|
||||
expect(wrapWagtailIcon(type)).toBe(type);
|
||||
});
|
||||
});
|
||||
|
||||
it('#registry', () => expect(registry).toBeDefined());
|
||||
it('#ModalWorkflowSource', () => expect(ModalWorkflowSource).toBeDefined());
|
||||
it('#Link', () => expect(Link).toBeDefined());
|
||||
it('#Document', () => expect(Document).toBeDefined());
|
||||
it('#ImageBlock', () => expect(ImageBlock).toBeDefined());
|
||||
it('#EmbedBlock', () => expect(EmbedBlock).toBeDefined());
|
||||
});
|
||||
|
|
@ -4,29 +4,19 @@ const registry = {
|
|||
sources: {},
|
||||
};
|
||||
|
||||
const registerDecorators = (decorators) => {
|
||||
Object.assign(registry.decorators, decorators);
|
||||
};
|
||||
const registerDecorators = (decorators) => Object.assign(registry.decorators, decorators);
|
||||
const registerBlocks = (blocks) => Object.assign(registry.blocks, blocks);
|
||||
const registerSources = (sources) => Object.assign(registry.sources, sources);
|
||||
|
||||
const getDecorator = name => registry.decorators[name];
|
||||
|
||||
const registerBlocks = (blocks) => {
|
||||
Object.assign(registry.blocks, blocks);
|
||||
};
|
||||
|
||||
const getBlock = name => registry.blocks[name];
|
||||
|
||||
const registerSources = (sources) => {
|
||||
Object.assign(registry.sources, sources);
|
||||
};
|
||||
|
||||
const getSource = name => registry.sources[name];
|
||||
|
||||
export default {
|
||||
registerDecorators,
|
||||
getDecorator,
|
||||
registerBlocks,
|
||||
getBlock,
|
||||
registerSources,
|
||||
getDecorator,
|
||||
getBlock,
|
||||
getSource,
|
||||
};
|
||||
|
|
|
|||
39
client/src/components/Draftail/registry.test.js
Normal file
39
client/src/components/Draftail/registry.test.js
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
import registry from './registry';
|
||||
|
||||
describe('registry', () => {
|
||||
describe('sources', () => {
|
||||
it('works', () => {
|
||||
expect(registry.getSource('UndefinedSource')).not.toBeDefined();
|
||||
|
||||
registry.registerSources({
|
||||
TestSource: null,
|
||||
});
|
||||
|
||||
expect(registry.getSource('TestSource')).toBe(null);
|
||||
});
|
||||
});
|
||||
|
||||
describe('decorators', () => {
|
||||
it('works', () => {
|
||||
expect(registry.getDecorator('UndefinedDecorator')).not.toBeDefined();
|
||||
|
||||
registry.registerDecorators({
|
||||
TestDecorator: null,
|
||||
});
|
||||
|
||||
expect(registry.getDecorator('TestDecorator')).toBe(null);
|
||||
});
|
||||
});
|
||||
|
||||
describe('blocks', () => {
|
||||
it('works', () => {
|
||||
expect(registry.getBlock('UndefinedBlock')).not.toBeDefined();
|
||||
|
||||
registry.registerBlocks({
|
||||
TestBlock: null,
|
||||
});
|
||||
|
||||
expect(registry.getBlock('TestBlock')).toBe(null);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
@ -16,7 +16,7 @@ MUTABILITY[DOCUMENT] = 'MUTABLE';
|
|||
MUTABILITY[ENTITY_TYPE.IMAGE] = 'IMMUTABLE';
|
||||
MUTABILITY[EMBED] = 'IMMUTABLE';
|
||||
|
||||
const getChooserConfig = (entityType, entity) => {
|
||||
export const getChooserConfig = (entityType, entity) => {
|
||||
const chooserURL = {};
|
||||
chooserURL[ENTITY_TYPE.IMAGE] = `${global.chooserUrls.imageChooser}?select_format=true`;
|
||||
chooserURL[EMBED] = global.chooserUrls.embedsChooser;
|
||||
|
|
@ -59,7 +59,7 @@ const getChooserConfig = (entityType, entity) => {
|
|||
};
|
||||
};
|
||||
|
||||
const filterEntityData = (entityType, data) => {
|
||||
export const filterEntityData = (entityType, data) => {
|
||||
switch (entityType.type) {
|
||||
case ENTITY_TYPE.IMAGE:
|
||||
return {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,343 @@
|
|||
import React from 'react';
|
||||
import { shallow } from 'enzyme';
|
||||
|
||||
import ModalWorkflowSource, { getChooserConfig, filterEntityData } from './ModalWorkflowSource';
|
||||
import { EditorState, convertFromRaw, AtomicBlockUtils, RichUtils, Modifier } from 'draft-js';
|
||||
|
||||
global.ModalWorkflow = () => {};
|
||||
|
||||
describe('ModalWorkflowSource', () => {
|
||||
beforeEach(() => {
|
||||
jest.spyOn(global, 'ModalWorkflow');
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.restoreAllMocks();
|
||||
});
|
||||
|
||||
it('works', () => {
|
||||
expect(shallow((
|
||||
<ModalWorkflowSource
|
||||
editorState={{}}
|
||||
entityType={{}}
|
||||
entity={{}}
|
||||
onComplete={() => {}}
|
||||
onClose={() => {}}
|
||||
/>
|
||||
))).toMatchSnapshot();
|
||||
});
|
||||
|
||||
describe('#getChooserConfig', () => {
|
||||
it('IMAGE', () => {
|
||||
expect(getChooserConfig({ type: 'IMAGE' })).toEqual({
|
||||
url: '/admin/images/chooser/?select_format=true',
|
||||
urlParams: {},
|
||||
});
|
||||
});
|
||||
|
||||
it('EMBED', () => {
|
||||
expect(getChooserConfig({ type: 'EMBED' })).toEqual({
|
||||
url: '/admin/embeds/chooser/',
|
||||
urlParams: {},
|
||||
});
|
||||
});
|
||||
|
||||
it('DOCUMENT', () => {
|
||||
expect(getChooserConfig({ type: 'DOCUMENT' })).toEqual({
|
||||
url: '/admin/documents/chooser/',
|
||||
urlParams: {},
|
||||
});
|
||||
});
|
||||
|
||||
describe('LINK', () => {
|
||||
it('no entity', () => {
|
||||
expect(getChooserConfig({ type: 'LINK' })).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('page', () => {
|
||||
expect(getChooserConfig({ type: 'LINK' }, {
|
||||
getData: () => ({ id: 1, parentId: 0 })
|
||||
})).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('mail', () => {
|
||||
expect(getChooserConfig({ type: 'LINK' }, {
|
||||
getData: () => ({ url: 'mailto:test@example.com' })
|
||||
})).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('external', () => {
|
||||
expect(getChooserConfig({ type: 'LINK' }, {
|
||||
getData: () => ({ url: 'https://www.example.com/' })
|
||||
})).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('#filterEntityData', () => {
|
||||
it('IMAGE', () => {
|
||||
expect(filterEntityData({ type: 'IMAGE' }, {
|
||||
id: 53,
|
||||
title: 'Test',
|
||||
alt: 'Test',
|
||||
class: 'richtext-image right',
|
||||
edit_link: '/admin/images/53/',
|
||||
format: 'right',
|
||||
preview: {
|
||||
url: '/media/images/test.width-500.jpg',
|
||||
}
|
||||
})).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('EMBED', () => {
|
||||
expect(filterEntityData({ type: 'EMBED' }, {
|
||||
authorName: 'Test',
|
||||
embedType: 'video',
|
||||
providerName: 'YouTube',
|
||||
thumbnail: 'https://i.ytimg.com/vi/pSlVtxLOYiM/hqdefault.jpg',
|
||||
title: 'Test',
|
||||
url: 'https://www.youtube.com/watch?v=pSlVtxLOYiM',
|
||||
})).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('DOCUMENT', () => {
|
||||
expect(filterEntityData({ type: 'DOCUMENT' }, {
|
||||
edit_link: '/admin/documents/edit/1/',
|
||||
filename: 'test.pdf',
|
||||
id: 1,
|
||||
title: 'Test',
|
||||
url: '/documents/1/test.pdf',
|
||||
})).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('OTHER', () => {
|
||||
expect(filterEntityData({ type: 'OTHER' }, {})).toEqual({});
|
||||
});
|
||||
|
||||
describe('LINK', () => {
|
||||
it('page', () => {
|
||||
expect(filterEntityData({ type: 'LINK' }, {
|
||||
id: 60,
|
||||
parentId: 1,
|
||||
url: '/',
|
||||
editUrl: '/admin/pages/60/edit/',
|
||||
title: 'Welcome to the Wagtail Bakery!',
|
||||
})).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('mail', () => {
|
||||
expect(filterEntityData({ type: 'LINK' }, {
|
||||
prefer_this_title_as_link_text: false,
|
||||
title: 'test@example.com',
|
||||
url: 'mailto:test@example.com',
|
||||
})).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('external', () => {
|
||||
expect(filterEntityData({ type: 'LINK' }, {
|
||||
prefer_this_title_as_link_text: false,
|
||||
title: 'https://www.example.com/',
|
||||
url: 'https://www.example.com/',
|
||||
})).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('#componentDidMount', () => {
|
||||
const wrapper = shallow((
|
||||
<ModalWorkflowSource
|
||||
editorState={{}}
|
||||
entityType={{}}
|
||||
entity={{}}
|
||||
onComplete={() => {}}
|
||||
onClose={() => {}}
|
||||
/>
|
||||
));
|
||||
|
||||
wrapper.instance().onChosen = jest.fn();
|
||||
|
||||
wrapper.instance().componentDidMount();
|
||||
|
||||
global.ModalWorkflow.mock.calls[0][0].responses.embedChosen('test', {});
|
||||
|
||||
expect(global.ModalWorkflow).toHaveBeenCalled();
|
||||
expect(global.jQuery().on).toHaveBeenCalled();
|
||||
expect(wrapper.instance().onChosen).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('#onError', () => {
|
||||
window.alert = jest.fn();
|
||||
const onClose = jest.fn();
|
||||
|
||||
const wrapper = shallow((
|
||||
<ModalWorkflowSource
|
||||
editorState={{}}
|
||||
entityType={{}}
|
||||
entity={{}}
|
||||
onComplete={() => {}}
|
||||
onClose={onClose}
|
||||
/>
|
||||
));
|
||||
|
||||
wrapper.instance().componentDidMount();
|
||||
|
||||
global.ModalWorkflow.mock.calls[0][0].onError();
|
||||
|
||||
expect(global.ModalWorkflow).toHaveBeenCalled();
|
||||
expect(global.jQuery().on).toHaveBeenCalled();
|
||||
expect(window.alert).toHaveBeenCalled();
|
||||
expect(onClose).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('#componentWillUnmount', () => {
|
||||
const wrapper = shallow((
|
||||
<ModalWorkflowSource
|
||||
editorState={{}}
|
||||
entityType={{}}
|
||||
entity={{}}
|
||||
onComplete={() => {}}
|
||||
onClose={() => {}}
|
||||
/>
|
||||
));
|
||||
|
||||
wrapper.instance().componentWillUnmount();
|
||||
|
||||
expect(global.jQuery().off).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
describe('#onChosen', () => {
|
||||
it('works', () => {
|
||||
jest.spyOn(RichUtils, 'toggleLink');
|
||||
|
||||
const onComplete = jest.fn();
|
||||
|
||||
let editorState = EditorState.createWithContent(convertFromRaw({
|
||||
entityMap: {},
|
||||
blocks: [
|
||||
{
|
||||
key: 'a',
|
||||
text: 'test',
|
||||
}
|
||||
]
|
||||
}));
|
||||
let selection = editorState.getSelection();
|
||||
selection = selection.merge({
|
||||
focusOffset: 4,
|
||||
});
|
||||
editorState = EditorState.acceptSelection(editorState, selection);
|
||||
const wrapper = shallow((
|
||||
<ModalWorkflowSource
|
||||
editorState={editorState}
|
||||
entityType={{}}
|
||||
entity={{}}
|
||||
onComplete={onComplete}
|
||||
onClose={() => {}}
|
||||
/>
|
||||
));
|
||||
|
||||
wrapper.instance().onChosen({});
|
||||
|
||||
expect(onComplete).toHaveBeenCalled();
|
||||
expect(RichUtils.toggleLink).toHaveBeenCalled();
|
||||
|
||||
RichUtils.toggleLink.mockRestore();
|
||||
});
|
||||
|
||||
it('block', () => {
|
||||
jest.spyOn(AtomicBlockUtils, 'insertAtomicBlock');
|
||||
|
||||
const onComplete = jest.fn();
|
||||
|
||||
let editorState = EditorState.createWithContent(convertFromRaw({
|
||||
entityMap: {},
|
||||
blocks: [
|
||||
{
|
||||
key: 'a',
|
||||
text: 'test',
|
||||
}
|
||||
]
|
||||
}));
|
||||
let selection = editorState.getSelection();
|
||||
selection = selection.merge({
|
||||
focusOffset: 4,
|
||||
});
|
||||
editorState = EditorState.acceptSelection(editorState, selection);
|
||||
const wrapper = shallow((
|
||||
<ModalWorkflowSource
|
||||
editorState={editorState}
|
||||
entityType={{
|
||||
block: () => {},
|
||||
}}
|
||||
entity={{}}
|
||||
onComplete={onComplete}
|
||||
onClose={() => {}}
|
||||
/>
|
||||
));
|
||||
|
||||
wrapper.instance().onChosen({});
|
||||
|
||||
expect(onComplete).toHaveBeenCalled();
|
||||
expect(AtomicBlockUtils.insertAtomicBlock).toHaveBeenCalled();
|
||||
|
||||
AtomicBlockUtils.insertAtomicBlock.mockRestore();
|
||||
});
|
||||
|
||||
it('prefer_this_title_as_link_text', () => {
|
||||
jest.spyOn(Modifier, 'replaceText');
|
||||
|
||||
const onComplete = jest.fn();
|
||||
|
||||
let editorState = EditorState.createWithContent(convertFromRaw({
|
||||
entityMap: {},
|
||||
blocks: [
|
||||
{
|
||||
key: 'a',
|
||||
text: 'test',
|
||||
}
|
||||
]
|
||||
}));
|
||||
let selection = editorState.getSelection();
|
||||
selection = selection.merge({
|
||||
focusOffset: 4,
|
||||
});
|
||||
editorState = EditorState.acceptSelection(editorState, selection);
|
||||
const wrapper = shallow((
|
||||
<ModalWorkflowSource
|
||||
editorState={editorState}
|
||||
entityType={{}}
|
||||
onComplete={onComplete}
|
||||
onClose={() => {}}
|
||||
/>
|
||||
));
|
||||
|
||||
wrapper.instance().onChosen({
|
||||
url: 'example.com',
|
||||
prefer_this_title_as_link_text: true,
|
||||
});
|
||||
|
||||
expect(onComplete).toHaveBeenCalled();
|
||||
expect(Modifier.replaceText).toHaveBeenCalled();
|
||||
|
||||
Modifier.replaceText.mockRestore();
|
||||
});
|
||||
});
|
||||
|
||||
it('#onClose', () => {
|
||||
const onClose = jest.fn();
|
||||
const wrapper = shallow((
|
||||
<ModalWorkflowSource
|
||||
editorState={{}}
|
||||
entityType={{}}
|
||||
entity={{}}
|
||||
onComplete={() => {}}
|
||||
onClose={onClose}
|
||||
/>
|
||||
));
|
||||
|
||||
wrapper.instance().onClose({
|
||||
preventDefault: () => {},
|
||||
});
|
||||
|
||||
expect(onClose).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,105 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`ModalWorkflowSource #filterEntityData DOCUMENT 1`] = `
|
||||
Object {
|
||||
"filename": "test.pdf",
|
||||
"id": 1,
|
||||
"url": "/documents/1/test.pdf",
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`ModalWorkflowSource #filterEntityData EMBED 1`] = `
|
||||
Object {
|
||||
"authorName": "Test",
|
||||
"embedType": "video",
|
||||
"providerName": "YouTube",
|
||||
"thumbnail": "https://i.ytimg.com/vi/pSlVtxLOYiM/hqdefault.jpg",
|
||||
"title": "Test",
|
||||
"url": "https://www.youtube.com/watch?v=pSlVtxLOYiM",
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`ModalWorkflowSource #filterEntityData IMAGE 1`] = `
|
||||
Object {
|
||||
"alt": "Test",
|
||||
"format": "right",
|
||||
"id": 53,
|
||||
"src": "/media/images/test.width-500.jpg",
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`ModalWorkflowSource #filterEntityData LINK external 1`] = `
|
||||
Object {
|
||||
"url": "https://www.example.com/",
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`ModalWorkflowSource #filterEntityData LINK mail 1`] = `
|
||||
Object {
|
||||
"url": "mailto:test@example.com",
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`ModalWorkflowSource #filterEntityData LINK page 1`] = `
|
||||
Object {
|
||||
"id": 60,
|
||||
"parentId": 1,
|
||||
"url": "/",
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`ModalWorkflowSource #getChooserConfig LINK external 1`] = `
|
||||
Object {
|
||||
"url": "/admin/choose-external-link/",
|
||||
"urlParams": Object {
|
||||
"allow_email_link": true,
|
||||
"allow_external_link": true,
|
||||
"can_choose_root": "false",
|
||||
"link_text": "",
|
||||
"link_url": "https://www.example.com/",
|
||||
"page_type": "wagtailcore.page",
|
||||
},
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`ModalWorkflowSource #getChooserConfig LINK mail 1`] = `
|
||||
Object {
|
||||
"url": "/admin/choose-email-link/",
|
||||
"urlParams": Object {
|
||||
"allow_email_link": true,
|
||||
"allow_external_link": true,
|
||||
"can_choose_root": "false",
|
||||
"link_text": "",
|
||||
"link_url": "test@example.com",
|
||||
"page_type": "wagtailcore.page",
|
||||
},
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`ModalWorkflowSource #getChooserConfig LINK no entity 1`] = `
|
||||
Object {
|
||||
"url": "/admin/choose-page/",
|
||||
"urlParams": Object {
|
||||
"allow_email_link": true,
|
||||
"allow_external_link": true,
|
||||
"can_choose_root": "false",
|
||||
"link_text": "",
|
||||
"page_type": "wagtailcore.page",
|
||||
},
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`ModalWorkflowSource #getChooserConfig LINK page 1`] = `
|
||||
Object {
|
||||
"url": "/admin/choose-page/0/",
|
||||
"urlParams": Object {
|
||||
"allow_email_link": true,
|
||||
"allow_external_link": true,
|
||||
"can_choose_root": "false",
|
||||
"link_text": "",
|
||||
"page_type": "wagtailcore.page",
|
||||
},
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`ModalWorkflowSource works 1`] = `""`;
|
||||
|
|
@ -4,7 +4,7 @@ import Portal from './Portal';
|
|||
|
||||
const func = expect.any(Function);
|
||||
|
||||
describe.skip('Portal', () => {
|
||||
describe('Portal', () => {
|
||||
beforeEach(() => {
|
||||
document.body.innerHTML = '';
|
||||
});
|
||||
|
|
@ -18,8 +18,8 @@ describe.skip('Portal', () => {
|
|||
});
|
||||
|
||||
it('component lifecycle', () => {
|
||||
jest.spyOn(document, 'removeEventListener');
|
||||
jest.spyOn(window, 'removeEventListener');
|
||||
document.removeEventListener = jest.fn();
|
||||
window.removeEventListener = jest.fn();
|
||||
|
||||
const wrapper = shallow(<Portal onClose={() => {}}>Test!</Portal>);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Portal #children 1`] = `null`;
|
||||
exports[`Portal #children 1`] = `""`;
|
||||
|
||||
exports[`Portal component lifecycle 1`] = `"<div><div data-reactroot=\\"\\">Test!</div></div>"`;
|
||||
exports[`Portal component lifecycle 1`] = `"<div><div>Test!</div></div>"`;
|
||||
|
||||
exports[`Portal empty 1`] = `null`;
|
||||
exports[`Portal empty 1`] = `""`;
|
||||
|
|
|
|||
|
|
@ -39,3 +39,20 @@ global.wagtailConfig = {
|
|||
};
|
||||
|
||||
global.wagtailVersion = '1.6a1';
|
||||
|
||||
global.chooserUrls = {
|
||||
documentChooser: '/admin/documents/chooser/',
|
||||
emailLinkChooser: '/admin/choose-email-link/',
|
||||
embedsChooser: '/admin/embeds/chooser/',
|
||||
externalLinkChooser: '/admin/choose-external-link/',
|
||||
imageChooser: '/admin/images/chooser/',
|
||||
pageChooser: '/admin/choose-page/',
|
||||
snippetChooser: '/admin/snippets/choose/',
|
||||
};
|
||||
|
||||
const jQueryObj = {
|
||||
on: jest.fn(),
|
||||
off: jest.fn(),
|
||||
};
|
||||
|
||||
global.jQuery = () => jQueryObj;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,30 @@
|
|||
import draftail from '../../../../../client/src/components/Draftail/index';
|
||||
import {
|
||||
initEditor,
|
||||
registry,
|
||||
ModalWorkflowSource,
|
||||
Link,
|
||||
Document,
|
||||
ImageBlock,
|
||||
EmbedBlock,
|
||||
} from '../../../../../client/src/components/Draftail/index';
|
||||
|
||||
// Expose as a global variable, for integration with other scripts.
|
||||
window.draftail = draftail;
|
||||
/**
|
||||
* Expose as a global, and register the built-in entities.
|
||||
*/
|
||||
|
||||
window.draftail = registry;
|
||||
window.draftail.initEditor = initEditor;
|
||||
|
||||
window.draftail.registerSources({
|
||||
ModalWorkflowSource,
|
||||
});
|
||||
|
||||
window.draftail.registerDecorators({
|
||||
Link,
|
||||
Document,
|
||||
});
|
||||
|
||||
window.draftail.registerBlocks({
|
||||
ImageBlock,
|
||||
EmbedBlock,
|
||||
});
|
||||
|
|
|
|||
|
|
@ -4,4 +4,12 @@ describe('draftail.entry', () => {
|
|||
it('exposes global', () => {
|
||||
expect(window.draftail).toBeDefined();
|
||||
});
|
||||
|
||||
it('has defaults registered', () => {
|
||||
expect(window.draftail.getSource('ModalWorkflowSource')).toBeDefined();
|
||||
expect(window.draftail.getDecorator('Link')).toBeDefined();
|
||||
expect(window.draftail.getDecorator('Document')).toBeDefined();
|
||||
expect(window.draftail.getBlock('ImageBlock')).toBeDefined();
|
||||
expect(window.draftail.getBlock('EmbedBlock')).toBeDefined();
|
||||
});
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in a new issue