docbrown/app/javascript/utilities/__tests__/dragAndDrop.test.js
Nick Taylor f0963c1bfa
Drag and drop an image in the editor (#10145)
* Refactored drag n drop functionality to a hook and component.

* Add the snackbar to the article editor.

* Now you can drag and drop images in the post body content.

* Cleaning up a few things.

* Now post cover images can be dragged and dropped.

* Removed unused empty function.

* Added @testing-library/preact-hooks so that we can test hooks.

* Some renaming, small refactor.

* Added tests

* Added more tests.

* Added more tests.

* Added message about dropping only one image in post body.

* Added message about dropping only one image for cover image.

* put onDrop into it's own meethod.

* More tests.

* Added some API documentation.

* Updated editor help with drag and drop image help.

* Changed wording.

* Now the alt text for markdown removes the file extension.

* Updated help wording. Thanks @rhymes

* Now the image markdown adds a new line at the end as we currently do not support inline images.
2020-09-04 14:12:59 -04:00

179 lines
5.2 KiB
JavaScript

import { h } from 'preact';
import { render } from '@testing-library/preact';
import { renderHook, act } from '@testing-library/preact-hooks';
import { DragAndDropZone, useDragAndDrop } from '@utilities/dragAndDrop';
describe('drag and drop for components', () => {
describe('useDragAndDrop', () => {
it('should not add drag and drop event listeners when DOM element is null', () => {
const onDrop = jest.fn();
const onDragOver = jest.fn();
const onDragExit = jest.fn();
HTMLElement.prototype.addEventListener = jest.fn();
HTMLDocument.prototype.addEventListener = jest.fn();
const { result } = renderHook(() =>
useDragAndDrop({
onDrop,
onDragOver,
onDragExit,
}),
);
act(() => {
result.current.setElement(null);
});
expect(HTMLElement.prototype.addEventListener).not.toHaveBeenCalled();
expect(HTMLDocument.prototype.addEventListener).not.toHaveBeenCalled();
});
it('should attach drag and drop events when setElement receives a DOM node', () => {
const onDrop = jest.fn();
const onDragOver = jest.fn();
const onDragExit = jest.fn();
HTMLElement.prototype.addEventListener = jest.fn();
HTMLDocument.prototype.addEventListener = jest.fn();
const { result } = renderHook(() =>
useDragAndDrop({
onDrop,
onDragOver,
onDragExit,
}),
);
act(() => {
result.current.setElement(document.createElement('textarea'));
});
expect(HTMLElement.prototype.addEventListener).toHaveBeenCalledTimes(4);
expect(HTMLDocument.prototype.addEventListener).toHaveBeenCalledTimes(2);
});
it('should remove drag and drop event listeners when the hook is unmounted', () => {
const onDrop = jest.fn();
const onDragOver = jest.fn();
const onDragExit = jest.fn();
HTMLElement.prototype.removeEventListener = jest.fn();
HTMLDocument.prototype.removeEventListener = jest.fn();
const { unmount, result } = renderHook(() =>
useDragAndDrop({
onDrop,
onDragOver,
onDragExit,
}),
);
act(() => {
result.current.setElement(document.createElement('textarea'));
});
unmount();
expect(HTMLDocument.prototype.removeEventListener).toHaveBeenCalledTimes(
2,
);
expect(HTMLElement.prototype.removeEventListener).toHaveBeenCalledTimes(
4,
);
});
});
describe('<DragAndDropZone />', () => {
it('should attach drag and drop events', async () => {
const onDrop = jest.fn();
const onDragOver = jest.fn();
const onDragExit = jest.fn();
HTMLElement.prototype.addEventListener = jest.fn();
HTMLDocument.prototype.addEventListener = jest.fn();
const { rerender } = render(
<DragAndDropZone
onDragOver={onDragOver}
onDragExit={onDragExit}
onDrop={onDrop}
>
<textarea>I'm a text area</textarea>
</DragAndDropZone>,
);
// Rerendering so that the ref gets set to the DOM node.
// represented by the Preact element <textarea />
rerender(
<DragAndDropZone
onDragOver={onDragOver}
onDragExit={onDragExit}
onDrop={onDrop}
>
<textarea>I'm a text area</textarea>
</DragAndDropZone>,
);
expect(HTMLDocument.prototype.addEventListener).toBeCalledTimes(2);
expect(HTMLElement.prototype.addEventListener).toHaveBeenCalledTimes(4);
});
it('should not attach drag and drop events', async () => {
const onDrop = jest.fn();
const onDragOver = jest.fn();
const onDragExit = jest.fn();
HTMLElement.prototype.removeEventListener = jest.fn();
HTMLDocument.prototype.removeEventListener = jest.fn();
const { unmount, rerender } = render(
<DragAndDropZone
onDragOver={onDragOver}
onDragExit={onDragExit}
onDrop={onDrop}
>
<textarea>I'm a text area</textarea>
</DragAndDropZone>,
);
// Rerendering so that the ref gets set to the DOM node.
// represented by the Preact element <textarea />
rerender(
<DragAndDropZone
onDragOver={onDragOver}
onDragExit={onDragExit}
onDrop={onDrop}
>
<textarea>I'm a text area</textarea>
</DragAndDropZone>,
);
unmount();
expect(HTMLDocument.prototype.removeEventListener).toBeCalledTimes(2);
expect(HTMLElement.prototype.removeEventListener).toHaveBeenCalledTimes(
4,
);
});
it('should not attach drag and drop events when no children.', async () => {
const onDrop = jest.fn();
const onDragOver = jest.fn();
const onDragExit = jest.fn();
HTMLElement.prototype.addEventListener = jest.fn();
HTMLDocument.prototype.addEventListener = jest.fn();
expect(() => {
render(
<DragAndDropZone
onDragOver={onDragOver}
onDragExit={onDragExit}
onDrop={onDrop}
/>,
);
}).toThrowError(
'The <DragAndDropZone /> component children prop is null or was not specified.',
);
});
});
});