Files
portfolio-next/test/cli.test.ts
T
Lucas WintherandClaude Opus 5.5 974b3eb0df feat(work): CV-first work page, six proud projects, record and courses (spec 009)
- CV header with highlights and keeping-up summary replaces the intro and Now strip
- "Projects I'm proudest of": up to six featured panels; screenshots muted until hover
- "Also made" list; searching it also lists matching courses
- Record section: recognition & volunteering, courses by topic
- /work/learning/: searchable course list (plain script), in the sitemap
- Top bar: Projects, Record, Writing, CV; no Bluesky link in the work footer
- Highlights: only the placement takes the accent (owner, after the preview)

Owner looked at the rendered preview on 2026-11-12 before this commit.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-12 10:44:46 +01:00

44 lines
2.1 KiB
TypeScript

import { expect, it } from 'bun:test';
import { existsSync, mkdtempSync, readFileSync } from 'node:fs';
import { tmpdir } from 'node:os';
import { join } from 'node:path';
import { baseFiles, project, writeContent } from './library/helpers.ts';
const cli = (...args: string[]) => Bun.spawnSync(['bun', 'src/cli.ts', ...args], { stdout: 'pipe', stderr: 'pipe' });
it('validate passes on the fixture content', () => {
const r = cli('validate', 'fixtures/content');
expect(r.exitCode).toBe(0);
expect(r.stdout.toString()).toContain('Content OK (9 projects, 14 items)');
});
it('validate lists every error and exits 1', () => {
const dir = writeContent({ ...baseFiles, 'projects/a.md': project({ group: 'nope', related: ['zzz'] }) });
const r = cli('validate', dir);
expect(r.exitCode).toBe(1);
const out = r.stdout.toString();
expect(out).toContain('projects/a.md');
});
it('prints usage for unknown commands', () => {
const r = cli('frobnicate');
expect(r.exitCode).toBe(2);
expect(r.stderr.toString()).toContain('Usage: site');
});
it('build renders the site, copies media and writes sources-status.json', () => {
const out = join(mkdtempSync(join(tmpdir(), 'site-cli-')), 'site');
const cache = mkdtempSync(join(tmpdir(), 'site-cli-cache-'));
const env = { ...process.env, SOURCES_FIXTURES: '', GHOST_URL: '', TRAKT_CLIENT_ID: '', TRAKT_USER: '', HARDCOVER_TOKEN: '', GHOST_CONTENT_KEY: '' };
const r = Bun.spawnSync(['bun', 'src/cli.ts', 'build', 'fixtures/content', out, cache], { env, stdout: 'pipe', stderr: 'pipe' });
expect(r.stderr.toString()).not.toContain('error');
expect(r.exitCode).toBe(0);
expect(r.stdout.toString()).toContain('Built ');
expect(existsSync(join(out, 'index.html'))).toBe(true);
expect(existsSync(join(out, 'media', 'fixture-1.svg'))).toBe(true);
const status = JSON.parse(readFileSync(join(out, 'sources-status.json'), 'utf8'));
for (const name of ['ghost', 'trakt', 'hardcover']) expect(status[name].ok).toBe(false);
expect(JSON.stringify(status)).not.toMatch(/https?:/);
expect(existsSync(join(cache, 'sources.json'))).toBe(true);
}, 120_000);