import { describe, it, expect } from 'vitest'; import { resolve } from 'path'; /** * Regression test for issue #177 — `branding.favicon` object form crashes * the CLI with ERR_INVALID_ARG_TYPE. * * The 0.7.106 fix for #173 shipped `branding.favicon` as an object * (`{ source_dir, links_html, skip_default_links, base_path }`) in the * TypeScript types and in `src/layouts/Default.astro`, but `cli/index.mjs` * still called `resolve(process.cwd(), branding.favicon)` — which throws * `ERR_INVALID_ARG_TYPE` when `branding.favicon` is an object. * * Importing `cli/index.mjs` directly runs the full build pipeline, which * is too heavy for a unit test. Instead, this spec pins the type-narrowing * contract that the CLI's favicon resolution MUST honor: a string is a * path, an object is a config, and the two must never be conflated. The * integration smoke test (scripts/smoke.mjs) covers the end-to-end path. */ describe('CLI favicon config (issue #177)', () => { it('resolve() throws ERR_INVALID_ARG_TYPE when branding.favicon is an object — proves the bug class', async () => { // This is the bug: the legacy code did `resolve(cwd, branding.favicon)` // unconditionally. When branding.favicon is an object, Node throws. const faviconCfg = { skip_default_links: true, links_html: '' }; expect(() => resolve(process.cwd(), faviconCfg as any)).toThrow(/paths\[1\].*string|ERR_INVALID_ARG_TYPE/); }); it('typeof-string guard prevents the crash', () => { const faviconCfg = { skip_default_links: true, links_html: '' }; const safeResolve = () => typeof faviconCfg === 'string' && faviconCfg ? resolve(process.cwd(), faviconCfg) : null; expect(safeResolve).not.toThrow(); expect(safeResolve()).toBe(null); }); it('accepts string form (legacy) — single source path', () => { const faviconCfg = 'assets/my-brand.svg'; const resolved = typeof faviconCfg === 'string' && faviconCfg ? resolve(process.cwd(), faviconCfg) : null; expect(resolved).toBe(resolve(process.cwd(), 'assets/my-brand.svg')); }); it('accepts object form — no path resolution attempted on the object itself', () => { const faviconCfg = { source_dir: 'assets/favicons', links_html: '', skip_default_links: true, base_path: '/', }; expect(typeof faviconCfg).toBe('object'); // The object form must be inspected for fields, not passed to resolve(). expect((faviconCfg as any).source_dir).toBe('assets/favicons'); expect((faviconCfg as any).links_html).toContain('