229 lines
7.6 KiB
JavaScript
229 lines
7.6 KiB
JavaScript
/*
|
|
* prepare-release.test.cjs — Test standalone (zero deps) pour scripts/prepare-release.cjs
|
|
*
|
|
* Contrat vérifié (issu du planner / critères d'acceptation) :
|
|
* - `node scripts/prepare-release.cjs <semver>` met à jour `version.json` (racine)
|
|
* ET `admin-web/package.json` (champ `version`) avec la valeur passée.
|
|
* - Sans argument -> exit code != 0.
|
|
* - Version non-semver -> exit code != 0.
|
|
* - semver simple (1.2.3) ou avec prerelease (1.2.3-beta.1) -> succès.
|
|
* - Les autres clés de `admin-web/package.json` (name, dependencies, scripts...)
|
|
* sont préservées (pas écrasées).
|
|
*
|
|
* Ce test s'exécute AVANT l'implémentation (le script n'existe pas encore).
|
|
* Dans ce cas, chaque test échoue proprement avec "[FAIL] ... script not implemented yet",
|
|
* ce qui confirme l'état rouge attendu (TDD spec-first).
|
|
*
|
|
* Usage : node scripts/prepare-release.test.cjs
|
|
* Exit : 0 si tous les tests passent, 1 sinon.
|
|
*/
|
|
|
|
"use strict";
|
|
|
|
const assert = require("node:assert");
|
|
const fs = require("node:fs");
|
|
const path = require("node:path");
|
|
const { spawnSync } = require("node:child_process");
|
|
|
|
const ROOT = path.resolve(__dirname, "..");
|
|
const SCRIPT = path.join(ROOT, "scripts", "prepare-release.cjs");
|
|
const VERSION_JSON = path.join(ROOT, "version.json");
|
|
const ADMIN_PKG = path.join(ROOT, "admin-web", "package.json");
|
|
|
|
let passed = 0;
|
|
let failed = 0;
|
|
|
|
function ok(name) {
|
|
console.log(`[PASS] ${name}`);
|
|
passed++;
|
|
}
|
|
function ko(name, detail) {
|
|
console.log(`[FAIL] ${name}${detail ? " — " + detail : ""}`);
|
|
failed++;
|
|
}
|
|
|
|
/**
|
|
* Exécute prepare-release.cjs via node et renvoie { status, stdout, stderr }.
|
|
* Si le script n'existe pas, on simule un échec avec status null.
|
|
*/
|
|
function runScript(args) {
|
|
if (!fs.existsSync(SCRIPT)) {
|
|
return {
|
|
status: null,
|
|
stdout: "",
|
|
stderr: "scripts/prepare-release.cjs not implemented yet",
|
|
missing: true,
|
|
};
|
|
}
|
|
const res = spawnSync(process.execPath, [SCRIPT, ...args], {
|
|
cwd: ROOT,
|
|
encoding: "utf8",
|
|
timeout: 15000,
|
|
});
|
|
return {
|
|
status: res.status,
|
|
stdout: res.stdout ?? "",
|
|
stderr: res.stderr ?? "",
|
|
missing: false,
|
|
};
|
|
}
|
|
|
|
/* ------------------------------------------------------------------ *
|
|
* Backup / restore : on ne veut PAS polluer le working tree.
|
|
* On backup les fichiers AVANT les tests d'écriture et on restore à la fin,
|
|
* même si une assertion throw.
|
|
* ------------------------------------------------------------------ */
|
|
|
|
const backup = {};
|
|
|
|
function backupFile(file) {
|
|
if (fs.existsSync(file)) {
|
|
backup[file] = { existed: true, content: fs.readFileSync(file) };
|
|
} else {
|
|
backup[file] = { existed: false };
|
|
}
|
|
}
|
|
|
|
function restoreFile(file) {
|
|
const b = backup[file];
|
|
if (!b) return;
|
|
if (b.existed) {
|
|
fs.writeFileSync(file, b.content);
|
|
} else if (fs.existsSync(file)) {
|
|
fs.unlinkSync(file);
|
|
}
|
|
}
|
|
|
|
function readJSON(file) {
|
|
return JSON.parse(fs.readFileSync(file, "utf8"));
|
|
}
|
|
|
|
/* ------------------------------------------------------------------ *
|
|
* TEST CASES
|
|
* ------------------------------------------------------------------ */
|
|
|
|
// (a) succès semver simple
|
|
function test_simple_semver_updates_both_files() {
|
|
const name = "simple semver (9.9.9) updates version.json + admin-web/package.json";
|
|
const r = runScript(["9.9.9"]);
|
|
if (r.missing) return ko(name, "script not implemented yet");
|
|
try {
|
|
assert.strictEqual(r.status, 0, `expected exit 0, got ${r.status} (stderr=${r.stderr.trim()})`);
|
|
const v = readJSON(VERSION_JSON);
|
|
assert.strictEqual(v.version, "9.9.9", `version.json.version=${v.version}`);
|
|
const p = readJSON(ADMIN_PKG);
|
|
assert.strictEqual(p.version, "9.9.9", `admin-web/package.json.version=${p.version}`);
|
|
ok(name);
|
|
} catch (e) {
|
|
ko(name, e.message);
|
|
}
|
|
}
|
|
|
|
// (b) succès prerelease
|
|
function test_prerelease_semver_accepted() {
|
|
const name = "prerelease semver (1.2.3-beta.1) accepted";
|
|
const r = runScript(["1.2.3-beta.1"]);
|
|
if (r.missing) return ko(name, "script not implemented yet");
|
|
try {
|
|
assert.strictEqual(r.status, 0, `expected exit 0, got ${r.status} (stderr=${r.stderr.trim()})`);
|
|
const v = readJSON(VERSION_JSON);
|
|
assert.strictEqual(v.version, "1.2.3-beta.1", `version.json.version=${v.version}`);
|
|
const p = readJSON(ADMIN_PKG);
|
|
assert.strictEqual(p.version, "1.2.3-beta.1", `admin-web/package.json.version=${p.version}`);
|
|
ok(name);
|
|
} catch (e) {
|
|
ko(name, e.message);
|
|
}
|
|
}
|
|
|
|
// (c) échec sans arg
|
|
function test_no_arg_fails() {
|
|
const name = "no argument -> exit != 0";
|
|
const r = runScript([]);
|
|
if (r.missing) return ko(name, "script not implemented yet");
|
|
try {
|
|
assert.notStrictEqual(r.status, 0, `expected non-zero exit, got ${r.status}`);
|
|
ok(name);
|
|
} catch (e) {
|
|
ko(name, e.message);
|
|
}
|
|
}
|
|
|
|
// (d) échec version invalide
|
|
function test_invalid_version_fails() {
|
|
const name = "invalid version ('not-a-version') -> exit != 0";
|
|
const r = runScript(["not-a-version"]);
|
|
if (r.missing) return ko(name, "script not implemented yet");
|
|
try {
|
|
assert.notStrictEqual(r.status, 0, `expected non-zero exit, got ${r.status}`);
|
|
// fichiers ne doivent pas avoir été modifiés avec une version invalide
|
|
if (fs.existsSync(VERSION_JSON)) {
|
|
const v = readJSON(VERSION_JSON);
|
|
assert.notStrictEqual(v.version, "not-a-version", "version.json should not contain invalid version");
|
|
}
|
|
ok(name);
|
|
} catch (e) {
|
|
ko(name, e.message);
|
|
}
|
|
}
|
|
|
|
// (e) préservation des autres clés du package.json
|
|
function test_preserves_other_keys() {
|
|
const name = "other keys of admin-web/package.json preserved (name, scripts, dependencies)";
|
|
const r = runScript(["7.7.7"]);
|
|
if (r.missing) return ko(name, "script not implemented yet");
|
|
try {
|
|
assert.strictEqual(r.status, 0, `expected exit 0, got ${r.status}`);
|
|
const p = readJSON(ADMIN_PKG);
|
|
// Le package.json actuel contient name, scripts, dependencies, devDependencies.
|
|
// On vérifie que ces clés sont toujours là et non vides.
|
|
assert.ok(typeof p.name === "string" && p.name.length > 0, `name missing/empty: ${p.name}`);
|
|
assert.ok(p.scripts && typeof p.scripts === "object", "scripts object missing");
|
|
assert.ok(Object.keys(p.scripts).length > 0, "scripts object empty");
|
|
assert.ok(p.dependencies && typeof p.dependencies === "object", "dependencies object missing");
|
|
assert.ok(Object.keys(p.dependencies).length > 0, "dependencies object empty");
|
|
// La version, elle, doit avoir été bumpée
|
|
assert.strictEqual(p.version, "7.7.7", `version should be 7.7.7, got ${p.version}`);
|
|
ok(name);
|
|
} catch (e) {
|
|
ko(name, e.message);
|
|
}
|
|
}
|
|
|
|
/* ------------------------------------------------------------------ *
|
|
* RUN
|
|
* ------------------------------------------------------------------ */
|
|
|
|
function main() {
|
|
console.log("# prepare-release.cjs — test suite (standalone, zero deps)");
|
|
console.log(`# script: ${path.relative(ROOT, SCRIPT)}`);
|
|
console.log(`# exists: ${fs.existsSync(SCRIPT)}`);
|
|
console.log("");
|
|
|
|
// Backup AVANT les tests d'écriture
|
|
backupFile(VERSION_JSON);
|
|
backupFile(ADMIN_PKG);
|
|
|
|
let crashed = false;
|
|
try {
|
|
test_simple_semver_updates_both_files();
|
|
test_prerelease_semver_accepted();
|
|
test_no_arg_fails();
|
|
test_invalid_version_fails();
|
|
test_preserves_other_keys();
|
|
} catch (e) {
|
|
crashed = true;
|
|
console.error("[ERROR] unexpected exception in test runner:", e);
|
|
} finally {
|
|
// Restore TOUJOURS
|
|
restoreFile(VERSION_JSON);
|
|
restoreFile(ADMIN_PKG);
|
|
}
|
|
|
|
console.log("");
|
|
console.log(`# Summary: ${passed} passed, ${failed} failed${crashed ? " (+runner crash)" : ""}`);
|
|
process.exit(failed === 0 && !crashed ? 0 : 1);
|
|
}
|
|
|
|
main();
|