Skip to content

Commit

Permalink
body-units
Browse files Browse the repository at this point in the history
Made article tests quieter
  • Loading branch information
RoyEJohnson committed Dec 19, 2024
1 parent cd4581f commit 5abf3f7
Show file tree
Hide file tree
Showing 5 changed files with 210 additions and 101 deletions.
85 changes: 0 additions & 85 deletions src/app/components/body-units/body-units.js

This file was deleted.

129 changes: 129 additions & 0 deletions src/app/components/body-units/body-units.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
import React from 'react';
import RawHTML from '~/components/jsx-helpers/raw-html';
import Quote from '~/components/quote/quote.js';
import JITLoad from '~/helpers/jit-load';

function Unknown({data, type}: {data: unknown; type: string}) {
console.warn('Unknown data type', type);

return <RawHTML className="unknown-type" html={JSON.stringify(data)} />;
}

function convertAlignment(a: string) {
return a.replace('1/2', 'half').replace('1/3', 'third');
}

type CTAData = {
alignment: string;
heading: string;
description: string;
button_href: string;
button_text: string;
}

function CTA({data}: {data: CTAData}) {
const alignment = convertAlignment(data.alignment);

return (
<div className={`blog-cta ${alignment}`}>
<h2>{data.heading}</h2>
<div>{data.description}</div>
<a className="btn primary" href={data.button_href}>
{data.button_text}
</a>
</div>
);
}

function Paragraph({data}: {data: string}) {
return <RawHTML html={data} />;
}

type AImageData = {
caption: string;
image: {
original: {
src: string;
alt: string;
}
};
alignment: string;
alt_text: string;
};

function AlignedImage({data}: {data: AImageData}) {
const {
caption,
image: {
original: {src, alt}
}
} = data;
const alignment = convertAlignment(data.alignment);

return (
<figure className={alignment}>
<img src={src} alt={data.alt_text || alt} />
<RawHTML Tag="figcaption" html={caption} />
</figure>
);
}

type PQData = {
quote: string;
attribution: string;
}

function PullQuote({data}: {data: PQData}) {
const model = {
image: {},
content: data.quote,
attribution: data.attribution
};

return <Quote model={model} />;
}


type DocumentData = {
download_url: string;
}

function Document({data}: {data: DocumentData}) {
return <JITLoad importFn={() => import('./pdf-unit.js')} data={data} />;
}

// Using CMS tags, which are not camel-case
/* eslint camelcase: 0 */
const bodyUnits = {
paragraph: Paragraph,
aligned_html: Paragraph,
aligned_image: AlignedImage,
pullquote: PullQuote,
document: Document,
blog_cta: CTA
};

export type UnitType = {
id: string;
} & ({
type: 'paragraph' | 'aligned_html';
value: string;
} | {
type: 'aligned_image';
value: AImageData;
} | {
type: 'pullquote';
value: PQData;
} | {
type: 'document';
value: DocumentData;
} | {
type: 'blog_cta';
value: CTAData;
})

export default function BodyUnit({unit}: {unit: UnitType}) {
const Unit = bodyUnits[unit.type] as ({data}: {data: typeof unit.value}) => React.JSX.Element;

return Unit ? <Unit data={unit.value} /> : <Unknown data={unit.value} type={unit.type} />;
}
23 changes: 7 additions & 16 deletions src/app/pages/blog/article/article.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import BodyUnit from '~/components/body-units/body-units';
import BodyUnit, {UnitType} from '~/components/body-units/body-units';
import Byline from '~/components/byline/byline';
import ProgressRing from '~/components/progress-ring/progress-ring';
import useScrollProgress from './use-progress';
Expand All @@ -25,15 +25,6 @@ export function ArticleFromSlug({slug, onLoad}: ArticleArgs) {
);
}

