import { Assertions, Logger, Step } from '@ephox/agar'; import { Editor } from '../../alien/EditorTypes'; import { TinyDom } from '../TinyDom'; type SyncTestCallback = (initValue: T) => void; type AsyncTestCallback = (initValue: T, done: () => void, die: (err?: any) => void) => void; type Offset = 'after' | 'afterNextCharacter' | number; interface Suite { readonly test: (message: string, fn: SyncTestCallback) => void; readonly asyncTest: (message: string, fn: AsyncTestCallback) => void; readonly toSteps: (initValue: T) => Step[]; } const test = (message: string, fn: SyncTestCallback) => { return (initValue: T): Step => { return Logger.t( message, Step.sync(() => { fn(initValue); }) ); }; }; const asyncTest = (message: string, fn: AsyncTestCallback) => { return (initValue: T): Step => { return Logger.t( message, Step.async((done, die) => { fn(initValue, done, die); }) ); }; }; const createSuite = (): Suite => { const tests: Array<(initValue: T) => Step> = []; return { test: (message: string, fn: SyncTestCallback) => { tests.push(test(message, fn)); }, asyncTest: (message: string, fn: AsyncTestCallback) => { tests.push(asyncTest(message, fn)); }, toSteps: (initValue: T) => { return tests.map((test) => { return test(initValue); }); } }; }; const execCommand = (editor: T, cmd: string, ui?: boolean, value?: any): void => { if (editor.editorCommands.queryCommandSupported(cmd)) { editor.execCommand(cmd, ui, value); } }; const findContainer = (editor: T, selector: string | Node) => { let container; if (typeof selector === 'string') { container = editor.dom.select(selector)[0]; } else { container = selector; } if (container.firstChild) { container = container.firstChild; } return container; }; const setSelection = (editor: T, startSelector: string | Node, startOffset: Offset, endSelector?: string, endOffset?: Offset): void => { const startContainer = findContainer(editor, startSelector); const endContainer = findContainer(editor, endSelector ? endSelector : startSelector); const rng = editor.dom.createRng(); const setRange = (container: Node, offset: Offset | undefined, start: boolean) => { offset = offset ? offset : 0; if (offset === 'after') { if (start) { rng.setStartAfter(container); } else { rng.setEndAfter(container); } return; } else if (offset === 'afterNextCharacter') { container = container.nextSibling as Node; offset = 1; } if (start) { rng.setStart(container, offset); } else { rng.setEnd(container, offset); } }; setRange(startContainer, startOffset, true); setRange(endContainer, endSelector ? endOffset : startOffset, false); editor.selection.setRng(rng); }; const trimBrs = (html: string): string => { return html.toLowerCase().replace(/]*>|[\r\n]+/gi, ''); }; const equalDom = (actual: T, expected: T, message?: string): void => { Assertions.assertDomEq(typeof message !== 'undefined' ? message : 'Nodes are not equal', TinyDom.fromDom(expected), TinyDom.fromDom(actual)); }; const equal = (actual: T, expected: T, message?: string): void => { Assertions.assertEq(typeof message !== 'undefined' ? message : 'No message specified', expected, actual); }; const strictEqual = equal; const deepEqual = equal; export { test, asyncTest, createSuite, execCommand, setSelection, trimBrs, equal, equalDom, strictEqual, deepEqual };