import assert from 'node:assert/strict'; import { DOMParser } from 'linkedom'; const base = (process.env.VERIFY_URL || 'http://127.0.0.1:8080').replace(/\/$/, ''); const get = async (route) => { const response = await fetch(base + route, { redirect: 'manual', signal: AbortSignal.timeout(15000) }); return { response, text: await response.text() }; }; const xml = await get('/sitemap.xml'); assert.equal(xml.response.status, 200); const sitemap = new DOMParser().parseFromString(xml.text, 'text/xml'); const urls = [...sitemap.querySelectorAll('loc')].map((el) => el.textContent); assert.equal(new Set(urls).size, urls.length); const origin = new URL(urls[0]).origin; const paths = urls.map((url) => new URL(url).pathname); const selected = new Set(['/', '/services/', '/company/staff/', '/price/', '/contacts/', '/legaldocs/', '/checkup/', '/sales/']); for (const prefix of ['/company/staff/', '/price/', '/checkup/', '/legaldocs/']) { const group = paths.filter((p) => p.startsWith(prefix) && p !== prefix); if (group[0]) selected.add(group[0]); if (prefix === '/company/staff/') { const doctor = group.find((p) => p.split('/').filter(Boolean).length === 4); if (doctor) selected.add(doctor); } } for (const path of paths) selected.add(path); let hits = 0; for (const path of selected) { const { response, text } = await get(path); assert.equal(response.status, 200, path); const doc = new DOMParser().parseFromString(text, 'text/html'); for (const selector of ['title', 'h1', 'meta[name="description"]', 'link[rel="canonical"]', '#page-data', 'script[type="application/ld+json"]']) { assert.equal(doc.querySelectorAll(selector).length, 1, `${path}: ${selector}`); } assert.equal(doc.querySelector('link[rel="canonical"]').getAttribute('href'), origin + path, path); assert.ok(doc.querySelector('meta[name="description"]').getAttribute('content').trim(), `${path}: empty description`); assert.ok(doc.querySelector('#root').textContent.length > 500, `${path}: empty server HTML`); const initial = JSON.parse(doc.querySelector('#page-data').textContent); assert.ok(initial.prerendered); assert.ok(!Object.keys(initial).some((k) => /admin|lead|session/i.test(k))); const schema = JSON.parse(doc.querySelector('script[type="application/ld+json"]').textContent); assert.ok(schema['@graph'].some((n) => n['@type'] === 'BreadcrumbList')); assert.equal(schema['@graph'][0].url, origin + path); const second = await get(path); assert.equal(second.response.headers.get('x-html-cache'), 'hit', `${path}: cache miss on identical data`); hits++; } const query = await get('/company/staff/?q=test'); assert.equal(query.response.status, 200); assert.ok(query.response.headers.get('x-robots-tag').includes('noindex')); const queryDoc = new DOMParser().parseFromString(query.text, 'text/html'); assert.equal(queryDoc.querySelector('link[rel="canonical"]').getAttribute('href'), origin + '/company/staff/'); for (const alias of ['/company/docs/', '/services/estetic/rinoplastika']) { assert.equal((await get(alias)).response.status, 301, alias); } for (const missing of ['/services/not-a-service/', '/company/staff/not-a-specialty/', '/company/staff/not-a-specialty/not-a-doctor/', '/price/not-a-price/', '/checkup/not-a-checkup/', '/legaldocs/not-a-document/', '/not-a-page/']) { assert.equal((await get(missing)).response.status, 404, missing); } console.log(`Live SEO verified: ${selected.size} server-rendered pages, ${urls.length} sitemap URLs, ${hits} cache hits; query noindex, aliases and real 404s.`);