174 lines
10 KiB
JavaScript
174 lines
10 KiB
JavaScript
import { expect, test } from '@playwright/test'
|
|
|
|
const runtime = {
|
|
id: 'container-a',
|
|
alias: 'account-a',
|
|
name: 'account-a',
|
|
state: 'running',
|
|
status: 'Up',
|
|
image_version: '148.0.0.1',
|
|
fingerprint: { seed: 1000 },
|
|
profile: 'creatorhub-profile-account-a',
|
|
endpoint: 'http://account-a:9222',
|
|
}
|
|
|
|
test('keeps the create form inside a 900px viewport', async ({ page }) => {
|
|
await page.route('**/api/browsers', route => route.fulfill({ json: [] }))
|
|
await page.route('**/api/gateways', route => route.fulfill({ json: [] }))
|
|
await page.route('**/api/browser-images', route => route.fulfill({ json: [] }))
|
|
await page.route('**/api/phase-a/accounts', route => route.fulfill({ json: [] }))
|
|
await page.route('**/api/network-exits', route => route.fulfill({ json: [] }))
|
|
await page.setViewportSize({ width: 900, height: 800 })
|
|
await page.goto('/#/browsers')
|
|
|
|
await expect(page.getByRole('button', { name: '收起导航' }).first()).toBeVisible()
|
|
const createButton = page.getByRole('button', { name: '创建环境' })
|
|
await expect(createButton).toBeVisible()
|
|
expect(await page.evaluate(() => document.documentElement.scrollWidth)).toBeLessThanOrEqual(900)
|
|
const box = await createButton.boundingBox()
|
|
expect(box).not.toBeNull()
|
|
expect(box.x + box.width).toBeLessThanOrEqual(900)
|
|
})
|
|
|
|
test('shows the CDP endpoint only in the active branch at 900px and 599px', async ({ page }) => {
|
|
await page.route('**/api/browsers', route => route.fulfill({ json: [runtime] }))
|
|
await page.route('**/api/gateways', route => route.fulfill({ json: [] }))
|
|
await page.route('**/api/browser-images', route => route.fulfill({ json: [] }))
|
|
await page.route('**/api/phase-a/accounts', route => route.fulfill({ json: [] }))
|
|
await page.route('**/api/network-exits', route => route.fulfill({ json: [] }))
|
|
const endpoint = page.getByText('http://account-a:9222')
|
|
|
|
await page.setViewportSize({ width: 900, height: 800 })
|
|
await page.goto('/#/browsers')
|
|
await expect(page.getByRole('cell', { name: 'http://account-a:9222' })).toBeVisible()
|
|
await expect(endpoint.filter({ visible: true })).toHaveCount(1)
|
|
|
|
await page.setViewportSize({ width: 599, height: 800 })
|
|
await expect(page.getByRole('cell', { name: 'http://account-a:9222' })).toBeHidden()
|
|
await expect(endpoint.filter({ visible: true })).toHaveCount(1)
|
|
})
|
|
|
|
test('enforces browser readiness before starting at 900px', async ({ page }) => {
|
|
const stopped = { ...runtime, state: 'exited', status: 'Exited', endpoint: '' }
|
|
const environments = [
|
|
{ ...stopped, id: 'ready', alias: 'ready', name: '就绪环境', schedule_status: 'ready' },
|
|
{ ...stopped, id: 'missing', alias: 'missing', name: '实例缺失环境', schedule_status: 'blocked', schedule_block_reason: 'runtime_missing' },
|
|
{ ...stopped, id: 'revoked', alias: 'revoked', name: '已撤权环境', schedule_status: 'blocked', schedule_block_reason: 'account_revoked' },
|
|
]
|
|
await page.route('**/api/browsers', route => route.fulfill({ json: environments }))
|
|
await page.route('**/api/gateways', route => route.fulfill({ json: [] }))
|
|
await page.route('**/api/browser-images', route => route.fulfill({ json: [] }))
|
|
await page.route('**/api/phase-a/accounts', route => route.fulfill({ json: [] }))
|
|
await page.route('**/api/network-exits', route => route.fulfill({ json: [] }))
|
|
await page.route('**/api/browsers/*/start', route => route.fulfill({ status: 204 }))
|
|
await page.setViewportSize({ width: 900, height: 900 })
|
|
await page.goto('/#/browsers')
|
|
|
|
const ready = page.getByRole('button', { name: '启动 就绪环境' })
|
|
const missing = page.getByRole('button', { name: '启动 实例缺失环境' })
|
|
await expect(ready).toBeEnabled()
|
|
await expect(missing).toBeEnabled()
|
|
await expect(page.getByRole('button', { name: '启动 已撤权环境(授权已撤销)' })).toBeDisabled()
|
|
|
|
for (const [button, alias] of [[ready, 'ready'], [missing, 'missing']]) {
|
|
const request = page.waitForRequest(`**/api/browsers/${alias}/start`)
|
|
await button.click()
|
|
expect((await request).method()).toBe('POST')
|
|
}
|
|
})
|
|
|
|
test('submits a complete 192-character credential reference at 900px', async ({ page }) => {
|
|
const credentialKey = `${'a'.repeat(64)}/${'b'.repeat(127)}`
|
|
await page.route('**/api/phase-a/accounts', async route => {
|
|
if (route.request().method() === 'POST') return route.fulfill({ json: { id: 'account-new' } })
|
|
return route.fulfill({ json: [] })
|
|
})
|
|
await page.route('**/api/browsers', route => route.fulfill({ json: [] }))
|
|
await page.setViewportSize({ width: 900, height: 900 })
|
|
await page.goto('/#/accounts')
|
|
|
|
await page.getByRole('textbox', { name: '平台', exact: true }).fill('mock')
|
|
await page.getByRole('textbox', { name: '平台账号标识', exact: true }).fill('shop-new')
|
|
await page.getByRole('textbox', { name: '凭据引用 ID', exact: true }).fill('credential-new')
|
|
const input = page.getByRole('textbox', { name: '凭据引用键', exact: true })
|
|
await input.fill(credentialKey)
|
|
await expect(input).toHaveAttribute('maxlength', '192')
|
|
await expect(input).toHaveValue(credentialKey)
|
|
|
|
const request = page.waitForRequest(request => request.url().endsWith('/api/phase-a/accounts') && request.method() === 'POST')
|
|
await page.getByRole('button', { name: '创建账号' }).click()
|
|
await expect((await request).postDataJSON()).toMatchObject({ credential_reference: { key: credentialKey } })
|
|
})
|
|
|
|
test('keeps account and network-exit pages inside 599px, 900px and 1280px', async ({ page }) => {
|
|
const accountKey = 'a'.repeat(128)
|
|
const credentialID = 'c'.repeat(128)
|
|
const hostname = [63, 63, 63, 61].map(length => 'h'.repeat(length)).join('.')
|
|
const account = { id: 'account-a', platform: 'mock', platform_account_key: accountKey, authorization_kind: 'owned', authorization_status: 'authorized', runtime_status: 'paused', version: 1, credential_reference: { id: credentialID, provider: 'os_keyring' } }
|
|
const binding = { alias: 'env-a', name: '店铺环境', account_id: 'account-a', network_exit_id: 'exit-a', network_exit_health: 'healthy', binding_version: 1, schedule_status: 'blocked', schedule_block_reason: 'account_paused' }
|
|
const networkExit = { id: 'exit-a', protocol: 'socks5', host: hostname, port: 1080, health_status: 'healthy', credential_reference: { id: credentialID, provider: 'os_keyring' } }
|
|
await page.route('**/api/phase-a/accounts', route => route.fulfill({ json: [account] }))
|
|
await page.route('**/api/phase-a/accounts/account-a', route => route.fulfill({ json: account }))
|
|
await page.route('**/api/phase-a/drafts?account_id=account-a', route => route.fulfill({ json: [] }))
|
|
await page.route('**/api/browsers', route => route.fulfill({ json: [binding] }))
|
|
await page.route('**/api/network-exits', route => route.fulfill({ json: [networkExit] }))
|
|
|
|
for (const path of ['/#/accounts', '/#/accounts/account-a', '/#/network-exits']) {
|
|
for (const width of [599, 900, 1280]) {
|
|
await page.setViewportSize({ width, height: 900 })
|
|
await page.goto(path)
|
|
await expect(page.getByRole('heading', { level: 1 })).toBeVisible()
|
|
expect(await page.evaluate(() => document.documentElement.scrollWidth)).toBeLessThanOrEqual(width)
|
|
}
|
|
}
|
|
})
|
|
|
|
test('opens account detail at the phase A route', async ({ page }) => {
|
|
const account = { id: 'account-a', platform: 'mock', platform_account_key: 'shop-a', authorization_kind: 'owned', authorization_status: 'authorized', runtime_status: 'paused', version: 1, credential_reference: { id: 'credential-a', provider: 'os_keyring' } }
|
|
await page.route('**/api/phase-a/accounts', route => route.fulfill({ json: [account] }))
|
|
await page.route('**/api/phase-a/accounts/account-a', route => route.fulfill({ json: account }))
|
|
await page.route('**/api/browsers', route => route.fulfill({ json: [] }))
|
|
await page.route('**/api/phase-a/drafts?account_id=account-a', route => route.fulfill({ json: [] }))
|
|
await page.setViewportSize({ width: 599, height: 900 })
|
|
await page.goto('/#/accounts')
|
|
|
|
await page.getByRole('link', { name: '查看账号' }).click()
|
|
await expect(page).toHaveURL(/#\/accounts\/account-a$/)
|
|
await expect(page.getByRole('heading', { level: 1, name: 'shop-a' })).toBeVisible()
|
|
expect(await page.evaluate(() => document.documentElement.scrollWidth)).toBeLessThanOrEqual(599)
|
|
})
|
|
|
|
test('keeps draft review responsive and restores focus after dialog close and successful save', async ({ page }) => {
|
|
const account = { id: 'account-a', platform: 'mock', platform_account_key: 'shop-a', authorization_status: 'authorized', runtime_status: 'active', version: 2 }
|
|
const draft = {
|
|
id: 'draft-a', account_id: 'account-a', version: 1, content: 'x'.repeat(1000), account,
|
|
versions: [{ id: 'draft-a', account_id: 'account-a', version: 1, content: 'x'.repeat(1000) }],
|
|
confirmations: [], tasks: [],
|
|
}
|
|
const binding = { alias: 'env-a', name: '店铺环境', account_id: 'account-a', network_exit_id: 'exit-a', network_exit_health: 'healthy', binding_version: 4, schedule_status: 'ready', schedule_block_reason: '' }
|
|
await page.route('**/api/phase-a/drafts/draft-a', route => route.fulfill({ json: draft }))
|
|
await page.route('**/api/browsers', route => route.fulfill({ json: [binding] }))
|
|
await page.route('**/api/phase-a/confirmations', route => route.fulfill({ json: { id: 'confirmation-a' } }))
|
|
|
|
for (const width of [599, 900, 1280]) {
|
|
await page.setViewportSize({ width, height: 900 })
|
|
await page.goto('/#/drafts/draft-a')
|
|
await expect(page.getByRole('heading', { level: 1, name: '草稿核对' })).toBeVisible()
|
|
expect(await page.evaluate(() => document.documentElement.scrollWidth)).toBeLessThanOrEqual(width)
|
|
}
|
|
|
|
await page.setViewportSize({ width: 599, height: 900 })
|
|
await page.getByRole('checkbox', { name: /我已核对当前账号/ }).check()
|
|
const trigger = page.getByRole('button', { name: '确认当前快照' })
|
|
await trigger.click()
|
|
await expect(page.getByRole('dialog', { name: '确认草稿版本' })).toBeVisible()
|
|
await page.keyboard.press('Escape')
|
|
await expect(page.getByRole('dialog')).toBeHidden()
|
|
await expect(trigger).toBeFocused()
|
|
|
|
await trigger.click()
|
|
await page.getByRole('button', { name: '保存确认' }).click()
|
|
await expect(page.getByRole('dialog')).toBeHidden()
|
|
await expect(trigger).toBeFocused()
|
|
})
|