From e8a31edeba41fd7e0af1291fe543915fc39583c5 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Thu, 25 Jul 2019 17:27:47 +0200 Subject: [PATCH] test html to editor model deserialization --- test/editor/deserialize-test.js | 226 ++++++++++++++++++++++++++++++++ 1 file changed, 226 insertions(+) create mode 100644 test/editor/deserialize-test.js diff --git a/test/editor/deserialize-test.js b/test/editor/deserialize-test.js new file mode 100644 index 0000000000..c7e0278f52 --- /dev/null +++ b/test/editor/deserialize-test.js @@ -0,0 +1,226 @@ +/* +Copyright 2019 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import expect from 'expect'; +import {parseEvent} from "../../src/editor/deserialize"; +import {createPartCreator} from "./mock"; + +function htmlMessage(formattedBody, msgtype = "m.text") { + return { + getContent() { + return { + msgtype, + format: "org.matrix.custom.html", + formatted_body: formattedBody, + }; + }, + }; +} + +function textMessage(body, msgtype = "m.text") { + return { + getContent() { + return { + msgtype, + body, + }; + }, + }; +} + +function mergeAdjacentParts(parts) { + let prevPart; + for (let i = 0; i < parts.length; ++i) { + let part = parts[i]; + const isEmpty = !part.text.length; + const isMerged = !isEmpty && prevPart && prevPart.merge(part); + if (isEmpty || isMerged) { + // remove empty or merged part + part = prevPart; + parts.splice(i, 1); + //repeat this index, as it's removed now + --i; + } + prevPart = part; + } +} + +function normalize(parts) { + // merge adjacent parts as this will happen + // in the model anyway, and whether 1 or multiple + // plain parts are returned is an implementation detail + mergeAdjacentParts(parts); + // convert to data objects for easier asserting + return parts.map(p => p.serialize()); +} + +describe('editor/deserialize', function() { + describe('text messages', function() { + it('test with newlines', function() { + const parts = normalize(parseEvent(textMessage("hello\nworld"), createPartCreator())); + expect(parts.length).toBe(3); + expect(parts[0]).toStrictEqual({type: "plain", text: "hello"}); + expect(parts[1]).toStrictEqual({type: "newline", text: "\n"}); + expect(parts[2]).toStrictEqual({type: "plain", text: "world"}); + }); + it('@room pill', function() { + const parts = normalize(parseEvent(textMessage("text message for @room"), createPartCreator())); + expect(parts.length).toBe(2); + expect(parts[0]).toStrictEqual({type: "plain", text: "text message for "}); + expect(parts[1]).toStrictEqual({type: "at-room-pill", text: "@room"}); + }); + it('emote', function() { + const text = "says DON'T SHOUT!"; + const parts = normalize(parseEvent(textMessage(text, "m.emote"), createPartCreator())); + expect(parts.length).toBe(1); + expect(parts[0]).toStrictEqual({type: "plain", text: "/me says DON'T SHOUT!"}); + }); + }); + describe('html messages', function() { + it('inline styling', function() { + const html = "bold and emphasized text"; + const parts = normalize(parseEvent(htmlMessage(html), createPartCreator())); + expect(parts.length).toBe(1); + expect(parts[0]).toStrictEqual({type: "plain", text: "**bold** and *emphasized* text"}); + }); + it('hyperlink', function() { + const html = 'click this!'; + const parts = normalize(parseEvent(htmlMessage(html), createPartCreator())); + expect(parts.length).toBe(1); + expect(parts[0]).toStrictEqual({type: "plain", text: "click [this](http://example.com/)!"}); + }); + it('multiple lines with paragraphs', function() { + const html = '

hello

world

'; + const parts = normalize(parseEvent(htmlMessage(html), createPartCreator())); + expect(parts.length).toBe(3); + expect(parts[0]).toStrictEqual({type: "plain", text: "hello"}); + expect(parts[1]).toStrictEqual({type: "newline", text: "\n"}); + expect(parts[2]).toStrictEqual({type: "plain", text: "world"}); + }); + it('multiple lines with line breaks', function() { + const html = 'hello
world'; + const parts = normalize(parseEvent(htmlMessage(html), createPartCreator())); + expect(parts.length).toBe(3); + expect(parts[0]).toStrictEqual({type: "plain", text: "hello"}); + expect(parts[1]).toStrictEqual({type: "newline", text: "\n"}); + expect(parts[2]).toStrictEqual({type: "plain", text: "world"}); + }); + it('multiple lines mixing paragraphs and line breaks', function() { + const html = '

hello
warm

world

'; + const parts = normalize(parseEvent(htmlMessage(html), createPartCreator())); + expect(parts.length).toBe(5); + expect(parts[0]).toStrictEqual({type: "plain", text: "hello"}); + expect(parts[1]).toStrictEqual({type: "newline", text: "\n"}); + expect(parts[2]).toStrictEqual({type: "plain", text: "warm"}); + expect(parts[3]).toStrictEqual({type: "newline", text: "\n"}); + expect(parts[4]).toStrictEqual({type: "plain", text: "world"}); + }); + it('quote', function() { + const html = '

wise
words

indeed

'; + const parts = normalize(parseEvent(htmlMessage(html), createPartCreator())); + expect(parts.length).toBe(6); + expect(parts[0]).toStrictEqual({type: "plain", text: "> *wise*"}); + expect(parts[1]).toStrictEqual({type: "newline", text: "\n"}); + expect(parts[2]).toStrictEqual({type: "plain", text: "> **words**"}); + expect(parts[3]).toStrictEqual({type: "newline", text: "\n"}); + expect(parts[4]).toStrictEqual({type: "newline", text: "\n"}); + expect(parts[5]).toStrictEqual({type: "plain", text: "indeed"}); + }); + it('user pill', function() { + const html = "Hi Alice!"; + const parts = normalize(parseEvent(htmlMessage(html), createPartCreator())); + expect(parts.length).toBe(3); + expect(parts[0]).toStrictEqual({type: "plain", text: "Hi "}); + expect(parts[1]).toStrictEqual({type: "user-pill", text: "Alice", userId: "@alice:hs.tld"}); + expect(parts[2]).toStrictEqual({type: "plain", text: "!"}); + }); + it('room pill', function() { + const html = "Try #room:hs.tld?"; + const parts = normalize(parseEvent(htmlMessage(html), createPartCreator())); + expect(parts.length).toBe(3); + expect(parts[0]).toStrictEqual({type: "plain", text: "Try "}); + expect(parts[1]).toStrictEqual({type: "room-pill", text: "#room:hs.tld"}); + expect(parts[2]).toStrictEqual({type: "plain", text: "?"}); + }); + it('@room pill', function() { + const html = "formatted message for @room"; + const parts = normalize(parseEvent(htmlMessage(html), createPartCreator())); + expect(parts.length).toBe(2); + expect(parts[0]).toStrictEqual({type: "plain", text: "*formatted* message for "}); + expect(parts[1]).toStrictEqual({type: "at-room-pill", text: "@room"}); + }); + it('inline code', function() { + const html = "there is no place like 127.0.0.1!"; + const parts = normalize(parseEvent(htmlMessage(html), createPartCreator())); + expect(parts.length).toBe(1); + expect(parts[0]).toStrictEqual({type: "plain", text: "there is no place like `127.0.0.1`!"}); + }); + it('code block with no trailing text', function() { + const html = "
0xDEADBEEF\n
\n"; + const parts = normalize(parseEvent(htmlMessage(html), createPartCreator())); + console.log(parts); + expect(parts.length).toBe(5); + expect(parts[0]).toStrictEqual({type: "plain", text: "```"}); + expect(parts[1]).toStrictEqual({type: "newline", text: "\n"}); + expect(parts[2]).toStrictEqual({type: "plain", text: "0xDEADBEEF"}); + expect(parts[3]).toStrictEqual({type: "newline", text: "\n"}); + expect(parts[4]).toStrictEqual({type: "plain", text: "```"}); + }); + // failing likely because of https://github.com/vector-im/riot-web/issues/10316 + xit('code block with no trailing text and no newlines', function() { + const html = "
0xDEADBEEF
"; + const parts = normalize(parseEvent(htmlMessage(html), createPartCreator())); + expect(parts.length).toBe(5); + expect(parts[0]).toStrictEqual({type: "plain", text: "```"}); + expect(parts[1]).toStrictEqual({type: "newline", text: "\n"}); + expect(parts[2]).toStrictEqual({type: "plain", text: "0xDEADBEEF"}); + expect(parts[3]).toStrictEqual({type: "newline", text: "\n"}); + expect(parts[4]).toStrictEqual({type: "plain", text: "```"}); + }); + it('unordered lists', function() { + const html = ""; + const parts = normalize(parseEvent(htmlMessage(html), createPartCreator())); + expect(parts.length).toBe(5); + expect(parts[0]).toStrictEqual({type: "plain", text: "- Oak"}); + expect(parts[1]).toStrictEqual({type: "newline", text: "\n"}); + expect(parts[2]).toStrictEqual({type: "plain", text: "- Spruce"}); + expect(parts[3]).toStrictEqual({type: "newline", text: "\n"}); + expect(parts[4]).toStrictEqual({type: "plain", text: "- Birch"}); + }); + it('ordered lists', function() { + const html = "
  1. Start
  2. Continue
  3. Finish
"; + const parts = normalize(parseEvent(htmlMessage(html), createPartCreator())); + expect(parts.length).toBe(5); + expect(parts[0]).toStrictEqual({type: "plain", text: "1. Start"}); + expect(parts[1]).toStrictEqual({type: "newline", text: "\n"}); + expect(parts[2]).toStrictEqual({type: "plain", text: "1. Continue"}); + expect(parts[3]).toStrictEqual({type: "newline", text: "\n"}); + expect(parts[4]).toStrictEqual({type: "plain", text: "1. Finish"}); + }); + it('mx-reply is stripped', function() { + const html = "foobar"; + const parts = normalize(parseEvent(htmlMessage(html), createPartCreator())); + expect(parts.length).toBe(1); + expect(parts[0]).toStrictEqual({type: "plain", text: "bar"}); + }); + it('emote', function() { + const html = "says DON'T SHOUT!"; + const parts = normalize(parseEvent(htmlMessage(html, "m.emote"), createPartCreator())); + expect(parts.length).toBe(1); + expect(parts[0]).toStrictEqual({type: "plain", text: "/me says *DON'T SHOUT*!"}); + }); + }); +});