| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293 |
- import { test } from 'node:test'
- import assert from 'node:assert/strict'
- import { mkdtemp, mkdir, writeFile, rm } from 'node:fs/promises'
- import { createServer } from 'node:net'
- import { spawn } from 'node:child_process'
- import { tmpdir } from 'node:os'
- import { join, resolve } from 'node:path'
- import { _electron as electron, expect } from '@playwright/test'
- async function freePort() {
- const server = createServer()
- await new Promise(done => server.listen(0, '127.0.0.1', done))
- const port = server.address().port
- await new Promise(done => server.close(done))
- return port
- }
- test('the real desktop workspace downloads in place and waits for an explicit restart', { timeout: 60000 }, async () => {
- const root = resolve(import.meta.dirname, '..'), home = await mkdtemp(join(tmpdir(), 'yaoyao-inline-update-'))
- const port = await freePort(), upstream = await freePort(), origin = `http://127.0.0.1:${port}`
- await mkdir(join(home, 'server'))
- const server = spawn(process.execPath, ['--import', 'tsx', 'tests/fixtures/workspace-server.ts'], {
- cwd: root, env: { ...process.env, WORKSPACE_FIXTURE_HOME: join(home, 'server'), WORKSPACE_FIXTURE_PORT: String(port), WORKSPACE_FIXTURE_UPSTREAM_PORT: String(upstream) }, stdio: 'ignore',
- })
- const desktopHome = join(home, 'desktop'); await mkdir(desktopHome)
- await writeFile(join(desktopHome, 'desktop-preferences.json'), JSON.stringify({ startupChoice: 'remote', remoteServer: origin }))
- let app
- try {
- await expect.poll(async () => { try { return (await fetch(origin + '/healthz')).status } catch { return 0 } }, { timeout: 30000 }).toBe(200)
- app = await electron.launch({ args: [root], cwd: root, env: { ...process.env, HERMES_YAOYAO_DESKTOP_CLIENT_ONLY: '1', HERMES_YAOYAO_DESKTOP_TEST_HOME: desktopHome, HERMES_YAOYAO_DESKTOP_TEST_AUTO_UPDATE: '1' } })
- const page = await app.firstWindow()
- await app.evaluate(({ app }, root) => {
- const { createRequire } = process.getBuiltinModule('node:module')
- const { autoUpdater } = createRequire(root + '/package.json')(root + '/.desktop-build-client/electron-updater.cjs')
- globalThis.inlineFixture = { installs: 0 }
- autoUpdater.checkForUpdates = async () => ({ isUpdateAvailable: true, updateInfo: { version: '99.0.0' } })
- autoUpdater.downloadUpdate = () => new Promise(resolve => {
- inlineFixture.ready = () => resolve([])
- inlineFixture.stage = () => autoUpdater.emit('update-downloaded')
- autoUpdater.emit('download-progress', { transferred: 37, total: 100 })
- })
- autoUpdater.quitAndInstall = () => { inlineFixture.installs++ }
- }, root)
- await expect.poll(() => page.evaluate(() => window.yaoyaoDesktop.status().then(state => state.phase))).toBe('ready')
- await page.reload()
- await page.locator('#username').fill('fixture')
- await page.locator('#password').fill('fixture-pass')
- await page.locator('#submit').click()
- await page.waitForURL(origin + '/**')
- await page.goto(origin + '/conversations')
- await expect(page.locator('.desktop-sidebar .sidebar-account-switcher__main')).toBeVisible()
- await page.evaluate(() => window.yaoyaoDesktop.updateAction('check'))
- const footer = page.locator('.desktop-sidebar .desktop-update-entry')
- await expect(footer.getByRole('button', { name: '可更新', exact: true })).toBeVisible()
- await expect(page.locator('#desktop-update-entry')).toHaveCount(0)
- assert.equal(app.windows().length, 1)
- const output = join(root, 'test-results/desktop/inline-workspace'); await mkdir(output, { recursive: true })
- await page.screenshot({ path: join(output, 'available.png') })
- await footer.getByRole('button', { name: '可更新', exact: true }).click()
- await expect(footer.getByRole('progressbar')).toHaveAttribute('aria-valuenow', '37')
- await page.locator('.desktop-sidebar .sidebar-account-switcher__main').click()
- const menu = page.locator('.workspace-settings-menu .desktop-update-entry')
- await expect(menu).toContainText('正在下载 · 37%')
- await page.screenshot({ path: join(output, 'downloading-menu.png') })
- await page.keyboard.press('Escape')
- await expect(menu).toHaveCount(0)
- await app.evaluate(() => inlineFixture.stage())
- await expect(footer).toContainText('正在准备…')
- await page.reload()
- await expect(footer).toContainText('正在准备…')
- await expect(footer.getByRole('button')).toBeDisabled()
- await app.evaluate(() => inlineFixture.ready())
- await expect(footer.getByRole('button', { name: '重新启动', exact: true })).toBeEnabled()
- assert.equal(await app.evaluate(() => inlineFixture.installs), 0)
- assert.equal(app.windows().length, 1)
- await page.screenshot({ path: join(output, 'ready.png') })
- await page.evaluate(() => document.documentElement.classList.add('dark'))
- await page.screenshot({ path: join(output, 'ready-dark.png') })
- await footer.getByRole('button', { name: '重新启动', exact: true }).click()
- await expect.poll(() => app.evaluate(() => inlineFixture.installs)).toBe(1)
- await expect(footer.getByRole('button', { name: '正在重启…', exact: true })).toBeDisabled()
- assert.equal((await fetch(origin + '/healthz')).status, 200)
- } finally {
- await app?.close().catch(() => {})
- server.kill('SIGTERM')
- await new Promise(done => {
- if (server.exitCode !== null) return done()
- const timer = setTimeout(() => { server.kill('SIGKILL'); done() }, 3000)
- server.once('exit', () => { clearTimeout(timer); done() })
- })
- await rm(home, { recursive: true, force: true })
- }
- })
|