fix(workbench): complete profile and channel flows

This commit is contained in:
2026-07-24 14:46:38 +08:00
parent d7eb20a85f
commit f430566976
21 changed files with 563 additions and 151 deletions

View File

@@ -164,6 +164,13 @@ const visualCheckWorkspace = {
cronPlans: [],
}
await page.route('http://agent.senlin.ai/api/v1/status', async (route) => {
await route.fulfill({
json: { timestamp: '2026-07-24T00:00:00Z' },
headers: { 'access-control-allow-origin': '*' },
})
})
await page.route('http://localhost:9150/api/v1/**', async (route) => {
const url = new URL(route.request().url())
if (url.pathname === '/api/v1/status') {
@@ -171,7 +178,7 @@ await page.route('http://localhost:9150/api/v1/**', async (route) => {
return
}
if (url.pathname === '/api/v1/auth/login') {
await route.fulfill({ json: { token: 'visual-check-token' } })
await route.fulfill({ json: { token: 'visual-check-token', user: { email: 'visual@senlin.ai', displayName: '视觉检查' } } })
return
}
if (url.pathname === '/api/v1/projects') {
@@ -182,6 +189,16 @@ await page.route('http://localhost:9150/api/v1/**', async (route) => {
await route.fulfill({ json: visualCheckWorkspace })
return
}
if (url.pathname === `/api/v1/projects/${projectId}/channels` && route.request().method() === 'POST') {
const input = route.request().postDataJSON()
const channel = {
id: '019b0000-0000-7000-8000-000000000060', projectId, type: 'custom_link',
title: input.title, icon: input.icon || 'link', count: 0, url: input.url, sortOrder: 8,
}
visualCheckWorkspace.channels = [...visualCheckWorkspace.channels, channel]
await route.fulfill({ status: 201, json: channel })
return
}
if (url.pathname === `/api/v1/projects/${projectId}/documents` && route.request().method() === 'GET') {
await route.fulfill({ json: [] })
return
@@ -201,7 +218,7 @@ await page.route('http://localhost:9150/api/v1/**', async (route) => {
createdAt: '2026-07-22T09:00:00Z',
updatedAt: '2026-07-22T09:00:00Z',
},
})
})
return
}
await route.fulfill({
@@ -394,6 +411,8 @@ const collectMetrics = async () => page.evaluate(() => {
await page.goto(`http://127.0.0.1:${port}/`, { waitUntil: 'networkidle' })
await page.locator('.login-form input').first().fill('localhost:9150')
await page.locator('.login-form input').nth(1).fill('visual@senlin.ai')
await page.locator('.login-form input').nth(2).fill('password123')
await page.waitForSelector('.connection-card.online')
const loginConnectionStatus = await page.locator('.connection-card').textContent()
await page.screenshot({ path: 'test-results/login-react-acro.png', fullPage: true })
@@ -451,6 +470,7 @@ const channelListHoverMetrics = await collectMetrics()
const channelPageChecks = []
let taskTagFilterCheck = null
let aiSessionCheck = null
let savedChannelVisible = false
for (const channel of [
{ label: '工作计划', pageClass: 'project-tasks-page', expectedHeading: '工作计划' },
{ label: 'AI 会话', pageClass: 'project-ai-page', expectedHeading: '' },
@@ -506,6 +526,15 @@ for (const channel of [
await page.screenshot({ path: 'test-results/project-ai-session-light.png', fullPage: true })
}
if (channel.label === '新建频道') {
const inputs = page.locator('.project-new-channel-page input')
await inputs.nth(0).fill('客户研究')
await inputs.nth(2).fill('https://example.com/customer-research')
await page.getByRole('button', { name: '保存频道' }).click()
await page.waitForTimeout(250)
savedChannelVisible = await page.locator('.channel-button', { hasText: '客户研究' }).count() === 1
}
if (channel.label === '笔记资料') {
await page.screenshot({ path: 'test-results/project-documents-light.png', fullPage: true })
}
@@ -533,6 +562,7 @@ console.log(JSON.stringify({
channelPageChecks,
taskTagFilterCheck,
aiSessionCheck,
savedChannelVisible,
errors,
}, null, 2))
@@ -543,10 +573,8 @@ if (errors.length) failures.push(`console errors: ${errors.join('; ')}`)
if (metrics.statusbarHeight !== 32) failures.push(`expected statusbar height 32, got ${metrics.statusbarHeight}`)
if (!metrics.statusName) failures.push('expected authenticated status label')
if (!metrics.statusOnlineDot) failures.push('expected legacy online status dot')
if (!metrics.statusUpgrade) failures.push('expected legacy upgrade action')
if (!metrics.statusSystemText.includes('3 个计划进行中') || !metrics.statusSystemText.includes('AI 空闲') || !metrics.statusSystemText.includes('152GB 可用')) {
failures.push(`expected legacy system status summary, got ${JSON.stringify(metrics.statusSystemText)}`)
}
if (metrics.statusUpgrade) failures.push('expected billing entry to be removed from the status bar')
if (!metrics.statusSystemText.includes('已连接到私有工作台')) failures.push(`expected connected status summary, got ${JSON.stringify(metrics.statusSystemText)}`)
if (metrics.searchHeight !== 42) failures.push(`expected search height 42, got ${metrics.searchHeight}`)
if (metrics.overflowX) failures.push('expected no horizontal overflow')
if (!metrics.workbenchMain) failures.push('missing workbench main')
@@ -632,6 +660,7 @@ if (!editSourceModalCheck.title.includes('编辑数据源') || editSourceModalCh
failures.push(`expected prefilled edit data source modal, got ${JSON.stringify(editSourceModalCheck)}`)
}
if (!editedSourceVisible) failures.push('expected edited data source name to update its card')
if (!savedChannelVisible) failures.push('expected saved custom channel to appear in the project sidebar')
if (!workspaceExploreMetrics.stage || !workspaceExploreMetrics.projectRail) {
failures.push(`missing workspace explore layout regions: rail=${JSON.stringify(workspaceExploreMetrics.projectRail)}, stage=${JSON.stringify(workspaceExploreMetrics.stage)}`)
} else if (Math.abs(workspaceExploreMetrics.stage.left - workspaceExploreMetrics.projectRail.right) > 1) {
@@ -699,8 +728,8 @@ for (const check of channelPageChecks) {
if (!check.activeChannel.includes(check.label)) {
failures.push(`expected ${check.label} sidebar button to stay active, got ${JSON.stringify(check.activeChannel)}`)
}
if (check.label === '新建频道' && (check.inputCount < 4 || !check.hasSaveChannel)) {
failures.push(`expected legacy new channel editor, got inputs=${check.inputCount}, save=${check.hasSaveChannel}`)
if (check.label === '新建频道' && (check.inputCount < 3 || !check.hasSaveChannel)) {
failures.push(`expected channel editor with persisted link fields, got inputs=${check.inputCount}, save=${check.hasSaveChannel}`)
}
if (check.label === 'AI 会话' && (
check.hasOverviewHead || !check.hasSessionList || !check.hasComposer || !check.hasExpertPicker ||