mirror of
https://github.com/hanzo-apps/hanzo.ai.git
synced 2026-10-29 07:20:43 +00:00
76 lines
3.0 KiB
TypeScript
76 lines
3.0 KiB
TypeScript
import { test, expect } from '@playwright/test'
|
||
import { serveExport } from './export'
|
||
import { signIn } from '../session'
|
||
|
||
/**
|
||
* THE FACE STANDS ABOVE THE NAME.
|
||
*
|
||
* A room is opened from a face in the column, so the face is what the reader is
|
||
* holding in mind when they arrive; the name alone makes them check they landed
|
||
* on the right one.
|
||
*
|
||
* It measures the AGENT'S OWN picture rather than a cast likeness. `Face` casts
|
||
* from the name and falls back to initials when the cast has no part for it, so
|
||
* a row named for its job — "Hanzo Researcher" — drew two letters here while the
|
||
* column beside it drew the memoji. Passing the record's own avatar is what
|
||
* makes the two agree, and this asserts the picture, not merely an element.
|
||
*/
|
||
const AGENT = {
|
||
id: 'a1',
|
||
name: 'Einstein',
|
||
description: 'Exact about what a rule says and whom it binds.',
|
||
avatar: '/agents/einstein.png',
|
||
model: 'enso',
|
||
}
|
||
|
||
test('the agent’s own face is drawn above its name', async ({ page }) => {
|
||
await signIn(page)
|
||
const site = await serveExport()
|
||
try {
|
||
await page.route('**/v1/agents**', (route) =>
|
||
route.fulfill({
|
||
status: 200,
|
||
contentType: 'application/json',
|
||
headers: { 'access-control-allow-origin': '*' },
|
||
body: JSON.stringify(
|
||
/\/agents\/[^?]/.test(route.request().url())
|
||
? { ...AGENT, instructions: '' }
|
||
: { data: [AGENT] },
|
||
),
|
||
}),
|
||
)
|
||
await page.setViewportSize({ width: 1440, height: 950 })
|
||
// `agent` is how the room is addressed — components/workspace/open.ts reads
|
||
// it off the query, which is what the column's own press writes.
|
||
await page.goto(`${site.url}/chat?agent=Einstein`, { waitUntil: 'load' })
|
||
|
||
const name = page.getByRole('heading', { name: 'Einstein', level: 1 })
|
||
await expect(name).toBeVisible()
|
||
|
||
// The portrait the record names, at a size the hero uses rather than a row.
|
||
const drawn = page.locator('img[src="/agents/einstein.png"]')
|
||
await expect(drawn.first()).toBeVisible()
|
||
|
||
// The hero's, told from the column's by size — the column draws the same
|
||
// portrait small, so an element check alone would pass on the wrong one.
|
||
// The crew under the composer draws every agent at disc size, this one
|
||
// included; it is a door to the room, not the hero, so it is left out here.
|
||
const boxes = await drawn.evaluateAll((els) =>
|
||
els
|
||
.filter((e) => !e.closest('[data-slot="crew"]'))
|
||
.map((e) => {
|
||
const r = e.getBoundingClientRect()
|
||
return { y: r.y, bottom: r.bottom, width: r.width }
|
||
}),
|
||
)
|
||
const box = boxes.find((b) => b.width > 40)
|
||
expect(boxes.filter((b) => b.width > 40), 'exactly one face at hero size').toHaveLength(1)
|
||
const title = await name.boundingBox()
|
||
expect(box, 'a portrait drawn at hero size, not a row’s').toBeTruthy()
|
||
expect(title, 'the name has a box').toBeTruthy()
|
||
expect(box!.bottom, 'the face sits above the name').toBeLessThanOrEqual(title!.y + 1)
|
||
} finally {
|
||
await site.close()
|
||
}
|
||
})
|