hermes-agent/apps/desktop/e2e/onboarding.spec.ts
ethernet 0860ee4e5a feat(desktop/e2e): Playwright E2E suite with visual regression diffs
Adds a full desktop Playwright E2E suite that launches the Electron app
against a mock inference server, exercising the full boot chain:

  electron -> hermes serve -> mock provider -> renderer

Includes:
- Mock OpenAI-compatible inference server (mock-server.ts)
- Shared fixtures with sandbox isolation (credentials, HERMES_HOME,
  userData, fixed window-state.json for reproducible screenshots)
- Test specs: boot, boot-failure, onboarding, mock-backend-setup, chat,
  and packaged-app launch
- Visual regression: expectVisualSnapshot() wraps toHaveScreenshot in
  try/catch so diffs are reported without failing the test suite
- CI workflow: xvfb at 1280x1024, baseline cache from main
  (--update-snapshots on main, compare on PRs), step summary table with
  diff/actual/expected image links, dedicated visual-diffs artifact
- dev:mock script for local fake-provider development
- test:e2e:visual + test:e2e:update-snapshots scripts using cage
- .gitignore: *-snapshots/ (baselines cached in CI, not committed)
2026-07-20 11:44:40 -04:00

76 lines
2.2 KiB
TypeScript

/**
* E2E onboarding tests — verify the provider picker appears when no
* inference provider is configured.
*
* Launches the app with an empty config.yaml (no providers). The renderer
* should detect the unconfigured state and show the DesktopOnboardingOverlay
* with provider options / API key form.
*
* Prerequisite: `npm run build` must have been run so dist/ exists.
*/
import { expect, test } from '@playwright/test'
import {
type NoProviderFixture,
setupNoProvider,
waitForOnboarding,
} from './fixtures'
import { expectVisualSnapshot } from './visual-snapshot'
let fixture: NoProviderFixture | null = null
test.afterAll(async () => {
await fixture?.cleanup()
fixture = null
})
test.describe('onboarding with no provider configured', () => {
test('onboarding overlay appears on first boot', async () => {
fixture = await setupNoProvider()
// The app should boot (hermes serve starts fine even without a provider),
// but the renderer should show the onboarding overlay because no
// provider is configured.
await waitForOnboarding(fixture.page, 90_000)
})
test('onboarding shows provider options or API key form', async () => {
if (!fixture) {
test.skip(true, 'Previous test failed — no app running')
return
}
const page = fixture.page
// The onboarding overlay should contain provider-related text.
// It might show OAuth providers, an API key form, or a "choose later"
// link. Verify at least one of these is visible.
const rootText = await page.evaluate(() => {
const root = document.getElementById('root')
return root?.textContent ?? ''
})
const hasProviderText =
rootText.includes('provider') ||
rootText.includes('Provider') ||
rootText.includes('API key') ||
rootText.includes('Sign in') ||
rootText.includes('OpenRouter') ||
rootText.includes('OpenAI')
expect(hasProviderText).toBe(true)
})
test('screenshot of onboarding overlay', async () => {
if (!fixture) {
test.skip(true, 'Previous test failed — no app running')
return
}
await expectVisualSnapshot(fixture.page, { name: 'onboarding-overlay', app: fixture.app })
})
})