# SSR expectations of the SEO layer's v0.2.0 features against the fixture
# SEO API (testing/fixtures, answers in testing/fixtures/seo). Grammar in
# testing/smoke-ssr.mjs. testing/expect.txt keeps the v0.1.1 behaviour and
# runs against a backend without /site (--no-site).

# Tracer: a page rendered by Nuxt carries the CMS title, canonical, hreflang
# and one JSON-LD graph from the resolve answer.
200 /blog/lwia-grzywa contains=<title>Lwia grzywa | Example</title> count=application/ld+json:1 count=rel="canonical":1 contains=hreflang="x-default" contains=lang="pl"><head>
200 /blog/lwia-grzywa contains=<link rel="alternate" hreflang="en" href="https://example.test/en/blog/lions-mane" contains=hreflang="pl"
200 /blog/lwia-grzywa contains=<meta property="og:locale" content="pl_PL"> contains=<meta property="og:locale:alternate" content="en_US">
200 /blog/lwia-grzywa notcontains=Own catch-all title
# One graph: the CMS nodes, the layer's node merged by @id (CMS values win),
# a new layer node appended; "<" inside the JSON cannot end the script.
200 /blog/lwia-grzywa count=data-hid="seo-jsonld":1 count="@type":"WebPage":1 contains="name":"Lwia grzywa" notcontains=Layer name loses contains="inLanguage":"pl" contains=#itemlist
200 /blog/lwia-grzywa notcontains=</script><script>alert

# Redirect decision before the page (and its route cache): the Location
# comes from the answer only; a target on the site's origin becomes a path,
# another host stays absolute; a crafted Host or X-Forwarded-Host changes
# nothing. No X-Robots-Tag on a redirect.
301 /stary header=Location: /nowy noheader=X-Robots-Tag
301 /stary reqheader=Host: evil.test reqheader=X-Forwarded-Host: evil.test reqheader=X-Forwarded-Proto: http header=Location: /nowy
302 /stary-zewnetrzny header=Location: https://partner.test/oferta?a=1
# 410 with the app's error page, also on staging with the noindex header.
410 /usuniety
410 /usuniety-staging header=X-Robots-Tag: noindex, nofollow
# A page's x_robots_tag becomes the header.
200 /blog/ukryty header=X-Robots-Tag: noindex, nofollow contains=<meta name="robots" content="noindex, nofollow">
# not_found: a pagination.invalid answer is a 404 (also on a page that would
# render); any other not_found is left to Nuxt's routing.
404 /plain?page=abc
200 /plain?page=2 contains=<title>Plain page | Playground</title>
404 /nieznana-strona

# The resolve cache: every request above to the tracer page made one call.
resolves /blog/lwia-grzywa 1
resolves /stary 1
# The Nuxt-server resolve route answers through the same cache.
200 /api/__seo__/resolve?url=/blog/lwia-grzywa contains="title":"Lwia grzywa | Example" header=X-Robots-Tag: noindex
resolves /blog/lwia-grzywa 1
422 /api/__seo__/resolve?url=https://evil.test/

# Root files from the backend, with its status, content type and
# X-Robots-Tag; a backend failure is 503 with Retry-After.
200 /robots.txt contains=Disallow: /konto type=text/plain header=X-Content-Type-Options: nosniff
200 /sitemap.xml contains=<sitemapindex type=application/xml
200 /sitemap-posts-1.xml contains=<urlset type=application/xml header=X-Robots-Tag: noindex
200 /llms.txt contains=Fixture llms.txt header=X-Robots-Tag: noindex
404 /sitemap-missing-1.xml
503 /sitemap-fail-1.xml header=Retry-After: 60
# Listed root files: a verification file and the IndexNow key file.
200 /google1234.html contains=google-site-verification: google1234.html header=X-Robots-Tag: noindex header=X-Content-Type-Options: nosniff
200 /a1b2c3d4e5f60718293a4b5c6d7e8f90.txt contains=a1b2c3d4e5f60718293a4b5c6d7e8f90 type=text/plain
# Not listed: passes through to Nuxt, which renders its 404 (the route
# middleware resolves it; no verification lookup is made).
404 /random.txt
404 /google0123.html
404 /kontakt

# 404 pages report themselves once with the bearer token; a 410 or a
# redirect does not.
report /kontakt
report /nieznana-strona
noreport /usuniety
noreport /stary

# Labels in the page's content locale (pl answer: the pl dictionary).
200 /blog/lwia-grzywa contains=<p class="seo-visually-hidden">Ścieżka nawigacji</p>

# Declared noindex without page code: a page whose meta requires sign-in,
# a page with its own seo.robots and a path under seo.noindexRoutes get the
# meta tag and the header; an ordinary page keeps the CMS robots.
200 /konto contains=<meta name="robots" content="noindex, nofollow"> count=name="robots":1 header=X-Robots-Tag: noindex, nofollow
200 /szkic contains=<meta name="robots" content="noindex, follow"> header=X-Robots-Tag: noindex, follow
200 /prywatne contains=<meta name="robots" content="noindex, nofollow"> header=X-Robots-Tag: noindex, nofollow
200 /plain noheader=X-Robots-Tag count=name="robots":0
200 /blog/lwia-grzywa contains=<meta name="robots" content="index, follow">

