UNPKG

slate-test-utils

Version:

> 📣 Love Slate and looking for your next gig? Sirona Medical is [hiring](https://sironamedical.com/about-us/careers/)!

198 lines (197 loc) • 8.13 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.buildTestHarness = void 0; const jsx_runtime_1 = require("react/jsx-runtime"); const react_1 = require("@testing-library/react"); const react_2 = require("@testing-library/react"); const editorQueries = require("./editorQueries"); const is_hotkey_1 = require("is-hotkey"); const utils_1 = require("./utils"); const slate_1 = require("slate"); const ensureSlateValid_1 = require("./ensureSlateValid"); /** * A test harness for the RichTextEditor that adds custom queries to assert on, lots * of simulated actions, and a custom rerender in case you want to assert on the DOM. * In most cases, you'll want to assert directly on the editor state to check that the editor * selection and other pieces of the editor are working as intended. */ const buildTestHarness = (Component) => async ({ debug = false, strict = false, editor, componentProps = {}, testID = 'slate-content-editable', }) => { const proppies = { editor, initialValue: editor.children, ...componentProps, }; if (strict) { (0, ensureSlateValid_1.ensureSlateStateValid)(editor); } const options = (0, react_1.render)((0, jsx_runtime_1.jsx)(Component, Object.assign({ initialValue: editor.children }, proppies), void 0), { queries: { ...react_1.queries, ...editorQueries }, // TODO: Rest of options... }); // @ts-ignore await (0, react_2.act)(async () => options); const element = options.getByTestId(testID); /** * Manually add this because JSDom doesn't implement this and Slate checks for it * internally before doing stuff. * * https://github.com/jsdom/jsdom/issues/1670 */ // @ts-ignore element.isContentEditable = true; /** * Slate React uses beforeinput events in order to prevent the default behavior within contenteditables * and apply certain operations to the Slate state based on the event type. We emulate all of the operations * that Slate applies in order to integration test the editor within a JSDom environment with React Testing * Library. * * Reference events we emulate: * https://github.com/ianstormtaylor/slate/blob/a5f4170162cefd1c9458544402bb8f2266e05ead/packages/slate-react/src/components/editable.tsx#L289 */ /** * Emulates typing content into Slate. * * @param {string} value */ const type = async (value) => (0, react_2.act)(async () => { (0, react_2.fireEvent)(element, new InputEvent('beforeinput', { inputType: 'insertText', data: value, })); }); const typeSpace = async () => type(' '); const paste = async (payload, options = {}) => (0, react_2.act)(async () => { var _a; const types = (_a = options === null || options === void 0 ? void 0 : options.types) !== null && _a !== void 0 ? _a : ['text/html']; const event = new window.Event('paste', { bubbles: true, cancelable: true, composed: true, }); // @ts-ignore Typescript doesn't expect clipboardData on Event type event.clipboardData = { types, getData() { return payload; }, }; (0, react_2.fireEvent)(element, event); }); /** * Deletes forward one character from the current Slate selection. */ const deleteForward = async () => (0, react_2.act)(async () => { (0, react_2.fireEvent)(element, new InputEvent('beforeinput', { inputType: 'deleteContentForward' })); }); /** * Deletes backward one character from the current Slate selection. */ const deleteBackward = async () => (0, react_2.act)(async () => { (0, react_2.fireEvent)(element, new InputEvent('beforeinput', { inputType: 'deleteContentBackward' })); }); /** * Deletes the entire soft line in Slate backwards and forwards from current Slate selection. */ const deleteEntireSoftline = async () => (0, react_2.act)(async () => { (0, react_2.fireEvent)(element, new InputEvent('beforeinput', { inputType: 'deleteEntireSoftLine' })); }); /** * Deletes the entire block content backwards from current Slate selection. */ const deleteHardLineBackward = async () => (0, react_2.act)(async () => { (0, react_2.fireEvent)(element, new InputEvent('beforeinput', { inputType: 'deleteHardLineBackward', })); }); /** * Deletes the entire block content backwards from current Slate selection. */ const deleteSoftLineBackward = async () => (0, react_2.act)(async () => { (0, react_2.fireEvent)(element, new InputEvent('beforeinput', { inputType: 'deleteSoftLineBackward', })); }); /** * Deletes the entire block content forwards from current Slate selection. */ const deleteHardLineForward = async () => (0, react_2.act)(async () => { (0, react_2.fireEvent)(element, new InputEvent('beforeinput', { inputType: 'deleteHardLineForward' })); }); /** * Deletes the entire block content forwards from current Slate selection. */ const deleteSoftLineForward = async () => (0, react_2.act)(async () => { (0, react_2.fireEvent)(element, new InputEvent('beforeinput', { inputType: 'deleteSoftLineForward' })); }); /** * Deletes a word backwards from Slate's selection */ const deleteWordBackward = async () => (0, react_2.act)(async () => { (0, react_2.fireEvent)(element, new InputEvent('beforeinput', { inputType: 'deleteWordBackward' })); }); /** * Deletes a word forward from Slate's selection */ const deleteWordForward = async () => (0, react_2.act)(async () => { (0, react_2.fireEvent)(element, new InputEvent('beforeinput', { inputType: 'deleteWordForward' })); }); /** * Inserts a line break at the current selection. Simulates pressing 'Enter' in a contenteditable with Slate. */ const pressEnter = async () => (0, react_2.act)(async () => { await triggerKeyboardEvent('Enter'); (0, react_2.fireEvent)(element, new InputEvent('beforeinput', { inputType: 'insertParagraph' })); }); /** * Simulates the user pressing a key down. This is commonly used for testing hotkeys. */ const triggerKeyboardEvent = async (hotkey) => (0, react_2.act)(async () => { const eventProps = (0, is_hotkey_1.parseHotkey)(hotkey); const values = hotkey.split('+'); (0, react_2.fireEvent)(element, new window.KeyboardEvent('keydown', { key: values[values.length - 1], code: `${eventProps.which}`, keyCode: eventProps.which, bubbles: true, ...eventProps, })); }); const undo = async () => editor.undo(); const redo = async () => editor.redo(); // Keyboard shortcut wouldn't work within JSDOM so we emulate it const selectAll = async () => slate_1.Transforms.select(editor, []); if (debug) { const { apply } = editor; editor.apply = (args) => { // eslint-disable-next-line no-console console.log('OPERATION APPLIED', JSON.stringify(args, null, 2)); return apply(args); }; } return [ editor, { type, deleteForward, deleteBackward, deleteEntireSoftline, deleteHardLineBackward, deleteSoftLineBackward, deleteHardLineForward, deleteSoftLineForward, deleteWordBackward, deleteWordForward, triggerKeyboardEvent, paste, pressEnter, typeSpace, undo, redo, selectAll, isApple: utils_1.isApple, rerender: () => options.rerender((0, jsx_runtime_1.jsx)(Component, Object.assign({}, proppies), void 0)), }, options, ]; }; exports.buildTestHarness = buildTestHarness;