Files
shd.build/src/lib/articles/document.test.ts
T
jb 57068b61cd
Validate and deploy production / validate (push) Canceled after 0s
Validate and deploy production / deploy (push) Canceled after 0s
Validate and deploy staging / validate (push) Successful in 28s
Validate and deploy staging / deploy (push) Successful in 1m3s
feat: expand ISAC content modeling
2026-08-03 01:23:20 -04:00

279 lines
7.0 KiB
TypeScript

import { describe, expect, it } from 'vitest';
import { EMPTY_ARTICLE_DOCUMENT, parseArticleDocument } from './document';
describe('article documents', () => {
it('accepts formatted prose, multiple Builds, and article images', () => {
const parsed = parseArticleDocument({
version: 1,
document: {
type: 'doc',
content: [
{
type: 'heading',
attrs: { level: 2 },
content: [
{ type: 'text', text: 'Opening', marks: [{ type: 'bold' }] },
],
},
{
type: 'paragraph',
content: [
{
type: 'text',
text: 'Use this rotation.',
marks: [
{ type: 'link', attrs: { href: 'https://shd.build/guides' } },
],
},
],
},
{
type: 'buildEmbed',
attrs: {
buildId: '11111111-1111-4111-8111-111111111111',
embedKey: 'build-11111111-1111-4111-8111-111111111111',
},
},
{
type: 'buildEmbed',
attrs: {
buildId: '22222222-2222-4222-8222-222222222222',
embedKey: 'build-22222222-2222-4222-8222-222222222222',
},
},
{
type: 'articleImage',
attrs: {
imageId: '33333333-3333-4333-8333-333333333333',
alt: 'A loadout screen',
caption: 'Final configuration',
},
},
],
},
});
expect(parsed?.buildEmbeds).toHaveLength(2);
expect(parsed?.imageIds).toEqual(['33333333-3333-4333-8333-333333333333']);
expect(parsed?.plainText).toContain('Opening Use this rotation.');
});
it('rejects unsafe links and unknown nodes', () => {
expect(
parseArticleDocument({
version: 1,
document: {
type: 'doc',
content: [
{
type: 'paragraph',
content: [
{
type: 'text',
text: 'unsafe',
marks: [
{ type: 'link', attrs: { href: 'javascript:alert(1)' } },
],
},
],
},
],
},
}),
).toBeNull();
expect(
parseArticleDocument({
version: 1,
document: {
type: 'doc',
content: [{ type: 'iframe', attrs: { src: 'https://example.com' } }],
},
}),
).toBeNull();
});
it('accepts and canonicalizes metadata emitted by the Tiptap editor', () => {
const parsed = parseArticleDocument({
version: 1,
document: {
type: 'doc',
content: [
{
type: 'paragraph',
content: [
{
type: 'text',
text: 'Read more',
marks: [
{
type: 'link',
attrs: {
href: 'https://shd.build/news',
target: '_blank',
rel: 'noopener noreferrer nofollow',
class: null,
title: 'News archive',
},
},
],
},
],
},
{
type: 'orderedList',
attrs: { start: 1, type: null },
content: [
{
type: 'listItem',
content: [
{
type: 'paragraph',
content: [{ type: 'text', text: 'First item' }],
},
],
},
],
},
],
},
});
expect(parsed?.document.document.content).toEqual([
{
type: 'paragraph',
content: [
{
type: 'text',
text: 'Read more',
marks: [
{
type: 'link',
attrs: {
href: 'https://shd.build/news',
title: 'News archive',
},
},
],
},
],
},
{
type: 'orderedList',
content: [
{
type: 'listItem',
content: [
{
type: 'paragraph',
content: [{ type: 'text', text: 'First item' }],
},
],
},
],
},
]);
expect(parsed?.plainText).toContain('News archive');
});
it('preserves supported ordered-list numbering', () => {
const parsed = parseArticleDocument({
version: 1,
document: {
type: 'doc',
content: [
{
type: 'orderedList',
attrs: { start: 2, type: 'A' },
content: [
{
type: 'listItem',
content: [{ type: 'paragraph' }],
},
],
},
],
},
});
expect(parsed?.document.document.content?.[0]).toMatchObject({
type: 'orderedList',
attrs: { start: 2, type: 'A' },
});
expect(parseArticleDocument(parsed?.document)?.document).toEqual(
parsed?.document,
);
});
it('rejects unknown link metadata and non-default ordered lists', () => {
const documentWith = (content: unknown[]) => ({
version: 1,
document: { type: 'doc', content },
});
expect(
parseArticleDocument(
documentWith([
{
type: 'paragraph',
content: [
{
type: 'text',
text: 'unsafe metadata',
marks: [
{
type: 'link',
attrs: {
href: 'https://shd.build',
onclick: 'alert(1)',
},
},
],
},
],
},
]),
),
).toBeNull();
expect(
parseArticleDocument(
documentWith([
{
type: 'orderedList',
attrs: { start: 0, type: 'decimal' },
content: [],
},
]),
),
).toBeNull();
expect(
parseArticleDocument(
documentWith([
{
type: 'orderedList',
attrs: { start: 1, type: 1 },
content: [],
},
]),
),
).toBeNull();
});
it('rejects duplicate embed keys and unknown envelope fields', () => {
const embed = {
type: 'buildEmbed',
attrs: {
buildId: '11111111-1111-4111-8111-111111111111',
embedKey: 'build-11111111-1111-4111-8111-111111111111',
},
};
expect(
parseArticleDocument({
version: 1,
document: { type: 'doc', content: [embed, embed] },
}),
).toBeNull();
expect(
parseArticleDocument({ ...EMPTY_ARTICLE_DOCUMENT, legacy: true }),
).toBeNull();
});
});