Files
2026-07-13 13:12:33 +08:00

86 lines
4.1 KiB
TypeScript

import { test, expect, type Page } from '@playwright/test'
// Desktop-shell emulation: the SPA detects the platform from the injected
// bridge object, and the CLI invocation prefix comes from the same bridge.
// The prefix mirrors the shape the Electron main process reports (env pair +
// quoted bundled binary path).
const PREFIX =
"OPENSQUILLA_STATE_DIR='/tmp/e2e desk/state' "
+ "OPENSQUILLA_GATEWAY_CONFIG_PATH='/tmp/e2e desk/config.toml' "
+ "'/Applications/OpenSquilla.app/Contents/Resources/runtime/gateway/opensquilla-gateway/opensquilla-gateway'"
async function installDesktopBridge(page: Page) {
await page.addInitScript((prefix: string) => {
const w = window as unknown as Record<string, unknown>
w.opensquillaDesktop = {
getOsLocale: async () => 'en-US',
isAutoUpdateEnabled: async () => false,
getGatewayStatus: async () => ({ url: '', port: 0, owned: true, status: 'ready', logPath: '' }),
getCliInvocation: async () => ({ mode: 'bundled', prefix }),
revealGatewayLog: async () => true,
getDesktopSettings: async () => ({}),
saveDesktopSettings: async () => ({}),
resetDesktopSettings: async () => ({ ok: true }),
setNativeTheme: async () => undefined,
openArtifact: async () => ({ ok: true }),
getOnboardingDefaults: async () => ({}),
saveOnboarding: async () => ({}),
cancelOnboarding: async () => ({}),
getBootState: async () => ({}),
retryStartup: async () => ({}),
quitApp: async () => ({}),
onBootStatus: () => () => {},
onBootError: () => () => {},
}
}, PREFIX)
}
test.describe('desktop shell CLI invocation', () => {
test('folds health-card commands and rewrites them to the bundled CLI', async ({ page }) => {
await installDesktopBridge(page)
await page.goto('/control/overview')
// The first doctor pass on a cold gateway can take a while, hence the
// generous wait for the first rendered finding card.
await page.waitForSelector('.health-finding', { timeout: 45000 })
// Findings with CLI fix steps fold behind the advanced disclosure on
// desktop. A fully configured gateway may surface none — skip then
// rather than asserting against an uncontrolled doctor state.
const folds = page.locator('details.cli-fold')
test.skip(await folds.count() === 0, 'gateway reports no findings with CLI fix steps')
const firstFold = folds.first()
await firstFold.locator('summary').click()
await expect(firstFold.locator('.cli-fold__hint')).toBeVisible()
// Every opensquilla command inside the fold carries the paste-ready prefix.
const firstCommand = firstFold.locator('code').first()
await expect(firstCommand).toContainText("OPENSQUILLA_STATE_DIR='/tmp/e2e desk/state'")
await expect(firstCommand).toContainText('opensquilla-gateway')
// Gateway lifecycle commands are guidance on desktop, never a rewritten,
// runnable command that would fight the shell-supervised gateway.
await expect(page.locator('.health-step__command code', { hasText: 'gateway restart' })).toHaveCount(0)
})
test('hides the CLI handoff disclosure in settings', async ({ page }) => {
await installDesktopBridge(page)
await page.goto('/control/settings/connection')
const dialog = page.getByRole('dialog', { name: 'Settings' })
await expect(dialog).toBeVisible({ timeout: 15000 })
await expect(dialog.locator('.settings-banner')).toBeVisible({ timeout: 15000 })
await expect(dialog.getByRole('button', { name: 'CLI handoff' })).toHaveCount(0)
})
test('web keeps flat, unprefixed commands', async ({ page }) => {
await page.goto('/control/overview')
await page.waitForSelector('.health-finding', { timeout: 45000 })
await expect(page.locator('details.cli-fold')).toHaveCount(0)
const commands = page.locator('.health-step__command code').filter({ hasText: 'opensquilla' })
test.skip(await commands.count() === 0, 'gateway reports no findings with CLI fix steps')
const command = commands.first()
await expect(command).toContainText(/^opensquilla /)
await expect(command).not.toContainText('OPENSQUILLA_STATE_DIR=')
})
})