124 lines
4.3 KiB
JavaScript
124 lines
4.3 KiB
JavaScript
const assert = require("assert");
|
|
const fs = require("fs");
|
|
const path = require("path");
|
|
const ejs = require("ejs");
|
|
|
|
const root = path.join(__dirname, "..");
|
|
|
|
function listFiles(directory, extension, output = []) {
|
|
for (const entry of fs.readdirSync(directory, { withFileTypes: true })) {
|
|
const target = path.join(directory, entry.name);
|
|
if (entry.isDirectory()) listFiles(target, extension, output);
|
|
else if (target.endsWith(extension)) output.push(target);
|
|
}
|
|
return output;
|
|
}
|
|
|
|
function verifyViews() {
|
|
const viewRoots = [path.join(root, "src", "web", "views"), path.join(root, "plugins")];
|
|
const files = viewRoots.flatMap((directory) => listFiles(directory, ".ejs"));
|
|
for (const file of files) {
|
|
ejs.compile(fs.readFileSync(file, "utf8"), { filename: file });
|
|
}
|
|
return files.length;
|
|
}
|
|
|
|
function verifyThemeService() {
|
|
const sandbox = fs.mkdtempSync(path.join(root, ".tmp-lumi-theme-test-"));
|
|
const serviceDir = path.join(sandbox, "src", "services");
|
|
let database = null;
|
|
fs.mkdirSync(serviceDir, { recursive: true });
|
|
for (const file of ["config.js", "db.js", "settings.js", "themes.js"]) {
|
|
fs.copyFileSync(
|
|
path.join(root, "src", "services", file),
|
|
path.join(serviceDir, file)
|
|
);
|
|
}
|
|
|
|
try {
|
|
database = require(path.join(serviceDir, "db.js"));
|
|
database.migrate();
|
|
require(path.join(serviceDir, "settings.js")).ensureDefaults();
|
|
const themes = require(path.join(serviceDir, "themes.js"));
|
|
|
|
assert.strictEqual(themes.BUILTIN_THEMES.length, 6);
|
|
for (const theme of themes.BUILTIN_THEMES) {
|
|
assert.deepStrictEqual(themes.validateThemeValues(theme), []);
|
|
}
|
|
|
|
const library = themes.listThemes();
|
|
assert(library.every((theme) => theme.builtin));
|
|
assert.throws(
|
|
() => themes.saveCustomTheme("builtin:lumi-default", library[0]),
|
|
/read-only/
|
|
);
|
|
|
|
const copy = themes.duplicateTheme("builtin:midnight", "Verification Theme");
|
|
assert.strictEqual(copy.builtin, false);
|
|
themes.setActiveTheme(copy.id);
|
|
assert.strictEqual(themes.getActiveTheme().id, copy.id);
|
|
|
|
const invalid = JSON.parse(JSON.stringify(copy));
|
|
invalid.light.text = "not-a-color";
|
|
assert.throws(() => themes.saveCustomTheme(copy.id, invalid), /hex color/);
|
|
|
|
const renamed = themes.renameCustomTheme(copy.id, "Verified Theme");
|
|
assert.strictEqual(renamed.name, "Verified Theme");
|
|
|
|
const repaired = themes.normalizeThemeValues({
|
|
...renamed,
|
|
light: { ...renamed.light, text: "#ffffff", surface: "#ffffff" }
|
|
});
|
|
assert.notStrictEqual(repaired.light.text, repaired.light.surface);
|
|
|
|
const themeView = path.join(root, "src", "web", "views", "admin-theme.ejs");
|
|
const rendered = ejs.render(fs.readFileSync(themeView, "utf8"), {
|
|
title: "Theming",
|
|
siteTitle: "Lumi Bot",
|
|
assetVersion: "verify",
|
|
theme: renamed,
|
|
activeTheme: renamed,
|
|
themes: themes.listThemes(),
|
|
editingTheme: renamed,
|
|
botAvatar: null,
|
|
navSections: [],
|
|
user: { username: "Admin" },
|
|
userAvatar: null,
|
|
userInitial: "A",
|
|
platformLogins: [],
|
|
flash: null,
|
|
softError: null
|
|
}, { filename: themeView });
|
|
assert(rendered.includes("data-theme-editor"));
|
|
assert(rendered.includes("Built-in · read-only"));
|
|
|
|
const statusView = path.join(root, "plugins", "moderation", "views", "status.ejs");
|
|
const statusRendered = ejs.render(fs.readFileSync(statusView, "utf8"), {
|
|
title: "Access restricted",
|
|
assetVersion: "verify",
|
|
theme: renamed,
|
|
sanction: {
|
|
action_type: "timeout",
|
|
status: "active",
|
|
created_at: Date.now(),
|
|
expires_at: Date.now() + 60000,
|
|
reason_short: "Verification",
|
|
reason_detail: "Standalone themed view verification.",
|
|
created_by_name: "Admin"
|
|
}
|
|
}, { filename: statusView });
|
|
assert(statusRendered.includes("/lumi-components.css"));
|
|
assert(statusRendered.includes('data-theme-id="custom:'));
|
|
|
|
themes.deleteCustomTheme(copy.id);
|
|
assert.strictEqual(themes.getActiveTheme().id, themes.DEFAULT_THEME_ID);
|
|
} finally {
|
|
database?.db.close();
|
|
fs.rmSync(sandbox, { recursive: true, force: true });
|
|
}
|
|
}
|
|
|
|
const viewCount = verifyViews();
|
|
verifyThemeService();
|
|
console.log(`WebUI verification passed: ${viewCount} EJS views and theme CRUD.`);
|