mirror of
https://github.com/stablyai/orca.git
synced 2026-11-13 09:27:29 +00:00
154 lines
5.9 KiB
TypeScript
154 lines
5.9 KiB
TypeScript
// Cover Add all import versus Settings re-adoption (P5/P6/P7/P9); picker host selection lives in ssh-config-host-picker.spec.ts.
|
||
|
||
import type { ElectronApplication, Page } from '@stablyai/playwright-test'
|
||
import { expect, test } from './helpers/orca-app'
|
||
import { waitForSessionReady } from './helpers/store'
|
||
import {
|
||
buildSshConfigBody,
|
||
configHostRow,
|
||
expectSshHostAbsentFromSettings,
|
||
expectSshHostListedInSettings,
|
||
makeSshConfigHostPrefix,
|
||
openSshConfigHostPicker,
|
||
openSshHostSettings,
|
||
removeSshTargetByAlias,
|
||
removeSshTargetsByPrefix,
|
||
returnToAppShell,
|
||
seedIsolatedSshConfig,
|
||
type SeededSshConfigHost
|
||
} from './helpers/ssh-config-host-picker'
|
||
|
||
test.use({ seedTestRepo: false })
|
||
|
||
// Use unique cleanup prefixes so workers loaded in the same millisecond cannot delete each other’s targets.
|
||
const HOST_PREFIX = makeSshConfigHostPrefix()
|
||
|
||
function pairHosts(prefix: string): { alpha: SeededSshConfigHost; bravo: SeededSshConfigHost } {
|
||
return {
|
||
alpha: {
|
||
alias: `${prefix}-alpha`,
|
||
hostname: `${prefix}-alpha.example.test`,
|
||
user: 'deploy',
|
||
port: 22
|
||
},
|
||
bravo: {
|
||
alias: `${prefix}-bravo`,
|
||
hostname: `${prefix}-bravo.example.test`,
|
||
user: 'ops',
|
||
port: 2222
|
||
}
|
||
}
|
||
}
|
||
|
||
async function seedPairConfig(
|
||
electronApp: ElectronApplication,
|
||
prefix: string
|
||
): Promise<{ alpha: SeededSshConfigHost; bravo: SeededSshConfigHost }> {
|
||
const hosts = pairHosts(prefix)
|
||
await seedIsolatedSshConfig(electronApp, buildSshConfigBody([hosts.alpha, hosts.bravo]))
|
||
return hosts
|
||
}
|
||
|
||
/** Import both config hosts via picker, then suppress `alias` (removeTarget tombstone). */
|
||
async function importPairThenDeleteAlias(
|
||
page: Page,
|
||
electronApp: ElectronApplication,
|
||
prefix: string,
|
||
aliasToDelete: string
|
||
): Promise<{ alpha: SeededSshConfigHost; bravo: SeededSshConfigHost }> {
|
||
const hosts = await seedPairConfig(electronApp, prefix)
|
||
const picker = await openSshConfigHostPicker(page)
|
||
await expect(picker.getByRole('button', { name: 'Add all 2 to Orca' })).toBeEnabled()
|
||
await picker.getByRole('button', { name: 'Add all 2 to Orca' }).click()
|
||
await expect(page.getByText('Added 2 hosts to Orca.')).toBeVisible({ timeout: 15_000 })
|
||
await expect(page.getByRole('dialog', { name: 'Choose from ~/.ssh/config' })).toBeHidden({
|
||
timeout: 10_000
|
||
})
|
||
await expect(page.getByRole('dialog', { name: 'Add SSH host' })).toBeHidden({
|
||
timeout: 10_000
|
||
})
|
||
await removeSshTargetByAlias(page, aliasToDelete)
|
||
return hosts
|
||
}
|
||
|
||
test.describe('SSH config host import (bulk + settings re-adopt)', () => {
|
||
test.beforeEach(async ({ orcaPage }) => {
|
||
await waitForSessionReady(orcaPage)
|
||
})
|
||
|
||
test.afterEach(async ({ orcaPage }) => {
|
||
await removeSshTargetsByPrefix(orcaPage, HOST_PREFIX).catch(() => undefined)
|
||
})
|
||
|
||
test('P6: Add all N to Orca imports new hosts; re-open shows all in Orca', async ({
|
||
electronApp,
|
||
orcaPage
|
||
}) => {
|
||
const hosts = await seedPairConfig(electronApp, HOST_PREFIX)
|
||
const picker = await openSshConfigHostPicker(orcaPage)
|
||
|
||
await expect(configHostRow(picker, hosts.alpha)).toBeVisible()
|
||
await expect(configHostRow(picker, hosts.bravo)).toBeVisible()
|
||
await expect(picker.getByRole('button', { name: 'Add all 2 to Orca' })).toBeEnabled()
|
||
|
||
await picker.getByRole('button', { name: 'Add all 2 to Orca' }).click()
|
||
await expect(orcaPage.getByText('Added 2 hosts to Orca.')).toBeVisible({ timeout: 15_000 })
|
||
await expect(orcaPage.getByRole('dialog', { name: 'Choose from ~/.ssh/config' })).toBeHidden({
|
||
timeout: 10_000
|
||
})
|
||
await expect(orcaPage.getByRole('dialog', { name: 'Add SSH host' })).toBeHidden({
|
||
timeout: 10_000
|
||
})
|
||
|
||
const sshSection = await openSshHostSettings(orcaPage)
|
||
await expectSshHostListedInSettings(sshSection, hosts.alpha)
|
||
await expectSshHostListedInSettings(sshSection, hosts.bravo)
|
||
|
||
await returnToAppShell(orcaPage)
|
||
const reopened = await openSshConfigHostPicker(orcaPage)
|
||
await expect(configHostRow(reopened, hosts.alpha)).toBeDisabled()
|
||
await expect(
|
||
configHostRow(reopened, hosts.alpha).getByText('In Orca', { exact: true })
|
||
).toBeVisible()
|
||
await expect(configHostRow(reopened, hosts.bravo)).toBeDisabled()
|
||
await expect(
|
||
configHostRow(reopened, hosts.bravo).getByText('In Orca', { exact: true })
|
||
).toBeVisible()
|
||
await expect(reopened.getByRole('button', { name: 'No new hosts to add' })).toBeDisabled()
|
||
})
|
||
|
||
test('P9: Sync keeps deleted config hosts; Restore removed hosts re-adopts them', async ({
|
||
electronApp,
|
||
orcaPage
|
||
}) => {
|
||
const hosts = await importPairThenDeleteAlias(
|
||
orcaPage,
|
||
electronApp,
|
||
HOST_PREFIX,
|
||
`${HOST_PREFIX}-alpha`
|
||
)
|
||
|
||
const sshSection = await openSshHostSettings(orcaPage)
|
||
await expectSshHostListedInSettings(sshSection, hosts.bravo)
|
||
await expectSshHostAbsentFromSettings(sshSection, hosts.alpha)
|
||
|
||
// Sync never lifts a removal, so bulk removal sticks.
|
||
await sshSection.getByRole('button', { name: 'Sync ~/.ssh/config' }).click()
|
||
await expect(orcaPage.getByText(/already in sync|Synced \d+ servers?/i).first()).toBeVisible({
|
||
timeout: 15_000
|
||
})
|
||
await expectSshHostAbsentFromSettings(sshSection, hosts.alpha)
|
||
|
||
await sshSection.getByRole('button', { name: 'More SSH host actions' }).click()
|
||
// The label carries the removed count once ~/.ssh/config is read; click waits for it to enable.
|
||
await orcaPage.getByRole('menuitem', { name: /^Restore removed hosts \(\d+\)…$/ }).click()
|
||
const restoreDialog = orcaPage.getByRole('dialog', { name: 'Restore removed hosts?' })
|
||
await expect(restoreDialog.getByText(hosts.alpha.alias)).toBeVisible({ timeout: 15_000 })
|
||
await restoreDialog.getByRole('button', { name: 'Restore' }).click()
|
||
await expect(orcaPage.getByText(/Synced \d+ servers?/i)).toBeVisible({ timeout: 15_000 })
|
||
|
||
await expectSshHostListedInSettings(sshSection, hosts.alpha)
|
||
await expectSshHostListedInSettings(sshSection, hosts.bravo)
|
||
})
|
||
})
|