mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-07-24 16:54:43 +00:00
88 lines
2.6 KiB
TypeScript
88 lines
2.6 KiB
TypeScript
import { expect, test } from '@playwright/test'
|
|
|
|
import {
|
|
PACKAGED_BINARY_PATH,
|
|
type PackagedAppFixture,
|
|
packagedBinaryExists,
|
|
setupPackagedApp,
|
|
} from './fixtures'
|
|
import { expectVisualSnapshot } from './visual-snapshot'
|
|
|
|
/**
|
|
* E2E smoke tests for the packaged Hermes desktop app.
|
|
*
|
|
* Launches the real packaged Electron binary (produced by `npm run pack` →
|
|
* `electron-builder --dir`) with BOOT_FAKE=1 and full sandbox isolation
|
|
* (credential stripping, isolated HERMES_HOME + userData, unique app name).
|
|
*
|
|
* Skips if the packaged binary doesn't exist — run `npm run pack` first.
|
|
*/
|
|
|
|
let fixture: PackagedAppFixture | null = null
|
|
|
|
test.beforeAll(async () => {
|
|
test.skip(
|
|
!packagedBinaryExists(),
|
|
`Built app binary not found: ${PACKAGED_BINARY_PATH}. Run 'npm run pack' first.`,
|
|
)
|
|
|
|
fixture = await setupPackagedApp()
|
|
})
|
|
|
|
test.afterAll(async () => {
|
|
await fixture?.cleanup()
|
|
fixture = null
|
|
})
|
|
|
|
test('window opens with the Hermes title', async () => {
|
|
const title = await fixture!.page.title()
|
|
expect(title).toContain('Hermes')
|
|
})
|
|
|
|
test('renderer loads and shows DOM content', async () => {
|
|
const page = fixture!.page
|
|
await page.waitForSelector('#root', { state: 'attached', timeout: 30_000 })
|
|
const childCount = await page.locator('#root > *').count()
|
|
expect(childCount).toBeGreaterThan(0)
|
|
})
|
|
|
|
test('boot progress overlay fades out or shows error state', async () => {
|
|
const page = fixture!.page
|
|
await page.waitForFunction(
|
|
() => {
|
|
const root = document.getElementById('root')
|
|
|
|
if (!root) {
|
|
return false
|
|
}
|
|
|
|
const text = root.textContent ?? ''
|
|
|
|
// Error path: boot failure overlay renders an error message.
|
|
if (text.includes('error') || text.includes('Error') || text.includes('failed')) {
|
|
return true
|
|
}
|
|
|
|
// Success path: overlay disappears and the app renders. If there's
|
|
// no "boot" / "starting" / "installing" text visible, boot has
|
|
// completed (either to the main UI or to onboarding).
|
|
const bootIndicators = ['starting', 'resolving', 'spawning', 'waiting', 'installing']
|
|
const lower = text.toLowerCase()
|
|
|
|
return !bootIndicators.some((word) => lower.includes(word))
|
|
},
|
|
undefined,
|
|
{ timeout: 60_000 },
|
|
)
|
|
})
|
|
|
|
test('can capture a screenshot for the CI artifact', async () => {
|
|
if (!fixture) {
|
|
test.skip(true, 'Previous test failed — no app running')
|
|
|
|
return
|
|
}
|
|
|
|
// Visual snapshot — won't fail on diff, just logs + generates diff image
|
|
await expectVisualSnapshot(fixture!.page, { name: 'packaged-app-booted', timeout: 10_000, app: fixture!.app })
|
|
})
|