type BodyData = {
type: string;
value:
| string
| {
alignment: string;
};
id: string;
};
export type ArticleData = BookData & {
error?: {
message: string;
Expand All @@ -42,7 +33,7 @@ export type ArticleData = BookData & {
subheading: string;
date: string;
author: string;
body: BodyData[];
body: UnitType[];
featuredVideo: [{value: string}];
articleImage: string;
featuredImageAltText: string;
Expand Down Expand Up @@ -166,19 +157,19 @@ function VideoArticle({data}: {data: ArticleData}) {
);
}

function normalUnits(unit: BodyData) {
return typeof unit.value === 'string' || unit.value.alignment !== 'bottom';
function normalUnits(unit: UnitType) {
return typeof unit.value === 'string' || ('alignment' in unit.value && unit.value.alignment !== 'bottom');
}
function bottomUnits(unit: BodyData) {
return typeof unit.value !== 'string' && unit.value.alignment === 'bottom';
function bottomUnits(unit: UnitType) {
return typeof unit.value !== 'string' && ('alignment' in unit.value && unit.value.alignment === 'bottom');
}

function ArticleBody({
bodyData,
setReadTime,
bodyRef
}: {
bodyData: BodyData[];
bodyData: UnitType[];
setReadTime: (rt: number) => void;
bodyRef: React.MutableRefObject<HTMLDivElement | undefined>;
}) {
Expand Down
71 changes: 71 additions & 0 deletions test/src/components/body-units.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import React from 'react';
import {describe, expect, it} from '@jest/globals';
import {render, screen, waitFor} from '@testing-library/preact';
import BodyUnit, {UnitType} from '~/components/body-units/body-units';

const mockDocument = jest.fn();

jest.mock('react-pdf/dist/esm/entry.webpack5', () => ({
Document: () => mockDocument(),
Page: jest.fn()
}));
jest.mock('react-pdf/dist/esm/Page/TextLayer.css', () => null);

describe('body-units', () => {
it('warns on unknown', () => {
const saveWarn = console.warn;
const whoopsUnit = {
type: 'whoops',
value: 'terrible mistake'
} as unknown as UnitType;

console.warn = jest.fn();

render(<BodyUnit unit={whoopsUnit} />);
expect(console.warn).toHaveBeenCalled();
console.warn = saveWarn;
screen.getByText('terrible mistake', {exact: false});
});
it('handles CTA', () => {
/* eslint-disable camelcase */
const unit: UnitType = {
id: 'meh',
type: 'blog_cta',
value: {
alignment: 'left',
heading: 'Heading',
description: 'description text',
button_href: '#',
button_text: 'click me'
}
};

render(<BodyUnit unit={unit} />);
screen.getByRole('link', {name: 'click me'});
});
it('handles pull-quote', () => {
const unit: UnitType = {
id: 'pq',
type: 'pullquote',
value: {
quote: 'what it says',
attribution: 'who said it'
}
};

render(<BodyUnit unit={unit} />);
screen.getByText('what it says', {exact: true});
});
it('handles document (pdf)', async () => {
const unit: UnitType = {
id: 'pdf',
type: 'document',
value: {
download_url: 'something'
}
};

render(<BodyUnit unit={unit} />);
await waitFor(() => expect(mockDocument).toHaveBeenCalled());
});
});
3 changes: 3 additions & 0 deletions test/src/pages/blog/article.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import useScrollProgress from '~/pages/blog/article/use-progress';
import pageData, {featuredVideo, pdfBody} from '~/../../test/src/data/article-page-data';
import * as HelpersData from '~/helpers/data';
import * as WCtx from '~/contexts/window';
import * as DH from '~/helpers/use-document-head';

const mockUsePageData = jest.fn();
const onload = jest.fn();
Expand All @@ -22,6 +23,8 @@ jest.mock('~/helpers/jit-load', () => ({
default: () => mockJITLoad()
}));

jest.spyOn(DH, 'setPageTitleAndDescriptionFromBookData').mockReturnValue();

describe('blog/article', () => {
afterEach(() => jest.resetAllMocks());
it('loads article', () => {
Expand Down

0 comments on commit 5abf3f7

Please sign in to comment.