@automattic/rtjson-to-wpblocks
Version:
Javascript code to convert Day One RTJson to WordPress Gutenberg Blocks
741 lines (706 loc) • 17.4 kB
JavaScript
// @ts-check
const dedent = require("dedent").default;
const { describe, it, expect } = require("@jest/globals");
const { buildNodeTree } = require("../build-node-tree.js");
describe("Test text nodes", () => {
it("Should return a paragraph with one node", () => {
let node = {
attributes: {},
text: "It has a paragraph\n",
};
let expected = [
{
type: "paragraph",
content: [
{ type: "text", attributes: {}, text: "It has a paragraph\n" },
],
},
];
expect(buildNodeTree([node])).toEqual(expected);
});
it("Should handle multiple paragraphs without merging them", () => {
let nodes = [
{
attributes: {},
text: "It has a paragraph\n",
},
{
attributes: {},
text: "Second paragraph\n",
},
{
attributes: {},
text: "Third paragraph\n",
},
];
let expected = [
{
type: "paragraph",
content: [
{ type: "text", attributes: {}, text: "It has a paragraph\n" },
],
},
{
type: "paragraph",
content: [{ type: "text", attributes: {}, text: "Second paragraph\n" }],
},
{
type: "paragraph",
content: [{ type: "text", attributes: {}, text: "Third paragraph\n" }],
},
];
expect(buildNodeTree(nodes)).toEqual(expected);
});
it("Should return header node", () => {
let nodeH2 = {
attributes: {
line: {
header: 2,
},
},
text: "Header 2\n",
};
let expectedH2 = [
{
type: "header",
content: [{ type: "text", ...nodeH2 }],
},
];
expect(buildNodeTree([nodeH2])).toEqual(expectedH2);
let nodeH3 = {
attributes: {
line: {
header: 3,
},
},
text: "Header 3\n",
};
let expectedH3 = [
{
type: "header",
content: [{ type: "text", ...nodeH3 }],
},
];
expect(buildNodeTree([nodeH3])).toEqual(expectedH3);
let nodeH1 = {
attributes: {
line: {
header: 1,
},
},
text: "Header 1\n",
};
let expectedH1 = [
{
type: "header",
content: [{ type: "text", ...nodeH1 }],
},
];
expect(buildNodeTree([nodeH1])).toEqual(expectedH1);
});
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 = [
{
type: "paragraph",
content: nodes.map((n) => ({ type: "text", ...n })),
},
];
expect(buildNodeTree(nodes)).toEqual(expected);
});
it("Should handle highlighted text in the middle of a paragraph", () => {
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 = [
{
type: "paragraph",
content: [
{ type: "text", attributes: {}, text: "Here is a paragraph " },
{
type: "text",
attributes: {
highlightedColor: color,
},
text: "with highlighted text",
},
{ type: "text", attributes: {}, text: ".\n" },
],
},
];
expect(buildNodeTree(nodes)).toEqual(expected);
});
it("Should handle inline code in the middle of a paragraph", () => {
/** @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 = [
{
type: "paragraph",
content: [
{ type: "text", attributes: {}, text: "Here is a paragraph " },
{
type: "text",
attributes: { inlineCode: true },
text: "with some code",
},
{ type: "text", attributes: {}, text: " in it.\n" },
],
},
];
expect(buildNodeTree(nodes)).toEqual(expected);
});
it("should handle a code block", () => {
/** @type {Array<RTJNode>} */
let nodes = [
{
attributes: {
line: {
codeBlock: true,
},
},
text: "Here is a code block\n",
},
];
let expected = [
{ type: "code", content: nodes.map((n) => ({ type: "text", ...n })) },
];
expect(buildNodeTree(nodes)).toEqual(expected);
});
it("should handle a horizontal ruler", () => {
/** @type {RTJNode} */
let node = {
embeddedObjects: [{ type: "horizontalRuleLine" }],
};
let expected = [{ type: "embedded", content: node }];
expect(buildNodeTree([node])).toEqual(expected);
});
it("should handle multiple quote nodes correctly", () => {
/** @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 = [
{
type: "quote",
content: [
{
type: "paragraph",
content: [
{
type: "text",
text: "First quote line ",
attributes: {
line: { quote: true },
},
},
{
type: "text",
text: "still first paragraph\n",
attributes: {
line: { quote: true },
},
},
],
},
{
type: "paragraph",
content: [
{
type: "text",
attributes: {
line: { quote: true },
},
text: "Second paragraph in quote\n",
},
],
},
],
},
{
type: "paragraph",
content: [{ type: "text", text: "Regular paragraph\n" }],
},
];
expect(buildNodeTree(nodes)).toEqual(expected);
});
it("should handle quotes with text formatting", () => {
/** @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 = [
{
type: "quote",
content: [
{
type: "paragraph",
content: [
{
type: "text",
text: "Quote with ",
attributes: {
line: { quote: true },
bold: true,
},
},
{
type: "text",
text: "mixed formatting\n",
attributes: {
line: { quote: true },
italic: true,
},
},
],
},
],
},
];
expect(buildNodeTree(nodes)).toEqual(expected);
});
});
describe("Test lists", () => {
it("should handle a simple list", () => {
/** @type {Array<RTJ.Node>} */
let nodes = [
{
attributes: {
line: {
listStyle: "bulleted",
indentLevel: 1,
},
},
text: "one\n",
},
{
attributes: {
line: {
listStyle: "bulleted",
indentLevel: 1,
},
},
text: "two\n",
},
];
let expected = [
{
type: "bulleted",
content: [
{
type: "listItem",
content: [
{
type: "text",
attributes: {
line: {
listStyle: "bulleted",
indentLevel: 1,
},
},
text: "one\n",
},
],
},
{
type: "listItem",
content: [
{
type: "text",
attributes: {
line: {
listStyle: "bulleted",
indentLevel: 1,
},
},
text: "two\n",
},
],
},
],
},
];
expect(buildNodeTree(nodes)).toEqual(expected);
});
it("Should handle complex lists", () => {
/** @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 = [
{
type: "bulleted",
content: [
{
type: "listItem",
content: [
{
type: "text",
attributes: {
line: {
listStyle: "bulleted",
indentLevel: 1,
},
},
text: "And a list\n",
},
{
type: "bulleted",
content: [
{
type: "listItem",
content: [
{
type: "text",
attributes: {
line: {
listStyle: "bulleted",
indentLevel: 2,
},
},
text: "Indented\n",
},
{
type: "bulleted",
content: [
{
type: "listItem",
content: [
{
type: "text",
attributes: {
line: {
listStyle: "bulleted",
indentLevel: 3,
},
},
text: "again\n",
},
],
},
],
},
],
},
],
},
],
},
],
},
];
expect(buildNodeTree(nodes)).toEqual(expected);
});
it("Should handle different lists following each other", () => {
/** @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",
},
];
const expected = [
{
type: "bulleted",
content: [
{ type: "listItem", content: [{ type: "text", ...nodes[0] }] },
],
},
{
type: "numbered",
content: [
{ type: "listItem", content: [{ type: "text", ...nodes[1] }] },
{ type: "listItem", content: [{ type: "text", ...nodes[2] }] },
],
},
];
expect(buildNodeTree(nodes)).toEqual(expected);
});
});
describe("Embedded objects", () => {
it("should handle a video block", () => {
/** @type {RTJ.Node} */
let node = {
embeddedObjects: [
{
type: "video",
identifier: "B7C0EB0794D04FF3B496308ED46D179A",
},
],
};
let expected = [{ type: "embedded", content: node }];
expect(buildNodeTree([node])).toEqual(expected);
});
});
describe("It should correctly handle edge cases", () => {
it("should handle an empty node", () => {
let nodes = [
{
attributes: {
line: {
header: 1,
identifier: "5BDE10FE-4D22-47B4-A00A-82D5F6488D69",
},
},
text: "Hello World!\n",
},
{
embeddedObjects: [
{
identifier: "ADA6341371F8441696DD75932177D1D0",
type: "photo",
},
],
},
{
text: "\n8-bit helvetica taxidermy tacos cred semiotics. plant asymmetrical.\n",
},
{
embeddedObjects: [
{
identifier: "F589ABE4B1554A8B9AE5ED50D3B10441",
type: "photo",
},
],
},
{
text: "\nBanh mi taxidermy tattooed vinyl.",
},
{
embeddedObjects: [
{
identifier: "29421FE8EBCC4D969F262E17E7FB1891",
type: "photo",
},
],
},
{
text: "Flexitarian ugh portland wolf moon keffiyeh. Vaporware shaman everyday carry brunch literally waistcoat biodiesel sus locavore. humblebrag church-key ennui cred keytar vexillologist.\n\nCupping adaptogen disrupt poke, twee humblebrag praxis godard activated charcoal ugh gluten-free art party leggings taiyaki slow-carb.\n\nPok pok offal bushwick kickstarter, cupping salvia gentrify prism copper mug pinterest.\n\nDummy text?",
},
];
let expected = [
{
type: "header",
content: [
{
type: "text",
attributes: {
line: {
header: 1,
identifier: "5BDE10FE-4D22-47B4-A00A-82D5F6488D69",
},
},
text: "Hello World!\n",
},
],
},
{
type: "embedded",
content: {
embeddedObjects: [
{
identifier: "ADA6341371F8441696DD75932177D1D0",
type: "photo",
},
],
},
},
{
type: "paragraph",
content: [
{
type: "text",
text: "\n8-bit helvetica taxidermy tacos cred semiotics. plant asymmetrical.\n",
},
],
},
{
type: "embedded",
content: {
embeddedObjects: [
{
identifier: "F589ABE4B1554A8B9AE5ED50D3B10441",
type: "photo",
},
],
},
},
{
type: "paragraph",
content: [
{ type: "text", text: "\nBanh mi taxidermy tattooed vinyl." },
],
},
{
type: "embedded",
content: {
embeddedObjects: [
{
identifier: "29421FE8EBCC4D969F262E17E7FB1891",
type: "photo",
},
],
},
},
{
type: "paragraph",
content: [
{
type: "text",
text: "Flexitarian ugh portland wolf moon keffiyeh. Vaporware shaman everyday carry brunch literally waistcoat biodiesel sus locavore. humblebrag church-key ennui cred keytar vexillologist.\n\nCupping adaptogen disrupt poke, twee humblebrag praxis godard activated charcoal ugh gluten-free art party leggings taiyaki slow-carb.\n\nPok pok offal bushwick kickstarter, cupping salvia gentrify prism copper mug pinterest.\n\nDummy text?",
},
],
},
];
expect(buildNodeTree(nodes)).toEqual(expected);
});
});