import { describe, expect, it } from 'vitest' import { asc, eq } from 'drizzle-orm' import { db } from '~/data/db' import { posts } from '~/data/schema' import { createEntry, listEntries, listEntryBlocks, replaceEntryBlocks, type EntryCreateValues, } from '~/data/repositories/entries' import { makeBrand, makeProject } from '../support/admin' import { makePost } from '../support/entries' import { postTypeId } from '../support/post-types' function values(projectId: string, slug: string, title = 'Beitrag'): EntryCreateValues { return { projectId, title, teaser: null, slug, typeId: postTypeId('feature'), audience: 'internal', coverMediaId: null, authorName: 'Paul', } } async function numbersOf(projectId: string): Promise { const rows = await db .select({ number: posts.number }) .from(posts) .where(eq(posts.projectId, projectId)) .orderBy(asc(posts.number)) return rows.map(row => row.number) } describe('createEntry vergibt Beitragsnummern', () => { it('zählt je Projekt getrennt hoch', async () => { const brand = await makeBrand() const trakk = await makeProject(brand.id, 'trakk', 'Trakk') const orbit = await makeProject(brand.id, 'orbit', 'Orbit') await createEntry(values(trakk.id, 'eins')) await createEntry(values(trakk.id, 'zwei')) await createEntry(values(orbit.id, 'eins')) expect(await numbersOf(trakk.id)).toEqual([1, 2]) expect(await numbersOf(orbit.id)).toEqual([1]) }) it('vergibt bei gleichzeitigem Anlegen lückenlose Nummern ohne Doppelung', async () => { const brand = await makeBrand() const project = await makeProject(brand.id) await Promise.all( Array.from({ length: 20 }, (_, index) => createEntry(values(project.id, `beitrag-${index}`))), ) expect(await numbersOf(project.id)).toEqual(Array.from({ length: 20 }, (_, index) => index + 1)) }) it('setzt hinter bereits vergebenen Nummern fort', async () => { const brand = await makeBrand() const project = await makeProject(brand.id) await makePost(project.id, { number: 142, slug: 'alter-beitrag' }) const created = await createEntry(values(project.id, 'neuer-beitrag')) expect(created.number).toBe(143) }) it('hängt die Nummer an, wenn der Slug im Projekt schon vergeben ist', async () => { const brand = await makeBrand() const project = await makeProject(brand.id) const first = await createEntry(values(project.id, 'regel-engine')) const second = await createEntry(values(project.id, 'regel-engine')) expect(first.slug).toBe('regel-engine') expect(second.slug).toBe(`regel-engine-${second.number}`) }) it('übernimmt Titel, Autor und Zielgruppe', async () => { const brand = await makeBrand() const project = await makeProject(brand.id) const created = await createEntry({ ...values(project.id, 'regel-engine', 'Regel-Engine'), audience: 'customer' }) expect(created).toMatchObject({ title: 'Regel-Engine', authorName: 'Paul', audience: 'customer', status: 'draft', number: 1, }) }) }) describe('replaceEntryBlocks', () => { it('speichert Blöcke in der übergebenen Reihenfolge', async () => { const brand = await makeBrand() const project = await makeProject(brand.id) const entry = await createEntry(values(project.id, 'mit-bloecken')) await replaceEntryBlocks(entry.id, [ { type: 'text', data: { text: 'Erster' } }, { type: 'quote', data: { text: 'Zweiter', source: 'Paul' } }, { type: 'text', data: { text: 'Dritter' } }, ]) const rows = await listEntryBlocks(entry.id) expect(rows.map(row => row.type)).toEqual(['text', 'quote', 'text']) expect(rows.map(row => row.sort)).toEqual([0, 1, 2]) expect(rows[1]?.data).toMatchObject({ text: 'Zweiter', source: 'Paul' }) }) it('ersetzt vorhandene Blöcke vollständig', async () => { const brand = await makeBrand() const project = await makeProject(brand.id) const entry = await createEntry(values(project.id, 'ersetzt')) await replaceEntryBlocks(entry.id, [{ type: 'text', data: { text: 'Alt' } }]) await replaceEntryBlocks(entry.id, [{ type: 'callout', data: { text: 'Neu', title: '', tone: 'info' } }]) const rows = await listEntryBlocks(entry.id) expect(rows).toHaveLength(1) expect(rows[0]?.type).toBe('callout') }) }) describe('listEntries', () => { it('grenzt auf Projekte, Status und Suche ein', async () => { const brand = await makeBrand() const trakk = await makeProject(brand.id, 'trakk', 'Trakk') const orbit = await makeProject(brand.id, 'orbit', 'Orbit') await makePost(trakk.id, { number: 1, slug: 'regel-engine', title: 'Regel-Engine', status: 'draft' }) await makePost(trakk.id, { number: 2, slug: 'sla-uhr', title: 'SLA-Uhr', status: 'published' }) await makePost(orbit.id, { number: 1, slug: 'eingang', title: 'Ein Eingang', status: 'draft' }) const mine = await listEntries({ projectIds: [trakk.id], page: 1, perPage: 25 }) const drafts = await listEntries({ status: 'draft', page: 1, perPage: 25 }) const found = await listEntries({ search: 'sla', page: 1, perPage: 25 }) const none = await listEntries({ projectIds: [], page: 1, perPage: 25 }) expect(mine.total).toBe(2) expect(drafts.items.map(item => item.slug).sort()).toEqual(['eingang', 'regel-engine']) expect(found.items.map(item => item.slug)).toEqual(['sla-uhr']) expect(none.total).toBe(0) }) })