# The site answer through the layer's server, for useSeoSite().
200 /api/__seo__/site contains="site_url":"https://example.test" header=X-Robots-Tag: noindex

# The route report at server start: the static paths with the token, not
# the signed-in page, the page with a noindex seo.robots or the declared
# noindex route; those three go in its noindex list (G1), never an
# indexable path or the layer's HTML sitemap page. The build matches the
# site answer: no drift warning.
routereport 1 has=/ has=/blog has=/plain has=/about lacks=/konto lacks=/szkic lacks=/prywatne lacks=/mapa-strony noindex=/konto noindex=/szkic noindex=/prywatne lacksnoindex=/ lacksnoindex=/mapa-strony
log [vue-seo-layer] drift::0

# L1 breadcrumbs: a layout instance (app.vue) and a page instance render
# exactly one trail, server-rendered links, the last item as text with
# aria-current; none on the home page (one item) or a page without a trail.
200 /blog/lwia-grzywa count=<nav class="seo-breadcrumbs":1 contains=<a class="seo-breadcrumbs__link" href="/">Start</a> contains=<span class="seo-breadcrumbs__current" aria-current="page">Lwia grzywa</span> count=aria-current="page":1
200 / count=seo-breadcrumbs:0
200 /plain count=seo-breadcrumbs:0

# L2 pagination: numbered links in the CMS form, page 1 unnumbered, five
# pages around the current one plus the first and the last with two gaps,
# rel prev/next anchors and head links, and %pages% filled in the CMS title
# and description (the payload keeps the raw answer); one page renders
# none. aria-current: the current page and the breadcrumbs' last item.
200 /blog?page=5 count=<nav class="seo-pagination":1 contains=<a class="seo-pagination__prev" href="/blog?page=4" rel="prev"> contains=<a class="seo-pagination__next" href="/blog?page=6" rel="next"> contains=<span class="seo-pagination__current" aria-current="page">5</span> count=aria-current="page":2
200 /blog?page=5 contains=<a href="/blog" aria-label="Strona 1">1</a> contains=<a href="/blog?page=14" aria-label="Strona 14">14</a> count=seo-pagination__gap:2
200 /blog?page=5 contains=<link rel="prev" href="/blog?page=4" contains=<link rel="next" href="/blog?page=6" contains=<title>Blog – strona 5 z 14 | Example</title> contains=content="Wpisy o grzybach, strona 5 z 14" notcontains=z %pages% |</title> notcontains=content="Wpisy o grzybach, strona 5 z %pages%"
200 /blog?page=14&sort=new contains=<a class="seo-pagination__prev" href="/blog?sort=new&amp;page=13" rel="prev"> count=seo-pagination__next:0 count=rel="next":0
200 /blog?pages=1 count=seo-pagination:0 count=rel="prev":0

# L3 HTML sitemap: H1, one H2 per non-empty group (the empty one left out),
# the category tree nested, a large group's link to its group page; a URL
# that is not http(s) renders as text; long titles stay whole.
200 /mapa-strony contains=<h1 class="seo-sitemap__title">Mapa strony</h1> count=<h2:3 notcontains=Tagi contains=<a href="/mapa-strony/posts" class="">Wpisy: wszystkie (1234)</a> notcontains=href="javascript: notcontains=<script>alert
200 /mapa-strony contains=Grzyby</a><ul class="seo-sitemap__list"> contains=<a href="/grzyby/lecznicze" contains=musi się zawinąć</a> count=<h1:1
# A group page: built trail, H1 with the page suffix, pagination; ?page=1
# is a 301 to the unnumbered URL; an unknown group or a page past the last
# is a 404; a failing sitemap API is a 503 (never an empty cached page).
200 /mapa-strony/posts?page=2 contains=<h1 class="seo-sitemap__title">Mapa strony: Wpisy · Strona 2</h1> contains=<a class="seo-breadcrumbs__link" href="/mapa-strony">Mapa strony</a> contains=<span class="seo-breadcrumbs__current" aria-current="page">Wpisy</span> count=<nav class="seo-breadcrumbs":1 count=<nav class="seo-pagination":1 contains=href="/mapa-strony/posts?page=3"
200 /mapa-strony/posts contains=<h1 class="seo-sitemap__title">Mapa strony: Wpisy</h1> contains=Lwia grzywa
301 /mapa-strony/posts?page=1 header=Location: /mapa-strony/posts
404 /mapa-strony/nope
404 /mapa-strony/posts?page=9
404 /mapa-strony/posts?page=abc
503 /mapa-strony/fail
# Every group empty: the empty message (en labels on the en path).
200 /en/sitemap contains=<h1 class="seo-sitemap__title">Sitemap</h1> contains=<p class="seo-sitemap__empty">There are no pages to list yet.</p> count=<h2:0
# A locale the CMS has no HTML sitemap path for.
404 /sitemap

# L4: the footer link to the locale's HTML sitemap.
200 /blog/lwia-grzywa contains=<footer><a href="/mapa-strony" class="seo-sitemap-link">Mapa strony</a></footer>
