// @vitest-environment jsdom // // `/` blog index — a static list page. Two things worth testing: // 1. `meta({ locale })` is localized — it reads the REAL catalog via // getCatalog, so we assert en vs de descriptions directly (no mock). // 2. the rendered list shows localized chrome + locale-prefixed links. The // page pulls chrome from @voltro/i18n (, useLocale); we mock those to // resolve against the real catalogs for a controllable "current locale", // so the assertions are genuine localized strings. Post titles/excerpts // come from the real content source and are NOT translated. import { afterEach, describe, expect, test, vi } from 'vitest' import { act, createElement, type ReactNode } from 'react' import { createRoot, type Root } from 'react-dom/client' import { posts } from '../content/posts' import en from '../locales/en' import de from '../locales/de' const catalogs: Record> = { en, de } let currentLocale = 'en' // Minimal ICU-ish interpolation: replace {key} with values[key]. const fill = (msg: string, values?: Record): string => values ? msg.replace(/\{(\w+)\}/g, (_, k: string) => String(values[k] ?? `{${k}}`)) : msg vi.mock('@voltro/i18n', () => ({ // The locale catalogs call these at module top-level; identity mirrors the // real (compile-time-only) implementations so importing them doesn't throw. defineCatalog: (c: T): T => c, defineLocale: () => (c: T): T => c, useLocale: () => currentLocale, useT: (id: string, values?: Record) => fill(catalogs[currentLocale]?.[id] ?? id, values), T: ({ id, values }: { id: string; values?: Record }) => fill(catalogs[currentLocale]?.[id] ?? id, values), })) const { default: Index, meta, renderMode, interactive } = await import('./page') ;(globalThis as { IS_REACT_ACT_ENVIRONMENT?: boolean }).IS_REACT_ACT_ENVIRONMENT = true let container: HTMLDivElement let root: Root const render = (node: ReactNode): void => { container = document.createElement('div') document.body.appendChild(container) act(() => { root = createRoot(container) root.render(node) }) } afterEach(() => { currentLocale = 'en' if (root) act(() => root.unmount()) container?.remove() document.body.innerHTML = '' }) describe('index — config + localized meta', () => { test('is a static page with zero client JS', () => { expect(renderMode).toBe('static') expect(interactive).toBe('none') }) test('meta() returns a localized title + description per locale', () => { expect(meta({ locale: 'en' }).title).toContain('Blog') expect(meta({ locale: 'en' }).description).toContain('pre-rendered') expect(meta({ locale: 'de' }).description).toContain('vorgerenderter') }) test('meta() falls back to the default (en) catalog for an unknown locale', () => { expect(meta({ locale: 'zz' }).description).toContain('pre-rendered') }) }) describe('index — localized render', () => { test('lists every post, newest first, with bare links + English chrome (en)', () => { currentLocale = 'en' render(createElement(Index)) const links = Array.from(container.querySelectorAll('.post-list a')) expect(links).toHaveLength(posts.length) // Newest-first: the 2025-02-03 post precedes the 2025-01-15 one. expect(links[0]!.getAttribute('href')).toBe('/blog/cms-to-ssg') expect(links[links.length - 1]!.getAttribute('href')).toBe('/blog/hello-static') expect(container.textContent).toContain(`${posts.length} posts`) }) test('prefixes post links with /de and renders German chrome (de)', () => { currentLocale = 'de' render(createElement(Index)) const links = Array.from(container.querySelectorAll('.post-list a')) expect(links[0]!.getAttribute('href')).toBe('/de/blog/cms-to-ssg') expect(container.textContent).toContain(`${posts.length} Beiträge`) }) })