Lumi/scripts/verify-feedback-system.js
2026-06-18 04:24:50 +02:00

133 lines
5.3 KiB
JavaScript

const assert = require("assert");
const fs = require("fs");
const path = require("path");
const ejs = require("ejs");
const root = path.join(__dirname, "..");
const sandbox = fs.mkdtempSync(path.join(root, ".tmp-lumi-feedback-test-"));
const serviceDir = path.join(sandbox, "src", "services");
fs.mkdirSync(serviceDir, { recursive: true });
for (const file of ["db.js", "feedback.js"]) {
fs.copyFileSync(path.join(root, "src", "services", file), path.join(serviceDir, file));
}
let database = null;
try {
database = require(path.join(serviceDir, "db.js"));
database.migrate();
const feedback = require(path.join(serviceDir, "feedback.js"));
const db = database.db;
const now = Date.now();
db.prepare(
"INSERT INTO user_profiles (id, internal_username, created_at, updated_at) VALUES (?, ?, ?, ?)"
).run("user-1", "FeedbackUser", now, now);
db.prepare(
"INSERT INTO user_profiles (id, internal_username, created_at, updated_at) VALUES (?, ?, ?, ?)"
).run("admin-1", "AdminUser", now, now);
const entry = feedback.createFeedback({
summary: "Save button fails",
category: "broken_interaction",
severity: "broken",
scope_type: "element",
scope_label: "Save settings button",
description: "Clicking the save button does not apply the changes.",
steps_to_reproduce: "Open settings, change a field, click save.",
expected_behavior: "The settings should be saved.",
actual_behavior: "The page reloads without saving.",
current_url: "http://localhost/admin/settings",
page_title: "Settings",
target_metadata: {
selector: "#save-settings",
tag: "button",
text: "Save settings",
secret: "must not persist"
},
diagnostics: {
user_agent: "verification-agent",
viewport: "1200x800",
hidden: "must not persist"
}
}, { id: "user-1" });
assert.equal(entry.status, "new");
assert.equal(entry.target_metadata.secret, undefined);
assert.equal(entry.diagnostics.hidden, undefined);
assert.equal(feedback.listPublicFeedback({ userId: "user-1" })[0].is_mine, true);
assert.equal(feedback.listMyFeedback("user-1").length, 1);
feedback.addSubmitterComment(entry.id, "This also happens after a hard reload.", { id: "user-1" });
const withComment = feedback.getFeedbackForSubmitter(entry.id, "user-1");
assert.equal(withComment.comments.length, 1);
assert.equal(withComment.comments[0].kind, "submitter_comment");
feedback.markFeedbackViewed("user-1");
feedback.adminUpdateFeedback(entry.id, {
status: "needs_more_context",
category: "bug",
severity: "urgent",
admin_reply: "Can you add which browser this happened in?",
work_note: "Likely settings form regression.",
status_note: "Need browser detail."
}, { id: "admin-1" });
const notices = feedback.notificationSummary("user-1");
assert.equal(notices.needs_context, 1);
const adminEntry = feedback.getFeedbackForAdmin(entry.id);
assert(adminEntry.comments.some((comment) => comment.kind === "admin_reply"));
assert(adminEntry.comments.some((comment) => comment.kind === "work_note"));
const submitterEntry = feedback.getFeedbackForSubmitter(entry.id, "user-1");
assert.equal(submitterEntry.comments.some((comment) => comment.kind === "work_note"), false);
const todoPath = path.join(sandbox, "TODO.md");
fs.writeFileSync(todoPath, "# TODO\n\n## Done\n");
feedback.convertFeedbackToTodo(entry.id, "Fix feedback verification issue.", { id: "admin-1" }, todoPath);
assert(fs.readFileSync(todoPath, "utf8").includes("## Feedback-Derived TODOs"));
assert(fs.readFileSync(todoPath, "utf8").includes("Fix feedback verification issue."));
const feedbackView = path.join(root, "src", "web", "views", "feedback.ejs");
const adminView = path.join(root, "src", "web", "views", "admin-feedback.ejs");
const commonLocals = {
siteTitle: "Lumi Bot",
assetVersion: "verify",
theme: null,
botAvatar: null,
navSections: [],
user: { id: "user-1", username: "FeedbackUser" },
userAvatar: null,
userInitial: "F",
platformLogins: [],
platformLinks: [],
platforms: [],
flash: null,
softError: null,
feedbackNotifications: feedback.notificationSummary("user-1"),
feedbackOptions: feedback.feedbackOptions()
};
const userRendered = ejs.render(fs.readFileSync(feedbackView, "utf8"), {
...commonLocals,
title: "Feedback",
feedbackList: feedback.listPublicFeedback({ userId: "user-1" }),
myFeedback: feedback.listMyFeedback("user-1"),
selectedFeedback: feedback.getFeedbackForSubmitter(entry.id, "user-1")
}, { filename: feedbackView });
assert(userRendered.includes("My feedback"));
assert(userRendered.includes("Admin reply"));
const adminRendered = ejs.render(fs.readFileSync(adminView, "utf8"), {
...commonLocals,
user: { id: "admin-1", username: "AdminUser", isAdmin: true },
userInitial: "A",
title: "Feedback review",
feedbackItems: feedback.listFeedbackForAdmin({}),
filters: { status: "", category: "", severity: "", scope: "", submitter: "", needs_action: "", sort: "last_activity" }
}, { filename: adminView });
assert(adminRendered.includes("Feedback queue"));
assert(adminRendered.includes("Convert to TODO"));
console.log("Core feedback system verification passed.");
} finally {
database?.db.close();
fs.rmSync(sandbox, { recursive: true, force: true });
}