From 2aa82394480104ebd4ee5e01b4054c07fdbb2758 Mon Sep 17 00:00:00 2001 From: Ian Storm Taylor Date: Wed, 13 Jul 2016 18:56:03 -0700 Subject: [PATCH] fix wrapInline selecting, add rendering tests --- .eslintrc | 1 + lib/components/leaf.js | 1 - lib/models/state.js | 17 ++++-- test/rendering/fixtures/custom-block/index.js | 10 ++++ .../fixtures/custom-block/input.yaml | 14 +++++ .../fixtures/custom-block/output.html | 15 +++++ .../rendering/fixtures/custom-inline/index.js | 11 ++++ .../fixtures/custom-inline/input.yaml | 13 ++++ .../fixtures/custom-inline/output.html | 10 ++++ .../default-block-and-inline/index.js | 4 ++ .../default-block-and-inline/input.yaml | 11 ++++ .../default-block-and-inline/output.html | 10 ++++ .../rendering/fixtures/default-block/index.js | 4 ++ .../fixtures/default-block/input.yaml | 8 +++ .../fixtures/default-block/output.html | 8 +++ .../fixtures/multiple-custom-block/index.js | 10 ++++ .../fixtures/multiple-custom-block/input.yaml | 20 +++++++ .../multiple-custom-block/output.html | 22 +++++++ .../fixtures/multiple-custom-inline/index.js | 11 ++++ .../multiple-custom-inline/input.yaml | 21 +++++++ .../multiple-custom-inline/output.html | 15 +++++ test/rendering/index.js | 59 +++++++++++++++++++ test/server.js | 1 + test/transforms/index.js | 2 +- 24 files changed, 292 insertions(+), 6 deletions(-) create mode 100644 test/rendering/fixtures/custom-block/index.js create mode 100644 test/rendering/fixtures/custom-block/input.yaml create mode 100644 test/rendering/fixtures/custom-block/output.html create mode 100644 test/rendering/fixtures/custom-inline/index.js create mode 100644 test/rendering/fixtures/custom-inline/input.yaml create mode 100644 test/rendering/fixtures/custom-inline/output.html create mode 100644 test/rendering/fixtures/default-block-and-inline/index.js create mode 100644 test/rendering/fixtures/default-block-and-inline/input.yaml create mode 100644 test/rendering/fixtures/default-block-and-inline/output.html create mode 100644 test/rendering/fixtures/default-block/index.js create mode 100644 test/rendering/fixtures/default-block/input.yaml create mode 100644 test/rendering/fixtures/default-block/output.html create mode 100644 test/rendering/fixtures/multiple-custom-block/index.js create mode 100644 test/rendering/fixtures/multiple-custom-block/input.yaml create mode 100644 test/rendering/fixtures/multiple-custom-block/output.html create mode 100644 test/rendering/fixtures/multiple-custom-inline/index.js create mode 100644 test/rendering/fixtures/multiple-custom-inline/input.yaml create mode 100644 test/rendering/fixtures/multiple-custom-inline/output.html create mode 100644 test/rendering/index.js diff --git a/.eslintrc b/.eslintrc index b737d1bcf..7947fc265 100644 --- a/.eslintrc +++ b/.eslintrc @@ -14,6 +14,7 @@ }, "env": { "browser": true, + "mocha": true, "node": true }, "rules": { diff --git a/lib/components/leaf.js b/lib/components/leaf.js index e4491633c..8585c767c 100644 --- a/lib/components/leaf.js +++ b/lib/components/leaf.js @@ -72,7 +72,6 @@ class Leaf extends React.Component { const native = window.getSelection() const el = ReactDOM.findDOMNode(this).firstChild - // If both the start and end are here, set the selection all at once. if (hasStart && hasEnd) { native.removeAllRanges() diff --git a/lib/models/state.js b/lib/models/state.js index 064ed9fe4..121abf3f1 100644 --- a/lib/models/state.js +++ b/lib/models/state.js @@ -858,10 +858,19 @@ class State extends new Record(DEFAULTS) { document = document.wrapInlineAtRange(selection, type, data) // Determine what the selection should be after wrapping. - if (selection.isExpanded) { - const start = document.getNextText(selection.startKey) - const end = document.getPreviousText(selection.endKey) - selection = selection.moveToRangeOf(start, end) + if (selection.isCollapsed) { + selection = selection + } + + else if (selection.startOffset == 0) { + const text = document.getDescendant(selection.startKey) + selection = selection.moveToRangeOf(text) + selection = selection.normalize(document) + } + + else { + const text = document.getNextText(selection.startKey) + selection = selection.moveToRangeOf(text) selection = selection.normalize(document) } diff --git a/test/rendering/fixtures/custom-block/index.js b/test/rendering/fixtures/custom-block/index.js new file mode 100644 index 000000000..7cb16796d --- /dev/null +++ b/test/rendering/fixtures/custom-block/index.js @@ -0,0 +1,10 @@ + +import React from 'react' + +function Code(props) { + return
{props.children}
+} + +export function renderNode(node) { + if (node.type == 'code') return Code +} diff --git a/test/rendering/fixtures/custom-block/input.yaml b/test/rendering/fixtures/custom-block/input.yaml new file mode 100644 index 000000000..ab7f93d42 --- /dev/null +++ b/test/rendering/fixtures/custom-block/input.yaml @@ -0,0 +1,14 @@ + +nodes: + - kind: block + type: default + nodes: + - kind: text + ranges: + - text: word + - kind: block + type: code + nodes: + - kind: text + ranges: + - text: another diff --git a/test/rendering/fixtures/custom-block/output.html b/test/rendering/fixtures/custom-block/output.html new file mode 100644 index 000000000..42a82304a --- /dev/null +++ b/test/rendering/fixtures/custom-block/output.html @@ -0,0 +1,15 @@ + +
+
+ + word + +
+
+    
+      
+        another
+      
+    
+  
+
diff --git a/test/rendering/fixtures/custom-inline/index.js b/test/rendering/fixtures/custom-inline/index.js new file mode 100644 index 000000000..da3646fee --- /dev/null +++ b/test/rendering/fixtures/custom-inline/index.js @@ -0,0 +1,11 @@ + +import React from 'react' + +function Link(props) { + const href = props.node.data.get('href') + return {props.children} +} + +export function renderNode(node) { + if (node.type == 'link') return Link +} diff --git a/test/rendering/fixtures/custom-inline/input.yaml b/test/rendering/fixtures/custom-inline/input.yaml new file mode 100644 index 000000000..bb0a47aed --- /dev/null +++ b/test/rendering/fixtures/custom-inline/input.yaml @@ -0,0 +1,13 @@ + +nodes: + - kind: block + type: default + nodes: + - kind: inline + type: link + data: + href: https://google.com + nodes: + - kind: text + ranges: + - text: word diff --git a/test/rendering/fixtures/custom-inline/output.html b/test/rendering/fixtures/custom-inline/output.html new file mode 100644 index 000000000..b4a008d65 --- /dev/null +++ b/test/rendering/fixtures/custom-inline/output.html @@ -0,0 +1,10 @@ + +
+
+ + + word + + +
+
diff --git a/test/rendering/fixtures/default-block-and-inline/index.js b/test/rendering/fixtures/default-block-and-inline/index.js new file mode 100644 index 000000000..dbf0139ef --- /dev/null +++ b/test/rendering/fixtures/default-block-and-inline/index.js @@ -0,0 +1,4 @@ + +/** + * Nothing, pure defaults. + */ diff --git a/test/rendering/fixtures/default-block-and-inline/input.yaml b/test/rendering/fixtures/default-block-and-inline/input.yaml new file mode 100644 index 000000000..353b1de1f --- /dev/null +++ b/test/rendering/fixtures/default-block-and-inline/input.yaml @@ -0,0 +1,11 @@ + +nodes: + - kind: block + type: default + nodes: + - kind: inline + type: default + nodes: + - kind: text + ranges: + - text: word diff --git a/test/rendering/fixtures/default-block-and-inline/output.html b/test/rendering/fixtures/default-block-and-inline/output.html new file mode 100644 index 000000000..0544dc005 --- /dev/null +++ b/test/rendering/fixtures/default-block-and-inline/output.html @@ -0,0 +1,10 @@ + +
+
+ + + word + + +
+
diff --git a/test/rendering/fixtures/default-block/index.js b/test/rendering/fixtures/default-block/index.js new file mode 100644 index 000000000..dbf0139ef --- /dev/null +++ b/test/rendering/fixtures/default-block/index.js @@ -0,0 +1,4 @@ + +/** + * Nothing, pure defaults. + */ diff --git a/test/rendering/fixtures/default-block/input.yaml b/test/rendering/fixtures/default-block/input.yaml new file mode 100644 index 000000000..9c6aefff6 --- /dev/null +++ b/test/rendering/fixtures/default-block/input.yaml @@ -0,0 +1,8 @@ + +nodes: + - kind: block + type: default + nodes: + - kind: text + ranges: + - text: word diff --git a/test/rendering/fixtures/default-block/output.html b/test/rendering/fixtures/default-block/output.html new file mode 100644 index 000000000..94d33447a --- /dev/null +++ b/test/rendering/fixtures/default-block/output.html @@ -0,0 +1,8 @@ + +
+
+ + word + +
+
diff --git a/test/rendering/fixtures/multiple-custom-block/index.js b/test/rendering/fixtures/multiple-custom-block/index.js new file mode 100644 index 000000000..7cb16796d --- /dev/null +++ b/test/rendering/fixtures/multiple-custom-block/index.js @@ -0,0 +1,10 @@ + +import React from 'react' + +function Code(props) { + return
{props.children}
+} + +export function renderNode(node) { + if (node.type == 'code') return Code +} diff --git a/test/rendering/fixtures/multiple-custom-block/input.yaml b/test/rendering/fixtures/multiple-custom-block/input.yaml new file mode 100644 index 000000000..92c5c3fbb --- /dev/null +++ b/test/rendering/fixtures/multiple-custom-block/input.yaml @@ -0,0 +1,20 @@ + +nodes: + - kind: block + type: default + nodes: + - kind: text + ranges: + - text: word + - kind: block + type: code + nodes: + - kind: text + ranges: + - text: another + - kind: block + type: code + nodes: + - kind: text + ranges: + - text: third diff --git a/test/rendering/fixtures/multiple-custom-block/output.html b/test/rendering/fixtures/multiple-custom-block/output.html new file mode 100644 index 000000000..a3bb0eda5 --- /dev/null +++ b/test/rendering/fixtures/multiple-custom-block/output.html @@ -0,0 +1,22 @@ + +
+
+ + word + +
+
+    
+      
+        another
+      
+    
+  
+
+    
+      
+        third
+      
+    
+  
+
diff --git a/test/rendering/fixtures/multiple-custom-inline/index.js b/test/rendering/fixtures/multiple-custom-inline/index.js new file mode 100644 index 000000000..da3646fee --- /dev/null +++ b/test/rendering/fixtures/multiple-custom-inline/index.js @@ -0,0 +1,11 @@ + +import React from 'react' + +function Link(props) { + const href = props.node.data.get('href') + return {props.children} +} + +export function renderNode(node) { + if (node.type == 'link') return Link +} diff --git a/test/rendering/fixtures/multiple-custom-inline/input.yaml b/test/rendering/fixtures/multiple-custom-inline/input.yaml new file mode 100644 index 000000000..8bdbdc47a --- /dev/null +++ b/test/rendering/fixtures/multiple-custom-inline/input.yaml @@ -0,0 +1,21 @@ + +nodes: + - kind: block + type: default + nodes: + - kind: inline + type: link + data: + href: https://google.com + nodes: + - kind: text + ranges: + - text: another + - kind: inline + type: link + data: + href: https://google.com + nodes: + - kind: text + ranges: + - text: word diff --git a/test/rendering/fixtures/multiple-custom-inline/output.html b/test/rendering/fixtures/multiple-custom-inline/output.html new file mode 100644 index 000000000..6ed4e2bd9 --- /dev/null +++ b/test/rendering/fixtures/multiple-custom-inline/output.html @@ -0,0 +1,15 @@ + +
+
+ + + another + + + + + word + + +
+
diff --git a/test/rendering/index.js b/test/rendering/index.js new file mode 100644 index 000000000..8189e3a6b --- /dev/null +++ b/test/rendering/index.js @@ -0,0 +1,59 @@ + +import React from 'react' +import ReactDOM from 'react-dom/server' +import assert from 'assert' +import cheerio from 'cheerio' +import fs from 'fs' +import readMetadata from 'read-metadata' +import { Editor, Raw } from '../..' +import { resolve } from 'path' + +/** + * Tests. + */ + +describe('rendering', () => { + const tests = fs.readdirSync(resolve(__dirname, './fixtures')) + + for (const test of tests) { + it(test, () => { + const dir = resolve(__dirname, './fixtures', test) + const input = readMetadata.sync(resolve(dir, 'input.yaml')) + const output = fs.readFileSync(resolve(dir, 'output.html'), 'utf8') + const props = { + state: Raw.deserialize(input), + onChange: () => {}, + ...require(dir) + } + + const string = ReactDOM.renderToStaticMarkup() + const expected = cheerio + .load(output) + .html() + .trim() + .replace(/\n/gm, '') + .replace(/>\s*<') + + assert.equal(clean(string), expected) + }) + } +}) + +/** + * Clean a renderer `html` string, removing dynamic attributes. + * + * @param {String} html + * @return {String} + */ + +function clean(html) { + const $ = cheerio.load(html) + + $('*').each((i, el) => { + $(el).removeAttr('data-key') + $(el).removeAttr('data-offset-key') + $(el).removeAttr('style') + }) + + return $.html() +} diff --git a/test/server.js b/test/server.js index f36494c7b..6072ef27d 100644 --- a/test/server.js +++ b/test/server.js @@ -1,2 +1,3 @@ +import './rendering' import './transforms' diff --git a/test/transforms/index.js b/test/transforms/index.js index 65a63f760..a301afb4a 100644 --- a/test/transforms/index.js +++ b/test/transforms/index.js @@ -16,7 +16,7 @@ describe('transforms', () => { const transforms = fs.readdirSync(dir) for (const transform of transforms) { - describe(toCamel(transform), () => { + describe(`${toCamel(transform)}()`, () => { const dir = resolve(__dirname, './fixtures', transform) const tests = fs.readdirSync(dir)