/** Verify: no avatars anywhere; project/report pages show nav for logged-in users only. */
import { chromium } from "playwright-core";
import { join, dirname } from "node:path";
import { fileURLToPath } from "node:url";
import { homedir } from "node:os";
const root = dirname(fileURLToPath(import.meta.url));
const SERVER = "http://localhost:8001";
const WEB = "http://localhost:5173";
const stamp = Date.now();
const EMAIL = `nav-verify-${stamp}@example.com`;
const PASSWORD = "nav-verify-pass";
const executablePath = join(homedir(), ".cache/ms-playwright/chromium-1234/chrome-linux64/chrome");
const browser = await chromium.launch({ executablePath, headless: true });
async function api(path, options = {}) {
const r = await fetch(SERVER + path, options);
if (!r.ok) throw new Error(`API ${path} -> ${r.status}: ${await r.text()}`);
return r.json();
}
await api("/api/auth/register", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ nickname: `nav-verify-${stamp}`, email: EMAIL, password: PASSWORD }),
});
const login = await api("/api/auth/login", {
method: "POST",
headers: { "Content-Type": "application/json", "X-Client": "extension" },
body: JSON.stringify({ email: EMAIL, password: PASSWORD }),
});
const auth = { Authorization: `Bearer ${login.token}` };
const project = await api("/api/projects", {
method: "POST",
headers: { "Content-Type": "application/json", ...auth },
body: JSON.stringify({ name: "Nav Verify", description: "shell check" }),
});
const note = await api("/api/reports", {
method: "POST",
headers: { "Content-Type": "application/json", ...auth },
body: JSON.stringify({
project_id: project.id,
type: "element_note",
title: "Nav verify report",
environment: { user_agent: "verify", browser: "Chromium", os: "Linux", viewport: { w: 1440, h: 900 }, dpr: 1, language: "ru" },
}),
});
const page = await browser.newPage({ viewport: { width: 1440, height: 900 } });
page.on("pageerror", (e) => console.log("[pageerror]", String(e).slice(0, 400)));
page.on("console", (m) => {
if (m.type() === "error" && !m.text().includes("Failed to load resource")) console.log("[console]", m.text().slice(0, 300));
});
// --- anonymous: report page without nav ---
await page.goto(`${WEB}/r/${note.share_token}`);
await page.waitForSelector(".report-page", { timeout: 15000 });
await page.waitForTimeout(800);
const anon = await page.evaluate(() => ({
hasShell: !!document.querySelector(".navigation-shell, .nav-shell, [class*=shell-sidebar]"),
hasTopbar: !!document.querySelector(".nav-topbar"),
body: !!document.querySelector(".shell-body"),
}));
console.log("anonymous report:", JSON.stringify(anon));
await page.screenshot({ path: "/tmp/ltt-shots/13-report-anon.png" });
// --- logged in: report + project pages with nav ---
await page.goto(`${WEB}/login`);
await page.fill("input[type='text'], input[type='email']", EMAIL);
await page.fill("input[type='password']", PASSWORD);
await page.click("button[type='submit']");
await page.waitForURL("**/");
await page.goto(`${WEB}/r/${note.share_token}`);
await page.waitForSelector(".report-page", { timeout: 15000 });
await page.waitForTimeout(800);
const authed = await page.evaluate(() => ({
topbar: !!document.querySelector(".nav-topbar"),
footerUser: document.querySelector(".shell-footer-user")?.textContent.trim() ?? null,
avatars: document.querySelectorAll("[class*=avatar]").length,
footerAvatar: document.querySelectorAll(".shell-footer [class*=avatar]").length,
}));
console.log("authed report:", JSON.stringify(authed));
await page.screenshot({ path: "/tmp/ltt-shots/14-report-authed.png" });
await page.goto(`${WEB}/p/${project.share_token}`);
await page.waitForSelector(".project-page", { timeout: 15000 });
await page.waitForTimeout(800);
const proj = await page.evaluate(() => ({
topbar: !!document.querySelector(".nav-topbar"),
avatars: document.querySelectorAll("[class*=avatar]").length,
}));
console.log("authed project:", JSON.stringify(proj));
await page.screenshot({ path: "/tmp/ltt-shots/15-project-authed.png" });
// settings page: avatar removed
await page.goto(`${WEB}/settings`);
await page.waitForTimeout(800);
const settings = await page.evaluate(() => ({
avatars: document.querySelectorAll("[class*=avatar]").length,
profileName: document.querySelector(".settings-profile-name")?.textContent.trim() ?? null,
}));
console.log("settings:", JSON.stringify(settings));
await page.screenshot({ path: "/tmp/ltt-shots/16-settings.png" });
await browser.close();
console.log("VERIFY OK");