import assert from 'node:assert/strict'; import { readFile, stat } from 'node:fs/promises'; import test from 'node:test'; test('package scripts expose the local workflow', async () => { const pkg = JSON.parse(await readFile('package.json', 'utf8')); assert.equal(pkg.scripts.dev, 'astro dev'); assert.equal(pkg.scripts.build, 'astro build'); assert.equal(pkg.scripts.check, 'astro check && node --test'); assert.equal(pkg.scripts.test, 'node --test'); }); test('Astro configuration is environment-portable', async () => { const config = await readFile('astro.config.mjs', 'utf8'); assert.match(config, /process\.env\.SITE/); assert.match(config, /process\.env\.BASE/); assert.match(config, /starlight\(/); }); test('Incognito branding assets and configuration are present', async () => { for (const asset of [ 'public/favicon.ico', 'src/assets/logo.svg', 'src/assets/logo-dark.png', ]) { const details = await stat(asset); assert.ok(details.size > 0, `${asset} should not be empty`); } const config = await readFile('astro.config.mjs', 'utf8'); assert.match(config, /customCss/); assert.match(config, /logo/); assert.match(config, /dark:\s*'\.\/src\/assets\/logo\.svg'/); assert.match(config, /light:\s*'\.\/src\/assets\/logo-dark\.png'/); assert.match(config, /favicon/); assert.match(config, /https:\/\/msvincognito\.nl\//); }); test('the landing and association pages are available', async () => { for (const page of [ 'src/content/docs/index.mdx', 'src/content/docs/about-incognito.md', ]) { const details = await stat(page); assert.ok(details.size > 0, `${page} should not be empty`); } }); test('landing page navigation uses the migration manifest destinations', async () => { const landingPage = await readFile('src/content/docs/index.mdx', 'utf8'); for (const destination of [ './data-science-and-ai/', './master-ai/', './master-dsdm/', './useful-information/', './about-incognito/', ]) { assert.ok(landingPage.includes(`href="${destination}"`), `missing ${destination}`); } }); test('landing page labels source-era programme information as potentially outdated', async () => { const landingPage = await readFile('src/content/docs/index.mdx', 'utf8'); assert.match( landingPage, /This information originated in the previous wiki and may be outdated\./, ); }); test('Netlify builds the static site into dist', async () => { const config = await readFile('netlify.toml', 'utf8'); assert.match(config, /command = "npm run build"/); assert.match(config, /publish = "dist"/); }); test('the optional GitHub Pages workflow deploys only main or manual runs', async () => { const workflow = await readFile('.github/workflows/deploy.yml', 'utf8'); assert.match(workflow, /push:\s*\n\s+branches: \[main\]/); assert.match(workflow, /workflow_dispatch:/); assert.doesNotMatch(workflow, /pull_request:|schedule:/); assert.match(workflow, /actions\/checkout@v7/); assert.match(workflow, /withastro\/action@v6/); assert.match(workflow, /actions\/deploy-pages@v5/); }); test('GitHub Pages write and OIDC permissions are scoped only to deployment', async () => { const workflow = await readFile('.github/workflows/deploy.yml', 'utf8'); assert.doesNotMatch(workflow, /^permissions:/m); const build = workflow.match(/\n build:\n([\s\S]*?)(?=\n deploy:\n)/)?.[1] ?? ''; assert.match(build, /^ permissions:\n contents: read$/m); assert.doesNotMatch(build, /pages: write|id-token: write/); const deploy = workflow.match(/\n deploy:\n([\s\S]*)$/)?.[1] ?? ''; assert.match(deploy, /^ permissions:\n pages: write\n id-token: write$/m); }); test('maintainer documentation keeps Forgejo CI-independent', async () => { const readme = await readFile('README.md', 'utf8'); assert.match(readme, /Forgejo[^\n]*authoritative private repository/i); assert.match(readme, /does not depend on Forgejo CI/i); });