auth-ui.test.js 2.32 KB
// Structural check for T22's login/register UI in live.html and dance.html
// (dev-plan-3.md). No browser/DOM tooling is available to `node --test`
// here, so this can't render the pages — but it catches the easy mistake
// in this style of plain-HTML+inline-JS codebase: an element id renamed in
// the markup without updating the matching getElementById() call, which
// would otherwise fail silently in a real browser (getElementById returns
// null, then the first click throws and nothing visibly explains why).
// The actual end-to-end behavior (register/login/logout, nickname binding
// from an existing viewer_uid cookie) was verified manually in a real
// browser against the running server; see the session notes.
const test = require("node:test");
const assert = require("node:assert/strict");
const fs = require("node:fs");
const path = require("node:path");

const AUTH_IDS = ["authBtn", "authModal", "authTitle", "authEmail", "authPassword", "authError", "authSubmitBtn", "authToggleBtn", "authCloseBtn"];
// register/login share one call site (`` `/api/auth/${authMode}` ``, authMode
// is "register" or "login"), so check for that template plus the two literal
// endpoints separately, rather than four literal path strings.
const AUTH_ENDPOINTS = ["/api/auth/${authMode}", "/api/auth/logout", "/api/auth/me"];

for (const page of ["live.html", "dance.html"]) {
  test(`${page}: every auth element id used in the script is actually declared in the markup`, () => {
    const html = fs.readFileSync(path.join(__dirname, page), "utf8");
    for (const id of AUTH_IDS) {
      assert.match(html, new RegExp(`id="${id}"`), `markup is missing id="${id}"`);
      assert.match(html, new RegExp(`getElementById\\("${id}"\\)`), `script never looks up #${id}`);
    }
  });

  test(`${page}: wires up all four auth endpoints`, () => {
    const html = fs.readFileSync(path.join(__dirname, page), "utf8");
    for (const endpoint of AUTH_ENDPOINTS) {
      assert.ok(html.includes(endpoint), `script never calls ${endpoint}`);
    }
  });

  test(`${page}: the auth modal is hidden by default (must not force a login gate)`, () => {
    const html = fs.readFileSync(path.join(__dirname, page), "utf8");
    assert.match(html, /<div class="nickname-modal" id="authModal" hidden>/, "authModal must start hidden — logging in is optional, never a forced gate");
  });
}