Skip to content

Commit

Permalink
Add basic selection tests
Browse files Browse the repository at this point in the history
  • Loading branch information
trueadm authored and acywatson committed Apr 9, 2022
1 parent 77cabff commit 163b1d2
Show file tree
Hide file tree
Showing 6 changed files with 253 additions and 6 deletions.
1 change: 1 addition & 0 deletions .flowconfig
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
[ignore]
.*/scripts/.*
.*/build/.*
.*/__tests__/.*
.*/dist/.*
.*/.tempUserDataDir/.*
.*/node_modules/.*
Expand Down
1 change: 1 addition & 0 deletions .watchmanconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{}
5 changes: 5 additions & 0 deletions babel.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
'use strict';

module.exports = {
presets: ['@babel/preset-env', '@babel/preset-react'],
};
5 changes: 4 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@
"build": "node scripts/build.js",
"build-prod": "node scripts/build.js --prod",
"watch": "node scripts/build.js --watch",
"flow": "node ./scripts/tasks/flow.js"
"flow": "node ./scripts/tasks/flow.js",
"test": "jest",
"debug-test": "node --inspect-brk node_modules/.bin/jest --runInBand"
},
"devDependencies": {
"@babel/plugin-transform-flow-strip-types": "^7.12.1",
Expand All @@ -38,6 +40,7 @@
"jest": "26.6.0",
"minimist": "^1.2.5",
"prettier": "^2.1.2",
"react-test-renderer": "^17.0.1",
"rollup": "^2.33.1"
}
}
219 changes: 219 additions & 0 deletions packages/outline/src/__tests__/OutlineSelection-test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,219 @@
let container = null;
let React;
let ReactDOM;
let ReactTestUtils;
let Outline;

function sanitizeHTML(html) {
// Remove the special space characters
return html.replace(/\uFEFF/g, '');
}

function insertText(text) {
return {
type: 'insert_text',
text,
};
}

function deleteBackward() {
return {
type: 'delete_backward',
text: null,
};
}

function deleteForward() {
return {
type: 'delete_forward',
text: null,
};
}

function setNativeSelection(
anchorPath,
anchorOffset,
focusPath,
focusOffset,
isCollapsed = false,
) {
return {
type: 'set_native_selection',
anchorPath,
anchorOffset,
focusPath,
focusOffset,
isCollapsed,
};
}

function getNodeFromPath(path, editorElement) {
let node = editorElement;
for (let i = 0; i < path.length; i++) {
node = node.childNodes[path[i]];
}
return node;
}

function updateNativeSelection(
editorElement,
anchorPath,
anchorOffset,
focusPath,
focusOffset,
isCollapsed = false,
) {
const anchorNode = getNodeFromPath(anchorPath, editorElement);
const focusNode = getNodeFromPath(focusPath, editorElement);
const domSelection = window.getSelection();
const range = document.createRange();
range.collapse(isCollapsed);
range.setStart(anchorNode, anchorOffset);
range.setEnd(focusNode, focusOffset);
domSelection.removeAllRanges();
domSelection.addRange(range);
}

function applySelectionInputs(inputs, update, editor) {
const editorElement = editor.getEditorElement();
inputs.forEach((input) => {
update((view) => {
const selection = view.getSelection();

switch (input.type) {
case 'insert_text': {
selection.insertText(input.text);
break;
}
case 'delete_backward': {
selection.deleteBackward();
break;
}
case 'delete_forward': {
selection.deleteForward();
break;
}
case 'set_native_selection': {
updateNativeSelection(
editorElement,
input.anchorPath,
input.anchorOffset,
input.focusPath,
input.focusOffset,
input.isCollapsed,
);
break;
}
default:
console.log('TODO');
}
});
});
}

