desktop-hosts.spec.ts 5.9 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586
  1. import { test, expect } from '@playwright/test'
  2. test('registers a computer, downloads its private config and disables it', async ({ page }, testInfo) => {
  3. await page.goto('/conversations')
  4. await page.getByRole('textbox', { name: '账号', exact: true }).fill('fixture')
  5. await page.getByRole('textbox', { name: '密码', exact: true }).fill('fixture-pass')
  6. await page.getByRole('button', { name: '登录', exact: true }).click()
  7. await page.locator('.desktop-sidebar .sidebar-account-switcher__main').click()
  8. await page.getByRole('menuitem', { name: '我的设置', exact: true }).click()
  9. const dialog = page.getByRole('dialog', { name: '我的设置' })
  10. await dialog.getByRole('button', { name: 'Hermes 连接', exact: true }).click()
  11. await dialog.locator('details.desktop-host-settings summary').click()
  12. const panel = dialog.getByRole('region', { name: '电脑设置' })
  13. await expect(panel).toContainText('尚未注册电脑')
  14. await panel.getByRole('textbox', { name: '电脑名称', exact: true }).fill('书房 iMac')
  15. await page.screenshot({ path: testInfo.outputPath('desktop-host-registration.png') })
  16. await panel.getByRole('button', { name: '注册电脑', exact: true }).click()
  17. await expect(panel).toContainText('待连接')
  18. const downloaded = page.waitForEvent('download')
  19. await panel.getByRole('button', { name: '下载电脑配置', exact: true }).click()
  20. const download = await downloaded
  21. expect(download.suggestedFilename()).toBe('desktop-host.json')
  22. const stream = await download.createReadStream(); const chunks: Buffer[] = []
  23. for await (const chunk of stream!) chunks.push(Buffer.from(chunk))
  24. const configuration = JSON.parse(Buffer.concat(chunks).toString())
  25. expect(configuration).toMatchObject({ protocol: 1, serverURL: expect.stringMatching(/^https?:\/\//) })
  26. expect(configuration.hostId).toMatch(/^[0-9a-f-]{36}$/)
  27. expect(configuration.token.length).toBeGreaterThan(32)
  28. const result = await (await page.request.get('/api/app/admin/desktop-hosts')).json()
  29. expect(JSON.stringify(result)).not.toContain(configuration.token)
  30. expect(JSON.stringify(result)).not.toContain('tokenHash')
  31. await page.setViewportSize({ width: 390, height: 844 })
  32. await panel.getByRole('button', { name: '停用 书房 iMac' }).scrollIntoViewIfNeeded()
  33. await page.screenshot({ path: testInfo.outputPath('desktop-host-registered-mobile.png') })
  34. await panel.getByRole('button', { name: '停用 书房 iMac' }).click()
  35. await expect(panel).toContainText('已停用')
  36. expect((await (await page.request.get('/api/app/admin/desktop-hosts')).json()).hosts.find((h: any) => h.id === configuration.hostId).enabled).toBe(false)
  37. })
  38. test('shows other device status only in Bot settings', async ({ page }, testInfo) => {
  39. await page.goto('/conversations')
  40. await page.getByRole('textbox', { name: '账号', exact: true }).fill('fixture')
  41. await page.getByRole('textbox', { name: '密码', exact: true }).fill('fixture-pass')
  42. await page.getByRole('button', { name: '登录', exact: true }).click()
  43. await page.locator('.desktop-sidebar .sidebar-account-switcher__main').click()
  44. await page.getByRole('menuitem', { name: '我的设置', exact: true }).click()
  45. const dialog = page.getByRole('dialog', { name: '我的设置' })
  46. await dialog.getByRole('button', { name: 'Hermes 连接', exact: true }).click()
  47. await dialog.locator('details.desktop-host-settings summary').click()
  48. const panel = dialog.getByRole('region', { name: '电脑设置' })
  49. await panel.getByRole('textbox', { name: '电脑名称', exact: true }).fill('客厅 Mac mini')
  50. await panel.getByRole('button', { name: '注册电脑', exact: true }).click()
  51. await expect(panel).toContainText('待连接')
  52. const downloaded = page.waitForEvent('download')
  53. await panel.getByRole('button', { name: '下载电脑配置', exact: true }).click()
  54. const stream = await (await downloaded).createReadStream(); const chunks: Buffer[] = []
  55. for await (const chunk of stream!) chunks.push(Buffer.from(chunk))
  56. const configuration = JSON.parse(Buffer.concat(chunks).toString())
  57. const hostInfo = { id: crypto.randomUUID(), name: '客厅 Mac mini', platform: 'darwin', screen: true, accessibility: true, approved: [] }
  58. const exchange = () => page.request.post(`/api/desktop-host/v1/${configuration.hostId}/exchange`, {
  59. headers: { Authorization: `Bearer ${configuration.token}`, 'x-desktop-host-protocol': '1' },
  60. data: { host: hostInfo, results: [] },
  61. })
  62. expect((await (await exchange()).json()).commands).toEqual([])
  63. const seed = await (await page.request.post('/__test/computer?off=1', { data: {} })).json()
  64. await page.goto(`/conversations/${seed.conversationId}`)
  65. await page.getByRole('button', { name: '电脑与定时任务', exact: true }).click()
  66. const dock = page.getByRole('complementary', { name: '机器人电脑面板' })
  67. await expect(dock.locator('.env-check')).toHaveCount(0)
  68. await expect(dock.getByRole('combobox', { name: '操作的电脑', exact: true })).toHaveCount(0)
  69. await expect(dock.locator('.host-permission')).toHaveCount(0)
  70. await page.locator('.desktop-sidebar').getByRole('button',{name:'工具',exact:true}).click()
  71. await page.getByRole('menuitem',{name:'Bot 设置',exact:true}).click()
  72. const settings=page.getByRole('dialog',{name:'Bot 设置',exact:true})
  73. await settings.getByRole('button',{name:'环境与授权',exact:true}).click()
  74. const hostCard=settings.locator('.device-authorization article',{hasText:'客厅 Mac mini'})
  75. await expect(hostCard).toBeVisible()
  76. await expect(hostCard).toContainText('在线')
  77. await expect(hostCard.locator('button')).toHaveCount(0)
  78. await hostCard.scrollIntoViewIfNeeded()
  79. await page.screenshot({path:testInfo.outputPath('desktop-host-settings-status.png')})
  80. const agents = (await (await page.request.get('/api/app/agents')).json()).agents
  81. const updated = agents.find((a: any) => a.id === seed.agentId)
  82. expect(updated).toMatchObject({ envs: { vm: true, desktop: true } })
  83. expect(updated.desktopHost).toBeUndefined()
  84. })