fix(cms): enforce public publication contract

This commit is contained in:
syntaxbullet
2026-07-31 14:01:18 +02:00
parent 740e302c58
commit fec1bab2e5
4 changed files with 651 additions and 6 deletions

View File

@@ -0,0 +1,241 @@
import config from '@/payload.config'
import { getPublicationQueryOptions } from '@/utilities/publicationQuery'
import type { Payload, RequiredDataFromCollectionSlug } from 'payload'
import { getPayload } from 'payload'
import { afterAll, beforeAll, describe, expect, it } from 'vitest'
const publicationCollections = [
'pages',
'preistraeger',
'jury-mitglieder',
'partners',
'events',
'posts',
] as const
type PublicationCollection = (typeof publicationCollections)[number]
type PublicationCase<TCollection extends PublicationCollection = PublicationCollection> = {
collection: TCollection
data: (label: string) => RequiredDataFromCollectionSlug<TCollection>
hasPublicDetailRoute: boolean
}
const lexicalDocument = {
root: {
children: [
{
children: [
{
detail: 0,
format: 0,
mode: 'normal' as const,
style: '',
text: 'Publication contract fixture',
type: 'text',
version: 1,
},
],
direction: 'ltr' as const,
format: '' as const,
indent: 0,
textFormat: 0,
type: 'paragraph',
version: 1,
},
],
direction: 'ltr' as const,
format: '' as const,
indent: 0,
type: 'root',
version: 1,
},
}
let mediaID: number
const publicationCases: PublicationCase[] = [
{
collection: 'pages',
data: (label) => ({
layout: [{ blockType: 'content', columns: [] }],
_status: 'published',
slug: `publication-${label}`,
spaPath: `/publication-${label}`,
title: `Publication ${label}`,
}),
hasPublicDetailRoute: true,
},
{
collection: 'preistraeger',
data: (label) => ({
_status: 'published',
slug: `publication-${label}`,
spaPath: `/preistraeger/publication-${label}`,
title: `Publication ${label}`,
}),
hasPublicDetailRoute: true,
},
{
collection: 'jury-mitglieder',
data: (label) => ({ _status: 'published', name: `Publication ${label}` }),
hasPublicDetailRoute: false,
},
{
collection: 'partners',
data: (label) => ({
_status: 'published',
logo: mediaID,
name: `Publication ${label}`,
stableId: `publication-${label}`,
tier: 3,
}),
hasPublicDetailRoute: false,
},
{
collection: 'events',
data: (label) => ({
_status: 'published',
slug: `publication-${label}`,
spaPath: `/presse/events/publication-${label}`,
title: `Publication ${label}`,
}),
hasPublicDetailRoute: true,
},
{
collection: 'posts',
data: (label) => ({
_status: 'published',
content: lexicalDocument,
slug: `publication-${label}`,
spaPath: `/presse/blog/publication-${label}`,
title: `Publication ${label}`,
}),
hasPublicDetailRoute: true,
},
]
let payload: Payload
describe('draft-enabled collection publication contract', () => {
beforeAll(async () => {
payload = await getPayload({ config })
const imageData = Buffer.from(
'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNk+A8AAQUBAScY42YAAAAASUVORK5CYII=',
'base64',
)
const media = await payload.create({
collection: 'media',
data: { alt: 'Publication contract fixture' },
file: {
data: imageData,
mimetype: 'image/png',
name: `publication-contract-${process.pid}.png`,
size: imageData.length,
},
})
mediaID = media.id
})
afterAll(async () => {
if (mediaID) {
await payload.delete({ collection: 'media', id: mediaID })
}
})
it('keeps anonymous public and authenticated preview query modes explicit', () => {
expect(getPublicationQueryOptions(false)).toEqual({
draft: false,
overrideAccess: false,
})
expect(getPublicationQueryOptions(true)).toEqual({
draft: true,
overrideAccess: true,
})
})
it.each(publicationCases)(
'returns only published $collection documents to anonymous public reads',
async ({ collection, data, hasPublicDetailRoute }) => {
const published = await payload.create({
collection,
context: { disableRevalidate: true },
data: data(`${collection}-published`),
draft: false,
})
const unpublished = await payload.create({
collection,
context: { disableRevalidate: true },
data: data(`${collection}-unpublished`),
draft: false,
})
const storedDraft = await payload.update({
collection,
context: { disableRevalidate: true },
id: unpublished.id,
data: { _status: 'draft' },
draft: false,
})
expect(published._status).toBe('published')
expect(storedDraft._status).toBe('draft')
const publicResult = await payload.find({
collection,
...getPublicationQueryOptions(false),
pagination: false,
where: {
id: {
in: [published.id, unpublished.id],
},
},
})
expect(publicResult.docs.map((doc) => doc.id)).toEqual([published.id])
expect(publicResult.docs.every((doc) => doc._status === 'published')).toBe(true)
const previewResult = await payload.find({
collection,
...getPublicationQueryOptions(true),
pagination: false,
where: {
id: {
in: [published.id, unpublished.id],
},
},
})
expect(previewResult.docs.map((doc) => doc.id).sort()).toEqual(
[published.id, unpublished.id].sort(),
)
if (hasPublicDetailRoute) {
await expect(
payload.findByID({
collection,
id: published.id,
...getPublicationQueryOptions(false),
}),
).resolves.toMatchObject({ id: published.id, _status: 'published' })
await expect(
payload.findByID({
collection,
id: unpublished.id,
...getPublicationQueryOptions(false),
}),
).rejects.toThrow()
await expect(
payload.findByID({
collection,
id: unpublished.id,
...getPublicationQueryOptions(true),
}),
).resolves.toMatchObject({ id: unpublished.id, _status: 'draft' })
}
},
)
})