Files
hanzo.ai/e2e/gates/try.spec.ts
zeekay 6c65e3e941 @hanzo/app 0.2.0: the app SDK, renamed from @hanzo/rooms
Every import, the catalog pin and the docs name @hanzo/app and
github.com/hanzoai/app. lib/rooms.ts is lib/app.ts and
components/rooms.tsx is components/app.tsx.
2026-10-22 19:07:20 -07:00

58 lines
2.4 KiB
TypeScript

import { expect, test, type Page } from '@playwright/test'
import { serveExport } from './export'
import { signIn } from '../session'
/**
* /models' "Try it": a visitor who is not signed in is handed the thread, as
* /chat's own composer; a signed-in reader is sent to /chat instead, which
* stands behind the organization gate (app/_web.tsx), so no organization
* chats here that /chat would ask for its plan first.
*/
let base: string
let stop: () => Promise<void>
test.beforeAll(async () => {
const served = await serveExport()
base = served.url
stop = served.close
})
test.afterAll(async () => stop())
/** Every platform read answered empty: the section is measured, not the catalog. */
const quiet = (page: Page) =>
page.route(
(u) => u.pathname.startsWith('/v1/') && !u.pathname.startsWith('/v1/iam/') && !u.pathname.startsWith('/v1/billing/'),
(route) => route.fulfill({ json: {} }),
)
/**
* The thread's field, by its accessible name. The words in it are the composer's
* own ("Type / for skills", @hanzo/build `prompt`): @hanzo/app' `Ask` takes a
* `placeholder` and no longer draws it, and the name stays "Ask anything" so a
* reader's tools find it whatever it says. The site's own dock is "Ask Hanzo
* anything", another field.
*/
const field = (page: Page) => page.getByRole('textbox', { name: 'Ask anything', exact: true })
const open = (page: Page) => page.locator('[data-slot="try-open"]')
test('a visitor who is not signed in is handed the thread', async ({ page }) => {
await quiet(page)
await page.goto(`${base}/models`, { waitUntil: 'load' })
await expect(field(page)).toBeVisible({ timeout: 20_000 })
await expect(open(page)).toHaveCount(0)
})
test('a signed-in reader is sent to /chat, and handed no thread here', async ({ page }) => {
// A team on Free: /chat asks it for the Team plan, so nothing here may answer it first.
await signIn(page, { sub: 'acme', name: 'acme', email: '[email protected]', org: 'acme' })
await page.route(
(u) => u.pathname === '/v1/billing/tier',
(route) => route.fulfill({ json: { user: 'acme', tier: { name: 'free', displayName: 'Free' }, balance: { currency: 'usd', effectiveAvailable: 0 } } }),
)
await quiet(page)
await page.goto(`${base}/models`, { waitUntil: 'load' })
await expect(open(page)).toBeVisible({ timeout: 20_000 })
await expect(open(page).getByRole('link', { name: 'Open Hanzo Chat' })).toHaveAttribute('href', '/chat')
await expect(field(page)).toHaveCount(0)
})