- 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>
44 lines
2.1 KiB
TypeScript
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);
|