Files
hanzo.ai/e2e/gates/sidebar.spec.ts
fbc926f525 The app is @hanzo/rooms 0.1.55's App, at paths under /chat and /dev, behind the organization gate
_web.tsx draws rooms' App inside rooms' `Orgs`, as every room is: a reader
with no organization makes one, one with several picks one, and a team on Free
is asked for the Team plan before the app is drawn; a personal organization on
Free opens it. The app reads its place from the path: /chat and /chat/<id> are
Chat, a path under /dev is Dev. /?chat=<id> and /chat?thread=<id> move to
/chat/<id>, /?at= to /dev?at=, whose place the door replaces with its path, as
it does the builder's grammar rooms 0.1.35-0.1.38 wrote under /dev.

The gates read the app at its paths and the rooms' shell at /home, with new
Linux baselines for it; the limit banner, the model chip and the side panel
are held to what rooms 0.1.55 draws; the landing's budget is 445 KB, since
rooms' lib/host carries @hanzo/build's route grammar. app/gui.css is what the
build writes.


Co-authored-by: Hanzo Dev <[email protected]>
2026-10-16 15:05:24 -07:00

136 lines
6.0 KiB
TypeScript

import { expect, test, type Page } from '@playwright/test'
import { serveExport } from './export'
import { rail } from './rail'
import { answer, signIn } from '../session'
/**
* THE COLUMN'S FILTER NARROWS THE COLUMN, AND A SHARED LINK SHOWS NO API ERROR.
*
* The filter used to reach the chats and the rooms and nothing else: with no
* chats, typing changed nothing on screen, and the two folders under it listed
* every row whatever was typed. It now narrows the places, the lists, and the
* folders — a folder with matches opens on them, one with none is not drawn —
* and Escape clears it.
*
* /referral read `/v1/user/<id>/referrers`, a route the API never served, and
* printed "API error 404" to everybody who pressed Share Hanzo. It reads cloud's
* `/v1/referral` now, and the `?ref=` a friend arrives with is claimed quietly
* once they are signed in, whatever the answer.
*/
let url: string
let stop: () => Promise<void>
test.beforeAll(async () => {
const served = await serveExport()
url = served.url
stop = served.close
})
test.afterAll(async () => stop())
/** A signed-in reader with no chats, projects or rooms. */
async function reader(page: Page): Promise<void> {
await signIn(page)
await answer(page, '/v1/billing/balance', { available: 0 })
await answer(page, '/v1/agents', { agents: [] })
await answer(page, '/v1/agents/chat/conversations', { conversations: [] })
await answer(page, '/v1/agents/sessions', { sessions: [] })
await answer(page, '/v1/projects', [])
await answer(page, '/v1/team/rooms', { rooms: [] })
await answer(page, '/v1/channels/inbox', { items: [] })
}
test('the filter narrows the places, the lists and the folders, and Escape clears it', async ({ page }) => {
await reader(page)
await page.setViewportSize({ width: 1440, height: 900 })
await page.goto(`${url}/home`)
await rail(page, '[data-slot="list"]')
const box = page.locator('input[aria-label="Filter sidebar"]')
const places = page.locator('[data-slot="places-list"]')
const row = (name: string) => page.getByRole('button', { name, exact: true })
const folder = (name: string) => page.locator('[role="button"][aria-expanded]', { hasText: name })
await box.fill('stor')
await expect(places.getByRole('button')).toHaveCount(0)
await expect(folder('Cloud & Platform')).toHaveAttribute('aria-expanded', 'true')
await expect(row('S3 Object Storage')).toBeVisible()
await expect(row('Datastore')).toBeVisible()
await expect(row('Compute & VMs')).toHaveCount(0)
await expect(row('Settings')).toHaveCount(0)
await expect(page.getByText('No chat matches “stor”.')).toBeVisible()
await box.fill('settings')
await expect(folder('Cloud & Platform')).toHaveCount(0)
await expect(row('Settings')).toBeVisible()
await box.fill('dev')
await expect(places.getByRole('button', { name: 'Dev', exact: true })).toBeVisible()
await expect(places.getByRole('button', { name: 'Chat', exact: true })).toHaveCount(0)
await box.press('Escape')
await expect(box).toHaveValue('')
await expect(places.getByRole('button', { name: 'Chat', exact: true })).toBeVisible()
await expect(folder('Cloud & Platform')).toHaveAttribute('aria-expanded', 'false')
await expect(row('Settings')).toBeVisible()
})
test('the filter over settings says when nothing matches', async ({ page }) => {
await reader(page)
await page.setViewportSize({ width: 1440, height: 900 })
await page.goto(`${url}/home`)
await rail(page, '[data-slot="list"]')
await page.getByRole('button', { name: 'Settings', exact: true }).first().click()
const box = page.locator('input[aria-label="Filter sidebar"]')
await box.fill('bill')
await expect(page.getByRole('button', { name: 'Billing', exact: true })).toBeVisible()
await box.fill('zzzz')
await expect(page.getByText('No matches for “zzzz”.')).toBeVisible()
})
test('Share Hanzo reads the referral service, and no API error reaches the page', async ({ page }) => {
await reader(page)
const asked: string[] = []
page.on('request', (r) => asked.push(new URL(r.url()).pathname))
await answer(page, '/v1/referral', {
code: 'K7Q2ZP',
link: 'https://hanzo.ai/?ref=K7Q2ZP',
counts: { total: 3, signup: 2, qualified: 1 },
referrals: [{ id: 'r1', referee: 'acme', status: 'qualified', createdAt: 1790000000, qualifiedAt: 1790100000 }],
})
await page.setViewportSize({ width: 1440, height: 900 })
await page.goto(`${url}/referral`)
await expect(page.locator('input[value="https://hanzo.ai/?ref=K7Q2ZP"]')).toBeVisible()
await expect(page.getByText('Using Hanzo').first()).toBeVisible()
await expect(page.getByText('acme')).toBeVisible()
await expect(page.getByText(/API error|404/)).toHaveCount(0)
expect(asked.filter((p) => p.startsWith('/v1/user/') || p.startsWith('/v1/referrer'))).toEqual([])
})
test('a referral service that cannot answer is said in words, never as a status code', async ({ page }) => {
await reader(page)
await page.route(
(u) => u.pathname === '/v1/referral',
(route) => route.fulfill({ status: 404, contentType: 'application/json', body: '{"error":"not found"}' }),
)
await page.goto(`${url}/referral`)
await expect(page.getByText('Your referral link could not be loaded right now. Try again in a moment.')).toBeVisible()
await expect(page.getByText(/API error|404/)).toHaveCount(0)
})
test('a friend who follows the link is credited once signed in, and sees nothing of it', async ({ page }) => {
await reader(page)
const claims: unknown[] = []
await page.route(
(u) => u.pathname === '/v1/referral/claim',
(route) => {
claims.push(route.request().postDataJSON())
// An unknown code is a final answer too: dropped, and never shown.
return route.fulfill({ status: 404, contentType: 'application/json', body: '{"error":"unknown code"}' })
},
)
await page.goto(`${url}/chat?ref=K7Q2ZP`)
await expect.poll(() => claims).toEqual([{ code: 'K7Q2ZP' }])
await expect.poll(() => page.evaluate(() => localStorage.getItem('hz_ref'))).toBeNull()
await expect(page.getByText(/API error|404|unknown code/)).toHaveCount(0)
})