// Tests for shared/logo.js — turns the .app-header__logo SVG into a // link to the project landing (or deployment root). Mounts at // DOMContentLoaded across every tool's bundle. // // Strategy: serve any tool's compiled HTML at multiple URL paths via a // tiny in-process HTTP server, so we can verify the wrapping anchor's // href reflects the URL the page was loaded from. import { test, expect } from '@playwright/test'; import * as http from 'http'; import * as fs from 'fs'; import * as path from 'path'; const HTML_PATH = path.resolve('classifier/dist/classifier.html'); let server; let baseUrl; test.beforeAll(async () => { const html = fs.readFileSync(HTML_PATH, 'utf8'); server = http.createServer((req, res) => { res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' }); res.end(html); }); await new Promise(r => server.listen(0, '127.0.0.1', r)); baseUrl = `http://127.0.0.1:${server.address().port}`; }); test.afterAll(async () => { if (server) await new Promise(r => server.close(r)); }); test.describe('shared/logo.js', () => { test('does NOT wrap the logo on file://', async ({ page }) => { const filePath = path.resolve('classifier/dist/classifier.html'); await page.goto(`file://${filePath}`, { waitUntil: 'load' }); const wrapped = await page.evaluate(() => { const logo = document.querySelector('.app-header__logo'); return logo && logo.parentElement && logo.parentElement.tagName === 'A'; }); expect(wrapped).toBe(false); }); test('wraps with href=/ at the deployment root', async ({ page }) => { await page.goto(`${baseUrl}/`, { waitUntil: 'load' }); const got = await page.evaluate(() => { const a = document.querySelector('.app-header__logo-link'); return a && a.getAttribute('href'); }); expect(got).toBe('/'); }); test('wraps with href=/ when inside a project subtree', async ({ page }) => { await page.goto(`${baseUrl}/Project-1/working/casey/notes.md`, { waitUntil: 'load' }); const got = await page.evaluate(() => { const a = document.querySelector('.app-header__logo-link'); return a && a.getAttribute('href'); }); expect(got).toBe('/Project-1'); }); test('the wrapper carries an aria-label matching its target', async ({ page }) => { await page.goto(`${baseUrl}/Project-1/staging/`, { waitUntil: 'load' }); const probe = await page.evaluate(() => { const a = document.querySelector('.app-header__logo-link'); return a && { href: a.getAttribute('href'), label: a.getAttribute('aria-label'), }; }); expect(probe.href).toBe('/Project-1'); expect(probe.label).toBe('Project home'); }); test('mount is idempotent — already-wrapped logo is left alone', async ({ page }) => { await page.goto(`${baseUrl}/Project-1/`, { waitUntil: 'load' }); const wrapperCount = await page.evaluate(() => { // Run mount a second time — should be a no-op. window.zddc.logo.mount(); return document.querySelectorAll('.app-header__logo-link').length; }); expect(wrapperCount).toBe(1); }); });