Skip to content

Commit

Permalink
add tests for block resolution, refactor tests
Browse files Browse the repository at this point in the history
  • Loading branch information
pokornyd committed Jan 31, 2025
1 parent 8534471 commit 26158dc
Show file tree
Hide file tree
Showing 4 changed files with 97 additions and 80 deletions.
4 changes: 4 additions & 0 deletions tests/components/__snapshots__/portable-text.spec.tsx.snap
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`portable text React resolver renders a heading using custom resolvers 1`] = `"<h1 class="custom class">heading</h1>"`;

exports[`portable text React resolver renders a heading using default fallback 1`] = `"<h1>heading</h1>"`;

exports[`portable text React resolver renders a link using custom resolvers 1`] = `"<p><a href="http://google.com">external link</a></p>"`;

exports[`portable text React resolver renders a resolved linked item 1`] = `"<div>random text value</div>"`;
Expand Down
38 changes: 34 additions & 4 deletions tests/components/portable-text.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,13 +40,17 @@ const dummyRichText: Elements.RichTextElement = {
const portableTextComponents: PortableTextReactResolvers = {
types: {
componentOrItem: ({ value }) => {
const item = dummyRichText.linkedItems.find(item => item.system.codename === value.componentOrItem._ref);
const item = dummyRichText.linkedItems.find(
(item) => item.system.codename === value.componentOrItem._ref,
);
return <div>{item?.elements.text_element.value}</div>;
},
},
marks: {
contentItemLink: ({ value, children }) => {
const item = dummyRichText.linkedItems.find(item => item.system.id === value?.contentItemLink._ref);
const item = dummyRichText.linkedItems.find(
(item) => item.system.id === value?.contentItemLink._ref,
);
return (
<a href={"https://somerandomwebsite.xyz/" + item?.system.codename}>
{children}
Expand All @@ -57,11 +61,15 @@ const portableTextComponents: PortableTextReactResolvers = {
};

describe("portable text React resolver", () => {
const renderPortableText = (richTextValue: string, components = portableTextComponents) => {
const renderPortableText = (
richTextValue: string,
components = portableTextComponents,
) => {
dummyRichText.value = richTextValue;
const portableText = transformToPortableText(dummyRichText.value);

return render(<PortableText value={portableText} components={components} />).container.innerHTML;
return render(<PortableText value={portableText} components={components} />)
.container.innerHTML;
};

it("renders simple HTML", () => {
Expand Down Expand Up @@ -149,4 +157,26 @@ describe("portable text React resolver", () => {
);
expect(tree).toMatchSnapshot();
});

it("renders a heading using custom resolvers", () => {
const customComponentResolvers: PortableTextReactResolvers = {
...portableTextComponents,
block: {
h1: ({ children }) => <h1 className="custom class">{children}</h1>,
},
};

const tree = renderPortableText(
`<h1>heading</h1>`,
customComponentResolvers,
);
expect(tree).toMatchSnapshot();
});

it("renders a heading using default fallback", () => {
const tree = renderPortableText(
`<h1>heading</h1>`,
);
expect(tree).toMatchSnapshot();
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@ exports[`HTML resolution builds basic portable text into HTML 1`] = `"<p><br/></

exports[`HTML resolution by default resolves text styled with sub and sup 1`] = `"<p><sub>Subscript text</sub><sup>Superscript text</sup></p>"`;

exports[`HTML resolution resolves a h2 heading while using custom resolvers for h1 1`] = `"<h1 custom-attribute="value">modified heading</h1><h2>heading</h2>"`;

exports[`HTML resolution resolves a heading using custom resolvers 1`] = `"<h1 custom-attribute="value">heading</h1>"`;

exports[`HTML resolution resolves a heading using default fallback 1`] = `"<h1>heading</h1>"`;

exports[`HTML resolution resolves a link using default fallback 1`] = `"<p><a href="https://website.com/12345" target="_blank" rel="noopener noreferrer">link</a></p>"`;

exports[`HTML resolution resolves a linked item 1`] = `"<p>resolved value of text_element: <strong>random text value</strong></p><p>text after component</p>"`;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,8 @@
import { Elements, ElementType } from "@kontent-ai/delivery-sdk";
import { PortableTextTypeComponentOptions } from "@portabletext/to-html";

import {
ArbitraryTypedObject,
PortableTextBlock,
PortableTextComponentOrItem,
PortableTextExternalLink,
PortableTextImage,
PortableTextItemLink,
PortableTextMark,
PortableTextTable,
transformToPortableText,
} from "../../../../src";
import { PortableTextHtmlResolvers, resolveImage, toHTML } from "../../../../src/utils/resolution/html";
import { PortableTextComponentOrItem, transformToPortableText } from "../../../../src";
import { PortableTextHtmlResolvers, toHTML } from "../../../../src/utils/resolution/html";

jest.mock("short-unique-id", () => {
return jest.fn().mockImplementation(() => {
Expand All @@ -22,25 +12,9 @@ jest.mock("short-unique-id", () => {
});
});

type ResolverFunction<T extends ArbitraryTypedObject> = (value: T, children?: any) => string;

type CustomResolvers = {
image?: ResolverFunction<PortableTextImage>;
block?: ResolverFunction<PortableTextBlock>;
table?: ResolverFunction<PortableTextTable>;
component?: ResolverFunction<PortableTextComponentOrItem>;
contentItemLink?: ResolverFunction<PortableTextItemLink>;
link?: ResolverFunction<PortableTextExternalLink>;
sup?: ResolverFunction<PortableTextMark>;
};

const customResolvers: Partial<CustomResolvers> = {
image: (image) => `<img src="${image.asset.url}" alt="${image.asset.rel ?? ""}" height="800">`,
sup: (_, children) => `<sup custom-attribute="value">${children}</sup>`,
};

describe("HTML resolution", () => {
let richTextInput: Elements.RichTextElement;
let customResolvers: PortableTextHtmlResolvers;

beforeEach(() => {
richTextInput = {
Expand Down Expand Up @@ -74,60 +48,49 @@ describe("HTML resolution", () => {
links: [],
name: "dummy",
};
});

const getPortableTextComponents = (
element: Elements.RichTextElement,
customResolvers: CustomResolvers = {},
): PortableTextHtmlResolvers => ({
components: {
types: {
image: ({
value,
}) =>
customResolvers.image
? customResolvers.image(value)
: resolveImage(value),
componentOrItem: ({
value,
}: PortableTextTypeComponentOptions<PortableTextComponentOrItem>) => {
const linkedItem = element.linkedItems.find(
(item) => item.system.codename === value.componentOrItem._ref,
);
if (!linkedItem) return `Resolver for unknown type not implemented.`;

switch (linkedItem.system.type) {
case "test":
return `<p>resolved value of text_element: <strong>${linkedItem.elements.text_element.value}</strong></p>`;
default:
return `Resolver for type ${linkedItem.system.type} not implemented.`;
}
customResolvers = {
components: {
block: {
h1: ({ children }) => `<h1 custom-attribute="value">${children}</h1>`,
},
types: {
image: ({ value }) => `<img src="${value.asset.url}" alt="${value.asset.rel ?? ""}" height="800">`,
componentOrItem: ({
value,
}: PortableTextTypeComponentOptions<PortableTextComponentOrItem>) => {
const linkedItem = richTextInput.linkedItems.find(
(item) => item.system.codename === value.componentOrItem._ref,
);
if (!linkedItem) {
return `Resolver for unknown type not implemented.`;
}

switch (linkedItem.system.type) {
case "test":
return `<p>resolved value of text_element: <strong>${linkedItem.elements.text_element.value}</strong></p>`;
default:
return `Resolver for type ${linkedItem.system.type} not implemented.`;
}
},
},
marks: {
contentItemLink: ({ children, value }) =>
`<a href="https://website.com/${value?.contentItemLink._ref}">${children}</a>`,
sup: ({ children }) => `<sup custom-attribute="value">${children}</sup>`,
},
},
marks: {
contentItemLink: ({
children,
value,
}) => `<a href="https://website.com/${value?.contentItemLink._ref}">${children}</a>`,
sup: ({
children,
value,
}) => customResolvers.sup ? customResolvers.sup(value, children) : `<sup>${children}</sup>`,
},
},
};
});

const transformAndCompare = (
richTextValue: string,
customResolvers: CustomResolvers = {},
customResolvers?: PortableTextHtmlResolvers,
) => {
richTextInput.value = richTextValue;

const portableText = transformToPortableText(richTextInput.value);
const result = toHTML(
portableText,
getPortableTextComponents(richTextInput, customResolvers),
);
const result = toHTML(portableText, customResolvers);

expect(result).toMatchSnapshot();
};
Expand All @@ -141,12 +104,14 @@ describe("HTML resolution", () => {
it("resolves internal link", () => {
transformAndCompare(
"<p><a data-item-id=\"23f71096-fa89-4f59-a3f9-970e970944ec\" href=\"\"><em>item</em></a></p>",
customResolvers,
);
});

it("resolves a linked item", () => {
transformAndCompare(
"<object type=\"application/kenticocloud\" data-type=\"item\" data-rel=\"link\" data-codename=\"test_item\"></object><p>text after component</p>",
customResolvers,
);
});

Expand Down Expand Up @@ -182,10 +147,7 @@ describe("HTML resolution", () => {
});

it("resolves superscript with custom resolver", () => {
transformAndCompare(
"<p><sup>Superscript text</sup></p>",
customResolvers,
);
transformAndCompare("<p><sup>Superscript text</sup></p>", customResolvers);
});

it("resolves a link using default fallback", () => {
Expand All @@ -200,4 +162,19 @@ describe("HTML resolution", () => {
customResolvers,
);
});

it("resolves a heading using default fallback", () => {
transformAndCompare("<h1>heading</h1>");
});

it("resolves a heading using custom resolvers", () => {
transformAndCompare("<h1>heading</h1>", customResolvers);
});

it("resolves a h2 heading while using custom resolvers for h1", () => {
transformAndCompare(
"<h1>modified heading</h1><h2>heading</h2>",
customResolvers,
);
});
});

0 comments on commit 26158dc

Please sign in to comment.