Files
blog/test/obsidian-plugin.test.js
2026-10-06 16:00:36 -05:00

163 lines
5.2 KiB
JavaScript

import test from "node:test";
import assert from "node:assert/strict";
import fs from "node:fs";
import path from "node:path";
const pluginPath = path.resolve("/home/venus/Documents/Notes/.obsidian/plugins/blog-publisher/main.js");
// Pure helper function to be tested and exported/used by plugin
export function insertOrUpdateFrontmatterProperty(content, key, value) {
if (typeof content !== "string") return "";
const fmRegex = /^---\r?\n([\s\S]*?)\r?\n---/;
const match = content.match(fmRegex);
if (match) {
let fmBlock = match[1];
const keyRegex = new RegExp(`^${key}:.*$`, "m");
if (value === null || value === undefined) {
// Remove property if value is null
fmBlock = fmBlock.replace(new RegExp(`^${key}:.*\\r?\\n?`, "m"), "");
} else if (keyRegex.test(fmBlock)) {
// Replace existing property
fmBlock = fmBlock.replace(keyRegex, `${key}: "${value}"`);
} else {
// Append property to frontmatter
fmBlock = `${fmBlock}\n${key}: "${value}"`;
}
return content.replace(fmRegex, `---\n${fmBlock.trim()}\n---`);
} else if (value) {
return `---\n${key}: "${value}"\n---\n\n${content}`;
}
return content;
}
export function computePublicUrl(serverUrl, postPath) {
const base = (serverUrl || "").replace(/\/+$/, "");
const p = (postPath || "").startsWith("/") ? postPath : `/${postPath || ""}`;
return `${base}${p}`;
}
test("Obsidian Plugin: computePublicUrl normalizes slashes correctly", () => {
assert.equal(
computePublicUrl("https://riverrooks.dev", "/posts/test-note/"),
"https://riverrooks.dev/posts/test-note/"
);
assert.equal(
computePublicUrl("https://riverrooks.dev/", "/posts/test-note/"),
"https://riverrooks.dev/posts/test-note/"
);
assert.equal(
computePublicUrl("https://riverrooks.dev///", "posts/test-note/"),
"https://riverrooks.dev/posts/test-note/"
);
assert.equal(
computePublicUrl("http://localhost:8080", "/posts/test-note/"),
"http://localhost:8080/posts/test-note/"
);
});
test("Obsidian Plugin: insertOrUpdateFrontmatterProperty adds public-url when missing", () => {
const original = `---
title: "Sample Note"
date: 2026-09-23
publish: true
---
# Content here`;
const updated = insertOrUpdateFrontmatterProperty(
original,
"public-url",
"https://riverrooks.dev/posts/sample-note/"
);
assert.match(
updated,
/public-url:\s*"https:\/\/riverrooks\.dev\/posts\/sample-note\/"/,
"Must insert public-url into frontmatter"
);
assert.match(updated, /title:\s*"Sample Note"/, "Preserves title");
assert.match(updated, /publish:\s*true/, "Preserves publish flag");
assert.match(updated, /# Content here/, "Preserves body content");
});
test("Obsidian Plugin: insertOrUpdateFrontmatterProperty updates existing public-url", () => {
const original = `---
title: "Updated Note"
date: 2026-09-23
public-url: "https://old.domain/posts/sample-note/"
---
Body`;
const updated = insertOrUpdateFrontmatterProperty(
original,
"public-url",
"https://riverrooks.dev/posts/updated-note/"
);
assert.match(
updated,
/public-url:\s*"https:\/\/riverrooks\.dev\/posts\/updated-note\/"/,
"Must update public-url to new URL"
);
assert.doesNotMatch(
updated,
/old\.domain/,
"Old URL must be replaced"
);
});
test("Obsidian Plugin: insertOrUpdateFrontmatterProperty removes public-url on unpublish", () => {
const original = `---
title: "Unpublished Note"
date: 2026-09-23
public-url: "https://riverrooks.dev/posts/sample-note/"
---
Body`;
const updated = insertOrUpdateFrontmatterProperty(original, "public-url", null);
assert.doesNotMatch(updated, /public-url:/, "Must remove public-url when value is null");
assert.match(updated, /title:\s*"Unpublished Note"/, "Preserves other frontmatter");
});
test("Obsidian Plugin: Adversarial edge cases for frontmatter property insertion", () => {
// 1. Empty content
assert.equal(insertOrUpdateFrontmatterProperty("", "public-url", "https://url"), "---\npublic-url: \"https://url\"\n---\n\n");
// 2. Non-string inputs
assert.equal(insertOrUpdateFrontmatterProperty(null, "public-url", "https://url"), "");
assert.equal(insertOrUpdateFrontmatterProperty(undefined, "public-url", "https://url"), "");
// 3. Note without frontmatter
const plain = "# Just a header\nSome text.";
const result = insertOrUpdateFrontmatterProperty(plain, "public-url", "https://url");
assert.match(result, /^---\npublic-url:\s*"https:\/\/url"\n---/);
});
test("Obsidian Plugin: main.js in vault includes public-url insertion and recursion guard", () => {
assert.ok(fs.existsSync(pluginPath), `Plugin main.js must exist at ${pluginPath}`);
const pluginContent = fs.readFileSync(pluginPath, "utf-8");
// 1. Must handle public-url
assert.match(pluginContent, /public-url/i, "main.js must reference 'public-url'");
// 2. Must guard against infinite loops during frontmatter updates
assert.match(
pluginContent,
/isUpdatingFrontmatter/i,
"main.js must maintain a guard to prevent metadataCache recursion loops"
);
// 3. Must use processFrontMatter or frontmatter updater
assert.match(
pluginContent,
/processFrontMatter|updateFrontmatter/i,
"main.js must implement frontmatter updating logic"
);
});