hypertwist/website/tests/e2e/responsive-public-pages.spec.ts
2026-07-03 10:59:04 +00:00

154 lines
4.2 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { expect, test, type Page } from '@playwright/test'
import { gotoAppRoute } from './helpers/navigation'
import { expectNoHorizontalOverflow } from './helpers/layout'
type PublicRouteExpectation = {
path: string
heading: string
cta?: string
}
const responsivePublicRoutes: readonly PublicRouteExpectation[] = [
{
path: '/',
heading: 'One serious home for classic cubes, 120cell, 5D, and deep daily practice.',
cta: 'Create account',
},
{
path: '/features',
heading: 'A deep training toolkit, not just a timer.',
},
{
path: '/about',
heading: 'A training stack built for people who want more than a timer.',
},
{
path: '/resources',
heading: 'Every guide you need to start, train, and grow with HyperTwist.',
},
{
path: '/docs',
heading: 'The complete HyperTwist manual.',
},
{
path: '/pricing',
heading: 'Pricing that matches the actual delivery model.',
},
{
path: '/download',
heading: 'Download the desktop build and pair it with your browser account.',
},
{
path: '/getting-started',
heading: 'Start on the website. Train in the desktop app.',
},
{
path: '/launch-status',
heading: 'See how public pages, account access, and desktop delivery work together.',
},
{
path: '/support',
heading: 'Help for access, downloads, setup, and launch.',
},
{
path: '/login',
heading: 'Log in to HyperTwist',
cta: 'Log in',
},
{
path: '/changelog',
heading: 'Release notes for players, teams, and studios.',
},
{
path: '/open-source-notices',
heading: 'Open-source notices for public distribution surfaces.',
},
{
path: '/privacy',
heading: 'Privacy model',
},
{
path: '/terms',
heading: 'Terms of access',
},
{
path: '/shipping-payment',
heading: 'Digital delivery only',
},
{
path: '/register',
heading: 'Create a HyperTwist account',
cta: 'Create account',
},
] as const
async function assertResponsivePublicRoute(page: Page, route: PublicRouteExpectation) {
await gotoAppRoute(page, route.path, { waitUntil: 'domcontentloaded', timeoutMs: 45_000 })
await expect(page.getByRole('heading', { level: 1, name: route.heading })).toBeVisible()
if (route.cta) {
const button = page.getByRole('button', { name: route.cta })
if ((await button.count()) > 0) {
await expect(button.first()).toBeVisible()
} else {
await expect(page.getByRole('link', { name: route.cta }).first()).toBeVisible()
}
}
if (route.path === '/login' || route.path === '/register') {
await expectAuthShellAboveBackdrop(page)
}
await expectNoHorizontalOverflow(page)
}
async function expectAuthShellAboveBackdrop(page: Page) {
await expect(page.locator('#hypertwist-auth-shell-backdrop')).toHaveCount(1)
const stacking = await page.evaluate(() => {
const backdrop = document.getElementById('hypertwist-auth-shell-backdrop')
const shell = document.querySelector('.auth-shell')
if (!(backdrop instanceof HTMLElement) || !(shell instanceof HTMLElement)) {
return null
}
const backdropStyle = window.getComputedStyle(backdrop)
const shellStyle = window.getComputedStyle(shell)
return {
backdropPointerEvents: backdropStyle.pointerEvents,
backdropZIndex: backdropStyle.zIndex,
shellIsolation: shellStyle.isolation,
shellPosition: shellStyle.position,
shellZIndex: shellStyle.zIndex,
}
})
expect(stacking).toEqual({
backdropPointerEvents: 'none',
backdropZIndex: '0',
shellIsolation: 'isolate',
shellPosition: 'relative',
shellZIndex: '1',
})
}
test.describe('responsive public routes (mobile)', () => {
test.use({ viewport: { width: 390, height: 844 } })
for (const route of responsivePublicRoutes) {
test(`${route.path} renders without horizontal overflow`, async ({ page }) => {
await assertResponsivePublicRoute(page, route)
})
}
})
test.describe('responsive public routes (tablet)', () => {
test.use({ viewport: { width: 820, height: 1180 } })
for (const route of responsivePublicRoutes) {
test(`${route.path} renders without horizontal overflow`, async ({ page }) => {
await assertResponsivePublicRoute(page, route)
})
}
})