UNPKG

@automattic/rtjson-to-wpblocks

Version:

Javascript code to convert Day One RTJson to WordPress Gutenberg Blocks

499 lines (453 loc) 11.3 kB
// @ts-check const dedent = require("dedent").default; const { describe, it, expect } = require("@jest/globals"); const { rtjNodesToHtml } = require("../nodes2html.js"); // 🚨 HEY! We're patching the String prototype here to make tests easier to write. String.prototype.fixWhitespace = function () { return this.replaceAll(/>[\n\r\s]+</g, ">\n<").replaceAll(/></g, ">\n<"); }; describe("Converting RTJson to GB Serialized Block format", () => { it("Should convert a paragraph node", () => { let node = { attributes: {}, text: "It has a paragraph\n", }; let expected = dedent` <p>It has a paragraph</p> `; expect(rtjNodesToHtml([node]).fixWhitespace()).toBe( expected.fixWhitespace() ); }); it("Should convert a header node as html", () => { let node2 = { attributes: { line: { header: 2, }, }, text: "Header 2\n", }; let expected2 = dedent` <h2 class="wp-block-heading">Header 2</h2> `; expect(rtjNodesToHtml([node2])).toBe(expected2); let node3 = { attributes: { line: { header: 3, }, }, text: "Header 3\n", }; // Quick strange note here. In actual testing with the GB editor, it seems that // An h2 can have the "{level: 2}" part completely omitted, but the other levels // require it. This library will always include it because that seems to be valid // behavior according to GB experimentation. let expected3 = dedent` <h3 class="wp-block-heading">Header 3</h3> `; expect(rtjNodesToHtml([node3])).toBe(expected3); let nodeForAnH1 = { attributes: { line: { header: 1, }, }, text: "Header 1\n", }; let expectedForAnH1 = dedent` <h1 class="wp-block-heading">Header 1</h1> `; expect(rtjNodesToHtml([nodeForAnH1])).toBe(expectedForAnH1); }); it("should handle a simple list as html", () => { /** @type {Array<RTJ.Node>} */ let nodes = [ { attributes: { line: { listStyle: "bulleted", indentLevel: 1, }, }, text: "one\n", }, { attributes: { line: { listStyle: "bulleted", indentLevel: 1, }, }, text: "two\n", }, ]; expect(rtjNodesToHtml(nodes)).toMatchInlineSnapshot( `"<ul><li>one</li><li>two</li></ul>"` ); }); it("Should handle complex lists as html", () => { /** @type {Array<RTJ.Node>} */ let nodes = [ { attributes: { line: { listStyle: "bulleted", indentLevel: 1, }, }, text: "And a list\n", }, { attributes: { line: { listStyle: "bulleted", indentLevel: 2, }, }, text: "Indented\n", }, { attributes: { line: { listStyle: "bulleted", indentLevel: 3, }, }, text: "again\n", }, ]; let expected = dedent` <ul> <li>And a list<ul> <li>Indented<ul> <li>again</li> </ul> </li> </ul> </li> </ul> `; expect(rtjNodesToHtml(nodes).fixWhitespace()).toBe( expected.fixWhitespace() ); }); it("Should handle different lists following each other as html", () => { /** @type {Array<RTJ.Node>} */ let nodes = [ { attributes: { line: { listStyle: "bulleted", indentLevel: 1, }, }, text: "And a bulleted list\n", }, { attributes: { line: { listStyle: "numbered", indentLevel: 1, }, }, text: "A numbered list\n", }, { attributes: { line: { listStyle: "numbered", indentLevel: 1, }, }, text: "numbered 2\n", }, ]; let expected = dedent` <ul> <li>And a bulleted list</li> </ul> <ol> <li>A numbered list</li> <li>numbered 2</li> </ol> `; expect(rtjNodesToHtml(nodes).fixWhitespace()).toBe( expected.fixWhitespace() ); }); it("Should handle a photo node as html", () => { /** @type {Array<RTJ.Node>} */ let nodes = [ { embeddedObjects: [ { type: "photo", identifier: "B7C0EB0794D04FF3B496308ED46D179A", }, ], }, ]; /** @type {MediaLookup} */ let lookup = { B7C0EB0794D04FF3B496308ED46D179A: { id: 11, url: "https://testposting.mystagingwebsite.com/wp-content/uploads/2024/06/IMG_7738-768x1024.jpeg", }, }; let expected = dedent` <figure class="wp-block-image size-large"><img src="https://testposting.mystagingwebsite.com/wp-content/uploads/2024/06/IMG_7738-768x1024.jpeg" alt="" class="wp-image-11"/></figure> `; expect(rtjNodesToHtml(nodes, lookup).fixWhitespace()).toBe( expected.fixWhitespace() ); }); it("Should handle italics and bold in the middle of a paragraph", () => { /** @type {Array<RTJNode>} */ let nodes = [ { attributes: {}, text: "Here is a paragraph ", }, { attributes: { bold: true, }, text: "with bold text", }, { attributes: {}, text: " and ", }, { attributes: { italic: true, }, text: "with italicized text", }, { attributes: {}, text: " and ", }, { attributes: { bold: true, italic: true, }, text: "with both", }, { attributes: {}, text: ".\n", }, ]; let expected = dedent` <p>Here is a paragraph <strong>with bold text</strong> and <em>with italicized text</em> and <strong><em>with both</em></strong>.</p> `; expect(rtjNodesToHtml(nodes).fixWhitespace()).toBe( expected.fixWhitespace() ); }); it("Should handle highlighted text in the middle of a paragraph as html", () => { let color = "#ffdddd"; /** @type {Array<RTJNode>} */ let nodes = [ { attributes: {}, text: "Here is a paragraph ", }, { attributes: { highlightedColor: color, }, text: "with highlighted text", }, { attributes: {}, text: ".\n", }, ]; let expected = dedent` <p>Here is a paragraph <mark data-rich-text-format-boundary="true" style="background-color:${color}" class="has-inline-color">with highlighted text</mark>.</p> `; expect(rtjNodesToHtml(nodes).fixWhitespace()).toBe( expected.fixWhitespace() ); }); it("Should handle inline code in the middle of a paragraph as html", () => { /** @type {Array<RTJNode>} */ let nodes = [ { attributes: {}, text: "Here is a paragraph ", }, { attributes: { inlineCode: true, }, text: "with some code", }, { attributes: {}, text: " in it.\n", }, ]; let expected = dedent` <p>Here is a paragraph <code>with some code</code> in it.</p> `; expect(rtjNodesToHtml(nodes).fixWhitespace()).toBe( expected.fixWhitespace() ); }); it("should handle block quote as html", () => { /** @type {Array<RTJNode>} */ let nodes = [ { attributes: { line: { quote: true, }, }, text: "Here is a quote block\n", }, ]; let expected = dedent` <blockquote class="wp-block-quote"> <p>Here is a quote block</p> </blockquote> `; expect(rtjNodesToHtml(nodes).fixWhitespace()).toBe( expected.fixWhitespace() ); }); it("should handle a multiple line block quote as html", () => { /** @type {Array<RTJNode>} */ let nodes = [ { attributes: { line: { quote: true, }, }, text: "Here is a quote block\n", }, { attributes: { line: { quote: true, }, }, text: "Here's the second line\n", }, ]; let expected = dedent` <blockquote class="wp-block-quote"> <p>Here is a quote block</p> <p>Here's the second line</p> </blockquote> `; expect(rtjNodesToHtml(nodes).fixWhitespace()).toBe( expected.fixWhitespace() ); }); it("should handle a code block", () => { /** @type {Array<RTJNode>} */ let nodes = [ { attributes: { line: { codeBlock: true, }, }, text: "Here is a code block\n", }, ]; let expected = dedent` <pre class="wp-block-code"><code>Here is a code block</code> </pre> `; expect(rtjNodesToHtml(nodes).fixWhitespace()).toBe( expected.fixWhitespace() ); }); it("should handle a horizontal ruler as html", () => { /** @type {Array<RTJNode>} */ let nodes = [ { embeddedObjects: [{ type: "horizontalRuleLine" }], }, ]; let expected = dedent` <hr class="wp-block-separator has-alpha-channel-opacity"/> `; expect(rtjNodesToHtml(nodes).fixWhitespace()).toBe( expected.fixWhitespace() ); }); it("should handle multiple quote nodes correctly as html", () => { /** @type {Array<RTJNode>} */ let nodes = [ { text: "First quote line ", attributes: { line: { quote: true }, }, }, { text: "still first paragraph\n", attributes: { line: { quote: true }, }, }, { text: "Second paragraph in quote\n", attributes: { line: { quote: true }, }, }, // Add a non-quote node to ensure quote block closes properly { text: "Regular paragraph\n", }, ]; let expected = dedent` <blockquote class="wp-block-quote"> <p>First quote line still first paragraph</p> <p>Second paragraph in quote</p> </blockquote> <p>Regular paragraph</p> `; expect(rtjNodesToHtml(nodes).fixWhitespace()).toBe( expected.fixWhitespace() ); }); it("should handle quotes with text formatting as html", () => { /** @type {Array<RTJNode>} */ let nodes = [ { text: "Quote with ", attributes: { line: { quote: true }, bold: true, }, }, { text: "mixed formatting\n", attributes: { line: { quote: true }, italic: true, }, }, ]; let expected = dedent` <blockquote class="wp-block-quote"> <p><strong>Quote with </strong><em>mixed formatting</em> </p> </blockquote> `; expect(rtjNodesToHtml(nodes).fixWhitespace()).toBe( expected.fixWhitespace() ); }); });