mirror of
https://github.com/hanzo-apps/hanzo.ai.git
synced 2026-10-30 14:58:08 +00:00
The bar is Models, Dev, Platform, Pricing, Docs, Enterprise, Log in, and Get API key. The homepage is seven sections. Launch pages stay in the tree and drop out of the index through lib/launch.ts. /platform forwards to /cloud. Model and repository floors come from the snapshots the build already keeps. Co-authored-by: z <[email protected]>
61 lines
2.8 KiB
TypeScript
61 lines
2.8 KiB
TypeScript
import { test, expect } from '@playwright/test'
|
|
import { LAYERS, href } from '../lib/layers'
|
|
import { FOOT, FOOT_LINE, GET_KEY, LEGAL, LOGIN, MENUS, away } from '../components/home/nav-data'
|
|
|
|
/**
|
|
* Every link the header, the phone sheet and the footer offer answers 200.
|
|
*
|
|
* The bar and the sheet are one tree (components/home/nav-data.ts). The footer
|
|
* is the short set, and it is read off the page to prove it stayed short. Run
|
|
* against `pnpm dev` or a live host with BASE_URL pointing at it. A
|
|
* redirect is not an answer: a row that lands on a forward names an address the
|
|
* site has retired. A dev server compiles each route on its first request, so
|
|
* the budget is per link, not per test.
|
|
*/
|
|
test("the footer's columns are Models, Platform, Developers, Solutions, Learn and Company", () => {
|
|
expect(FOOT.map((m) => m.label)).toEqual(['Models', 'Platform', 'Developers', 'Solutions', 'Learn', 'Company'])
|
|
})
|
|
|
|
test('every header and footer link answers 200', async ({ page, request }) => {
|
|
test.setTimeout(900_000)
|
|
await page.goto('/', { waitUntil: 'load' })
|
|
const hrefs = new Set<string>(
|
|
MENUS.flatMap((m) => [m.href, ...m.groups.flatMap((g) => g.links.map((l) => l.href))]),
|
|
)
|
|
for (const link of [LOGIN, GET_KEY, ...LEGAL]) hrefs.add(link.href)
|
|
const want = [
|
|
...FOOT.flatMap((m) => [m.href, ...m.groups.flatMap((g) => g.links.map((l) => l.href))]),
|
|
...FOOT_LINE.map((l) => l.href),
|
|
]
|
|
const foot = await page.locator('footer[data-slot="footer"] a[href]').evaluateAll((els) => els.map((e) => e.getAttribute('href') ?? ''))
|
|
expect(foot.filter((h) => h !== '/').sort()).toEqual([...new Set(want)].sort())
|
|
for (const h of want) hrefs.add(h)
|
|
|
|
const failed: string[] = []
|
|
for (const h of hrefs) {
|
|
if (h.startsWith('#')) continue // a control on this page, not a page
|
|
const res = away(h)
|
|
? await request.get(h, { timeout: 30_000 })
|
|
: await request.get(h, { maxRedirects: 0, timeout: 120_000 })
|
|
if (res.status() !== 200) failed.push(`${h} → ${res.status()}`)
|
|
}
|
|
expect(failed, 'a header or footer link that does not answer 200').toEqual([])
|
|
})
|
|
|
|
/**
|
|
* The product index is the OS: every layer in lib/layers, each linking its own
|
|
* page, and each page answering. Replaces the ten-category index this route used
|
|
* to hold.
|
|
*/
|
|
test('/products draws every layer, and every layer page answers', async ({ page, request }) => {
|
|
test.setTimeout(900_000)
|
|
const res = await page.goto('/products')
|
|
expect(res?.status()).toBe(200)
|
|
await expect(page.locator('h1')).toHaveCount(1)
|
|
for (const l of LAYERS) {
|
|
await expect(page.locator(`main a[href="${href(l)}"]`).first(), `/products links ${l.name}`).toBeVisible()
|
|
const layer = await request.get(href(l), { maxRedirects: 0, timeout: 120_000 })
|
|
expect(layer.status(), `${href(l)} answers`).toBe(200)
|
|
}
|
|
})
|