// Task 3 用例 3:brand 容忍——brand:{} 与 brand:{logoText:'X'} 两态下 Header/Footer // 均渲染不落空(logoText 缺省用 name);导航缺席容忍(routes 无对应路径 → 隐藏项)。 // 经 Astro Container API 做真实组件渲染(非仅纯函数断言)。 import { experimental_AstroContainer as AstroContainer } from 'astro/container' import { describe, expect, it } from 'vitest' import SiteFooter from '../src/components/SiteFooter.astro' import SiteHeader from '../src/components/SiteHeader.astro' import type { RouteEntry, SiteConfig } from '../src/lib/load-render-data.js' const htmlRoute = (routePath: string): RouteEntry => ({ host: '', routePath, routeKind: 'html', queryPolicy: 'ignore', queryKey: null, targetStatus: '200', targetContentId: null, targetFile: null, redirectStatus: null, redirectLocation: null, indexable: true, priority: 1000, verificationStatus: 'verified_html', }) const ROUTES: RouteEntry[] = [htmlRoute('/'), htmlRoute('/products/'), htmlRoute('/news/')] const SITE_EMPTY_BRAND: SiteConfig = { name: 'demo-site', origin: 'https://demo.example', locale: 'zh-CN', brand: {}, } const SITE_LOGO_TEXT: SiteConfig = { ...SITE_EMPTY_BRAND, brand: { logoText: 'ACME 商标' }, } type Container = Awaited> let container: Container | undefined async function getContainer(): Promise { container ??= await AstroContainer.create() return container } describe('brand 容忍(Task 1 审查移交契约)', () => { it('brand:{} → Header/Footer 渲染 site.name(logoText 缺省用 name),无 undefined 落空', async () => { const c = await getContainer() const header = await c.renderToString(SiteHeader, { props: { site: SITE_EMPTY_BRAND, routes: ROUTES }, }) expect(header).toContain('demo-site') expect(header).not.toContain('undefined') const footer = await c.renderToString(SiteFooter, { props: { site: SITE_EMPTY_BRAND } }) expect(footer).toContain('demo-site') expect(footer).toContain(`© ${new Date().getFullYear()}`) expect(footer).not.toContain('undefined') }) it("brand:{logoText:'X'} → Header/Footer 显示 logoText", async () => { const c = await getContainer() const header = await c.renderToString(SiteHeader, { props: { site: SITE_LOGO_TEXT, routes: ROUTES }, }) expect(header).toContain('ACME 商标') const footer = await c.renderToString(SiteFooter, { props: { site: SITE_LOGO_TEXT } }) expect(footer).toContain('ACME 商标') }) it('brand 对象上无 logoText 键之外的杂键也不炸(恒按缺省容忍读)', async () => { const c = await getContainer() const site: SiteConfig = { ...SITE_EMPTY_BRAND, brand: { unknownKey: 'v' } as SiteConfig['brand'] } const header = await c.renderToString(SiteHeader, { props: { site, routes: ROUTES } }) expect(header).toContain('demo-site') expect(header).not.toContain('undefined') }) it('导航缺席容忍:routes 无 /products/ → 隐藏对应项,/news/ 存在则保留', async () => { const c = await getContainer() const partial = ROUTES.filter((r) => r.routePath !== '/products/') const header = await c.renderToString(SiteHeader, { props: { site: SITE_EMPTY_BRAND, routes: partial }, }) expect(header).not.toContain('href="/products/"') expect(header).toContain('href="/news/"') expect(header).toContain('href="/"') }) })