describe('OutlineSelection tests', () => {
beforeEach(() => {
React = require('react');
ReactDOM = require('react-dom');
ReactTestUtils = require('react-dom/test-utils');
Outline = require('outline');

container = document.createElement('div');
document.body.appendChild(container);
init();
});

let editor = null;

function init() {
const ref = React.createRef();

function TestBase() {
editor = Outline.useOutlineEditor(ref);
return <div ref={ref} contentEditable={true} />;
}

ReactTestUtils.act(() => {
ReactDOM.render(<TestBase />, container);
});
ref.current.focus();

// Insert initial block
update((view) => {
const paragraph = Outline.createParagraph();
const text = Outline.createText();
paragraph.append(text);
view.getBody().append(paragraph);
});

// Focus first element
updateNativeSelection(ref.current, [0, 0, 0], 0, [0, 0, 0], 0);
}

function update(callback) {
const viewModel = editor.createViewModel(callback);
editor.update(viewModel, true);
}

afterEach(() => {
document.body.removeChild(container);
container = null;
});

test('Expect initial output to be a block with some text', () => {
expect(sanitizeHTML(container.innerHTML)).toBe(
'<div contenteditable="true"><p><span data-text="true"><br></span></p></div>',
);
});

const suite = [
{
inputs: [
insertText('H'),
insertText('e'),
insertText('l'),
insertText('l'),
insertText('o'),
],
result:
'<div contenteditable="true"><p dir="ltr"><span data-text="true">Hello</span></p></div>',
},
{
inputs: [
insertText('1'),
insertText('2'),
insertText('3'),
deleteBackward(),
insertText('4'),
insertText('5'),
deleteBackward(),
insertText('6'),
deleteForward(),
],
result:
'<div contenteditable="true"><p><span data-text="true">1246</span></p></div>',
},
{
inputs: [
insertText('1'),
insertText('1'),
insertText('2'),
insertText('3'),
setNativeSelection([0, 0, 0], 0, [0, 0, 0], 0),
insertText('a'),
insertText('b'),
insertText('c'),
deleteForward(),
],
result:
'<div contenteditable="true"><p dir="ltr"><span data-text="true">abc123</span></p></div>',
},
];

suite.forEach((testUnit, i) => {
test('Test case #' + (i + 1), () => {
applySelectionInputs(testUnit.inputs, update, editor);
expect(sanitizeHTML(container.innerHTML)).toBe(testUnit.result);
});
});
});
28 changes: 23 additions & 5 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -9018,16 +9018,16 @@ react-error-overlay@^6.0.8:
resolved "https://registry.yarnpkg.com/react-error-overlay/-/react-error-overlay-6.0.8.tgz#474ed11d04fc6bda3af643447d85e9127ed6b5de"
integrity sha512-HvPuUQnLp5H7TouGq3kzBeioJmXms1wHy9EGjz2OURWBp4qZO6AfGEcnxts1D/CbwPLRAgTMPCEgYhA3sEM4vw==

"react-is@^16.12.0 || ^17.0.0", react-is@^17.0.1:
version "17.0.1"
resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.1.tgz#5b3531bd76a645a4c9fb6e693ed36419e3301339"
integrity sha512-NAnt2iGDXohE5LI7uBnLnqvLQMtzhkiAOLXTmv+qnF9Ky7xAPcX8Up/xWIhxvLVGJvuLiNc4xQLtuqDRzb4fSA==

react-is@^16.8.1:
version "16.13.1"
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"
integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==

react-is@^17.0.1:
version "17.0.1"
resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.1.tgz#5b3531bd76a645a4c9fb6e693ed36419e3301339"
integrity sha512-NAnt2iGDXohE5LI7uBnLnqvLQMtzhkiAOLXTmv+qnF9Ky7xAPcX8Up/xWIhxvLVGJvuLiNc4xQLtuqDRzb4fSA==

react-refresh@^0.8.3:
version "0.8.3"
resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.8.3.tgz#721d4657672d400c5e3c75d063c4a85fb2d5d68f"
Expand Down Expand Up @@ -9098,6 +9098,24 @@ react-scripts@4.0.0:
optionalDependencies:
fsevents "^2.1.3"

react-shallow-renderer@^16.13.1:
version "16.14.1"
resolved "https://registry.yarnpkg.com/react-shallow-renderer/-/react-shallow-renderer-16.14.1.tgz#bf0d02df8a519a558fd9b8215442efa5c840e124"
integrity sha512-rkIMcQi01/+kxiTE9D3fdS959U1g7gs+/rborw++42m1O9FAQiNI/UNRZExVUoAOprn4umcXf+pFRou8i4zuBg==
dependencies:
object-assign "^4.1.1"
react-is "^16.12.0 || ^17.0.0"

react-test-renderer@^17.0.1:
version "17.0.1"
resolved "https://registry.yarnpkg.com/react-test-renderer/-/react-test-renderer-17.0.1.tgz#3187e636c3063e6ae498aedf21ecf972721574c7"
integrity sha512-/dRae3mj6aObwkjCcxZPlxDFh73XZLgvwhhyON2haZGUEhiaY5EjfAdw+d/rQmlcFwdTpMXCSGVk374QbCTlrA==
dependencies:
object-assign "^4.1.1"
react-is "^17.0.1"
react-shallow-renderer "^16.13.1"
scheduler "^0.20.1"

react@^17.0.1:
version "17.0.1"
resolved "https://registry.yarnpkg.com/react/-/react-17.0.1.tgz#6e0600416bd57574e3f86d92edba3d9008726127"
Expand Down

0 comments on commit 163b1d2

Please sign in to comment.