116 lines
4.7 KiB
JavaScript
116 lines
4.7 KiB
JavaScript
/**
|
|
* --------------------------------------------------------------------
|
|
* docmd : the zero-config documentation engine.
|
|
*
|
|
* N-2 — `docmd deploy --force` flag must do something.
|
|
*
|
|
* Before the fix, `--force` was accepted in the CLI flags but never
|
|
* read in the deployer. Every `docmd deploy --docker` silently
|
|
* overwrote an existing `Dockerfile`. The fix: `--force` opts in to
|
|
* overwriting; the default behaviour skips existing files with a
|
|
* clear `TUI` line.
|
|
*
|
|
* Run: `node tests/runner.js --only=deploy`
|
|
* --------------------------------------------------------------------
|
|
*/
|
|
|
|
import {
|
|
DOCMD,
|
|
setup,
|
|
writeFile,
|
|
runTestFile
|
|
} from '../shared.js';
|
|
import { execSync } from 'node:child_process';
|
|
import fs from 'node:fs';
|
|
import path from 'node:path';
|
|
|
|
let passed = 0;
|
|
let failed = 0;
|
|
const failures = [];
|
|
|
|
function assert(condition, message) {
|
|
if (!condition) {
|
|
failed++;
|
|
failures.push(message);
|
|
console.log(` ❌ ${message}`);
|
|
} else {
|
|
passed++;
|
|
console.log(` ✅ ${message}`);
|
|
}
|
|
}
|
|
|
|
export const test = runTestFile({
|
|
name: 'Deploy --force honours overwrite (N-2)',
|
|
emoji: '🚢',
|
|
run: () => {
|
|
|
|
// N-2 — without --force, an existing Dockerfile is preserved.
|
|
{
|
|
const dir = setup('deploy-29-n2-no-force-skip');
|
|
writeFile(dir, 'docs/index.md', '# Hi\n');
|
|
writeFile(dir, 'docmd.config.json', JSON.stringify({ title: 'N2', src: './docs', out: './site' }, null, 2) + '\n');
|
|
// Pre-seed a Dockerfile so the deployer would overwrite it.
|
|
const existing = 'FROM existing:keep-me\n';
|
|
writeFile(dir, 'Dockerfile', existing);
|
|
|
|
let output = '';
|
|
try {
|
|
output = execSync(`node ${DOCMD} deploy --docker`, { cwd: dir, stdio: 'pipe', encoding: 'utf8' });
|
|
} catch (e) {
|
|
output = (typeof e.stdout === 'string' ? e.stdout : (e.stdout ? e.stdout.toString() : '')) +
|
|
(typeof e.stderr === 'string' ? e.stderr : (e.stderr ? e.stderr.toString() : ''));
|
|
}
|
|
|
|
const after = fs.readFileSync(path.join(dir, 'Dockerfile'), 'utf8');
|
|
assert(after === existing, 'N-2: without --force, existing Dockerfile is preserved');
|
|
assert(/skipped.*--force/i.test(output), 'N-2: TUI mentions --force when skipping');
|
|
}
|
|
|
|
// N-2 — with --force, an existing Dockerfile is overwritten.
|
|
{
|
|
const dir = setup('deploy-29-n2-force-overwrite');
|
|
writeFile(dir, 'docs/index.md', '# Hi\n');
|
|
writeFile(dir, 'docmd.config.json', JSON.stringify({ title: 'N2', src: './docs', out: './site' }, null, 2) + '\n');
|
|
writeFile(dir, 'Dockerfile', 'FROM existing:keep-me\n');
|
|
|
|
execSync(`node ${DOCMD} deploy --docker --force`, { cwd: dir, stdio: 'pipe' });
|
|
const after = fs.readFileSync(path.join(dir, 'Dockerfile'), 'utf8');
|
|
assert(after !== 'FROM existing:keep-me\n', 'N-2: with --force, existing Dockerfile is overwritten');
|
|
assert(/FROM .+/.test(after), 'N-2: overwritten Dockerfile contains a real FROM directive');
|
|
}
|
|
|
|
// N-2 — without --force and no existing file, the deployer writes
|
|
// a fresh Dockerfile (regression guard for the skip path).
|
|
{
|
|
const dir = setup('deploy-29-n2-no-force-fresh');
|
|
writeFile(dir, 'docs/index.md', '# Hi\n');
|
|
writeFile(dir, 'docmd.config.json', JSON.stringify({ title: 'N2', src: './docs', out: './site' }, null, 2) + '\n');
|
|
|
|
execSync(`node ${DOCMD} deploy --docker`, { cwd: dir, stdio: 'pipe' });
|
|
assert(fs.existsSync(path.join(dir, 'Dockerfile')), 'N-2: without --force and no existing file, Dockerfile is created');
|
|
}
|
|
|
|
// T-Z9 — generated `netlify.toml` must NOT contain a SPA catch-all
|
|
// redirect with `from = "/*" status = 200`. That pattern soft-404s
|
|
// every missing route by serving the home page with HTTP 200, which
|
|
// hides errors and hurts SEO. docmd generates real HTML per route,
|
|
// so the redirect is unnecessary — Netlify serves the bundled
|
|
// 404.html with 404 status for any path that doesn't have a file.
|
|
{
|
|
const dir = setup('deploy-29-tz9-no-soft-404');
|
|
writeFile(dir, 'docs/index.md', '# Hi\n');
|
|
writeFile(dir, 'docmd.config.json', JSON.stringify({ title: 'TZ9', src: './docs', out: './site', layout: { spa: true } }, null, 2) + '\n');
|
|
|
|
execSync(`node ${DOCMD} deploy --netlify`, { cwd: dir, stdio: 'pipe' });
|
|
const toml = fs.readFileSync(path.join(dir, 'netlify.toml'), 'utf8');
|
|
assert(!/\[\[redirects\]\]/.test(toml), 'T-Z9: no [[redirects]] block in generated netlify.toml');
|
|
assert(!/from\s*=\s*"\/\*"\s*\n\s*to\s*=\s*"\/index\.html"/m.test(toml), 'T-Z9: no catch-all redirect to /index.html');
|
|
}
|
|
}
|
|
});
|
|
|
|
export const results = {
|
|
get passed() { return passed; },
|
|
get failed() { return failed; },
|
|
get failures() { return [...failures]; }
|
|
}; |