const test = require("node:test"); const assert = require("node:assert/strict"); const fs = require("node:fs/promises"); const os = require("node:os"); const path = require("node:path"); const { findUrlOccurrences, replaceUrlInFiles } = require("../lib/url_replacements"); const { loadExternalLinksReport, getLinksByStatus } = require("../lib/external_links_report"); /** * Ecrit un fichier texte en creant son dossier parent. * @param {string} filePath Chemin absolu du fichier. * @param {string} content Contenu a ecrire. */ async function writeFixture(filePath, content) { await fs.mkdir(path.dirname(filePath), { recursive: true }); await fs.writeFile(filePath, content, "utf8"); } test("replaceUrlInFiles remplace les occurrences exactes dans markdown, yaml et json", async () => { const tempRoot = await fs.mkdtemp(path.join(os.tmpdir(), "dead-links-replace-")); const contentRoot = path.join(tempRoot, "content"); const deadUrl = "https://dead.example.com/page"; const replacementUrl = "https://archive.example.com/page"; await writeFixture( path.join(contentRoot, "article", "index.md"), `Lien [mort](${deadUrl})\nEncore ${deadUrl}\n` ); await writeFixture( path.join(contentRoot, "article", "data", "meta.yaml"), `source: "${deadUrl}"\n` ); await writeFixture( path.join(contentRoot, "stats", "data.json"), JSON.stringify({ url: deadUrl, untouched: "https://ok.example.com" }, null, 2) ); const matches = await findUrlOccurrences(contentRoot, deadUrl); assert.deepStrictEqual( matches.map((match) => [path.relative(contentRoot, match.filePath), match.occurrences]), [ ["article/data/meta.yaml", 1], ["article/index.md", 2], ["stats/data.json", 1], ] ); const result = await replaceUrlInFiles(contentRoot, deadUrl, replacementUrl, { matches }); assert.equal(result.totalOccurrences, 4); assert.equal(result.changedFiles.length, 3); const markdown = await fs.readFile(path.join(contentRoot, "article", "index.md"), "utf8"); const yaml = await fs.readFile(path.join(contentRoot, "article", "data", "meta.yaml"), "utf8"); const json = await fs.readFile(path.join(contentRoot, "stats", "data.json"), "utf8"); assert.ok(markdown.includes(replacementUrl)); assert.ok(!markdown.includes(deadUrl)); assert.ok(yaml.includes(replacementUrl)); assert.ok(json.includes(replacementUrl)); await fs.rm(tempRoot, { recursive: true, force: true }); }); test("loadExternalLinksReport retourne correctement les liens 404 du cache YAML", async () => { const tempRoot = await fs.mkdtemp(path.join(os.tmpdir(), "dead-links-cli-")); const reportPath = path.join(tempRoot, "external_links.yaml"); const deadUrl = "https://dead.example.com/article"; await writeFixture( reportPath, [ "generatedAt: '2026-03-25T21:00:00.000Z'", "links:", ` - url: ${deadUrl}`, " status: 404", " locations:", " - file: content/demo/index.md", " line: 5", " page: /demo", "", ].join("\n") ); const report = loadExternalLinksReport(reportPath); const deadLinks = getLinksByStatus(report, 404); assert.equal(report.generatedAt, "2026-03-25T21:00:00.000Z"); assert.equal(deadLinks.length, 1); assert.equal(deadLinks[0].url, deadUrl); assert.equal(deadLinks[0].locations[0].file, "content/demo/index.md"); assert.equal(deadLinks[0].locations[0].line, 5); await fs.rm(tempRoot, { recursive: true, force: true }); });