feat: redesign public and authenticated UI with mobile-first daisyui pages
This commit is contained in:
@@ -2,33 +2,53 @@
|
||||
|
||||
const test = require("node:test");
|
||||
const assert = require("node:assert/strict");
|
||||
const { layout, renderHomePage, renderAudioPage } = require("../src/views/pages");
|
||||
const {
|
||||
shell,
|
||||
renderLandingPage,
|
||||
renderLoginPage,
|
||||
renderAppPage,
|
||||
renderAudioPage,
|
||||
} = require("../src/views/pages");
|
||||
|
||||
test("layout includes daisyui stylesheet and mobile-first wrapper", () => {
|
||||
const html = layout({ title: "t", content: "x" });
|
||||
test("shell includes daisyui and pwa tags", () => {
|
||||
const html = shell({ title: "t", content: "x" });
|
||||
assert.match(html, /daisyui@5/);
|
||||
assert.match(html, /max-w-md mx-auto p-4/);
|
||||
assert.match(html, /manifest.webmanifest/);
|
||||
assert.match(html, /manifest\.webmanifest/);
|
||||
assert.match(html, /serviceWorker/);
|
||||
});
|
||||
|
||||
test("home page renders jobs list and wallet credits", () => {
|
||||
const html = renderHomePage({
|
||||
authenticated: true,
|
||||
test("landing page renders hero and flow sections", () => {
|
||||
const html = renderLandingPage({ authenticated: false, userId: null });
|
||||
assert.match(html, /From X Article to audiobook in one mention/);
|
||||
assert.match(html, /id="how"/);
|
||||
assert.match(html, /id="pricing"/);
|
||||
});
|
||||
|
||||
test("login page renders username form", () => {
|
||||
const html = renderLoginPage({ returnTo: "/audio/1" });
|
||||
assert.match(html, /action="\/auth\/dev-login"/);
|
||||
assert.match(html, /name="userId"/);
|
||||
assert.match(html, /value="\/audio\/1"/);
|
||||
});
|
||||
|
||||
test("app page renders stats and forms", () => {
|
||||
const html = renderAppPage({
|
||||
userId: "u1",
|
||||
balance: 7,
|
||||
jobs: [{ assetId: "a1", status: "completed", article: { title: "Hello" } }],
|
||||
summary: { balance: 4, totalJobs: 2, totalCreditsSpent: 2 },
|
||||
jobs: [{ assetId: "1", status: "completed", article: { title: "Hello" }, creditsCharged: 1 }],
|
||||
});
|
||||
|
||||
assert.match(html, /Wallet Credits/);
|
||||
assert.match(html, /7/);
|
||||
assert.match(html, /Top up credits/);
|
||||
assert.match(html, /Simulate mention/);
|
||||
assert.match(html, /Hello/);
|
||||
});
|
||||
|
||||
test("audio page asks auth/payment when access is denied", () => {
|
||||
test("audio page shows unlock action when payment is required", () => {
|
||||
const html = renderAudioPage({
|
||||
audio: { id: "a1", storageKey: "audio/a1.mp3", articleTitle: "A", durationSec: 30 },
|
||||
audio: { id: "1", storageKey: "audio/1.mp3", articleTitle: "A", durationSec: 30 },
|
||||
accessDecision: { allowed: false, reason: "payment_required", creditsRequired: 3 },
|
||||
userId: "u2",
|
||||
});
|
||||
|
||||
assert.match(html, /Unlock required: 3 credits/);
|
||||
assert.match(html, /Pay 3 credits and unlock forever/);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user