feat: connect search and project settings
This commit is contained in:
@@ -19,8 +19,23 @@ const page = await browser.newPage({ viewport: { width: 1440, height: 1024 }, de
|
||||
const errors = []
|
||||
const failures = []
|
||||
const projectId = '019b0000-0000-7000-8000-000000000001'
|
||||
const taskSearchResultId = '019b0000-0000-7000-8000-000000000003'
|
||||
const unknownProjectId = '019b0000-0000-7000-8000-000000000099'
|
||||
const searchRequests = []
|
||||
const projectPatchRequests = []
|
||||
let expectingProjectPatchError = false
|
||||
let expectedProjectPatchConsoleErrorCount = 0
|
||||
page.on('console', (message) => {
|
||||
if (message.type() === 'error') errors.push(message.text())
|
||||
if (message.type() !== 'error') return
|
||||
if (
|
||||
expectingProjectPatchError &&
|
||||
expectedProjectPatchConsoleErrorCount === 0 &&
|
||||
message.text() === 'Failed to load resource: the server responded with a status of 500 (Internal Server Error)'
|
||||
) {
|
||||
expectedProjectPatchConsoleErrorCount += 1
|
||||
return
|
||||
}
|
||||
errors.push(message.text())
|
||||
})
|
||||
|
||||
const visualCheckWorkspace = {
|
||||
@@ -54,6 +69,7 @@ const visualCheckWorkspace = {
|
||||
|
||||
await page.route('http://localhost:9150/api/v1/**', async (route) => {
|
||||
const url = new URL(route.request().url())
|
||||
const method = route.request().method()
|
||||
if (url.pathname === '/api/v1/status') {
|
||||
await route.fulfill({ json: { timestamp: new Date().toISOString() } })
|
||||
return
|
||||
@@ -70,6 +86,39 @@ await page.route('http://localhost:9150/api/v1/**', async (route) => {
|
||||
await route.fulfill({ json: visualCheckWorkspace })
|
||||
return
|
||||
}
|
||||
if (url.pathname === '/api/v1/search') {
|
||||
const query = url.searchParams.get('q') ?? ''
|
||||
searchRequests.push(query)
|
||||
if (query === '慢请求') await new Promise((resolve) => setTimeout(resolve, 300))
|
||||
const projectIdForResult = query === '未知项目' ? unknownProjectId : projectId
|
||||
await route.fulfill({
|
||||
json: {
|
||||
items: [{
|
||||
id: taskSearchResultId,
|
||||
type: 'task',
|
||||
title: query === '未知项目' ? '未知项目任务' : query === '慢请求' ? '慢请求任务' : query === '快请求' ? '快请求任务' : '回调任务',
|
||||
projectId: projectIdForResult,
|
||||
snippet: '检查签名',
|
||||
}],
|
||||
},
|
||||
})
|
||||
return
|
||||
}
|
||||
if (url.pathname === `/api/v1/projects/${projectId}` && method === 'PATCH') {
|
||||
const input = route.request().postDataJSON()
|
||||
projectPatchRequests.push(input)
|
||||
if (input.description === '触发失败') {
|
||||
await new Promise((resolve) => setTimeout(resolve, 250))
|
||||
await route.fulfill({
|
||||
status: 500,
|
||||
json: { error: { code: 'internal_error', message: '项目设置保存失败,请稍后重试' } },
|
||||
})
|
||||
return
|
||||
}
|
||||
Object.assign(visualCheckWorkspace.project, input)
|
||||
await route.fulfill({ json: visualCheckWorkspace.project })
|
||||
return
|
||||
}
|
||||
await route.fulfill({ status: 404, json: { error: { code: 'not_found', message: '视觉检查未配置该接口' } } })
|
||||
})
|
||||
|
||||
@@ -282,6 +331,95 @@ if (await channelNavButton.count() === 0) {
|
||||
}
|
||||
await page.setViewportSize({ width: 1440, height: 1024 })
|
||||
|
||||
const searchInput = page.getByPlaceholder('搜索项目、任务和笔记')
|
||||
const searchButton = page.getByRole('button', { name: '搜索', exact: true })
|
||||
if (await searchInput.count() === 0 || await searchButton.count() === 0) {
|
||||
failures.push('topbar must expose the connected project/task/note search controls')
|
||||
} else {
|
||||
await searchInput.fill('回调')
|
||||
await searchInput.press('Enter')
|
||||
await page.waitForTimeout(150)
|
||||
if (!searchRequests.includes('回调')) failures.push(`search Enter must request q=回调, got ${JSON.stringify(searchRequests)}`)
|
||||
const callbackResult = page.getByRole('button', { name: /回调任务/ })
|
||||
if (await callbackResult.count() === 0) {
|
||||
failures.push('search results must render in a selectable dropdown list')
|
||||
} else {
|
||||
await callbackResult.click()
|
||||
const activeAfterSearch = await page.locator('.channel-button.active').textContent()
|
||||
if (!activeAfterSearch?.includes('工作计划')) {
|
||||
failures.push(`task search result must navigate to 工作计划, got ${JSON.stringify(activeAfterSearch)}`)
|
||||
}
|
||||
}
|
||||
|
||||
await searchInput.fill('未知项目')
|
||||
await searchButton.click()
|
||||
await page.waitForTimeout(150)
|
||||
const unknownResult = page.getByRole('button', { name: /未知项目任务/ })
|
||||
if (await unknownResult.count() === 0) {
|
||||
failures.push('Search button must submit the current query and show results')
|
||||
} else {
|
||||
const projectBeforeUnknownResult = await page.locator('.project-title h5').textContent()
|
||||
await unknownResult.click()
|
||||
const projectAfterUnknownResult = await page.locator('.project-title h5').textContent()
|
||||
if (projectAfterUnknownResult !== projectBeforeUnknownResult) {
|
||||
failures.push('a result for an unavailable project must not fabricate project navigation')
|
||||
}
|
||||
}
|
||||
|
||||
await searchInput.fill('慢请求')
|
||||
await searchInput.press('Enter')
|
||||
await page.waitForTimeout(30)
|
||||
await searchInput.fill('快请求')
|
||||
await searchInput.press('Enter')
|
||||
await page.waitForTimeout(400)
|
||||
if (await page.getByRole('button', { name: /慢请求任务/ }).count() !== 0) {
|
||||
failures.push('a stale search response must not replace newer results')
|
||||
}
|
||||
if (await page.getByRole('button', { name: /快请求任务/ }).count() === 0) {
|
||||
failures.push('the newest search response must remain visible after requests resolve out of order')
|
||||
}
|
||||
await searchInput.fill('')
|
||||
}
|
||||
|
||||
const settingsButton = page.getByRole('button', { name: '编辑项目设置', exact: true })
|
||||
if (await settingsButton.count() === 0) {
|
||||
failures.push('project sidebar must expose an accessible project settings button')
|
||||
} else {
|
||||
await settingsButton.click()
|
||||
let settingsModal = page.getByRole('dialog', { name: '编辑项目' })
|
||||
await settingsModal.getByLabel('名称').fill('森林项目已更新')
|
||||
await settingsModal.getByRole('button', { name: '确定', exact: true }).click()
|
||||
await settingsModal.waitFor({ state: 'hidden', timeout: 2000 }).catch(() => {})
|
||||
if (projectPatchRequests[0]?.name !== '森林项目已更新') {
|
||||
failures.push(`project settings must PATCH the edited identity, got ${JSON.stringify(projectPatchRequests)}`)
|
||||
}
|
||||
if (await page.locator('.project-title h5').textContent() !== '森林项目已更新') {
|
||||
failures.push('successful project settings update must reload the same project identity')
|
||||
}
|
||||
if (await settingsModal.isVisible()) failures.push('successful project settings update must close the modal')
|
||||
|
||||
await settingsButton.click()
|
||||
settingsModal = page.getByRole('dialog', { name: '编辑项目' })
|
||||
await settingsModal.getByLabel('简介').fill('触发失败')
|
||||
expectingProjectPatchError = true
|
||||
await settingsModal.getByRole('button', { name: '确定', exact: true }).click()
|
||||
await page.waitForTimeout(50)
|
||||
const confirmButton = settingsModal.getByRole('button', { name: '确定', exact: true })
|
||||
if (!await confirmButton.evaluate((button) => button.classList.contains('arco-btn-loading'))) {
|
||||
failures.push('project settings confirmation must show loading while PATCH is pending')
|
||||
}
|
||||
await page.waitForTimeout(300)
|
||||
if (!await settingsModal.isVisible()) failures.push('failed project settings update must keep the modal open')
|
||||
if (!await settingsModal.getByText('项目设置保存失败,请稍后重试', { exact: true }).isVisible()) {
|
||||
failures.push('failed project settings update must render the API Chinese error inside the modal')
|
||||
}
|
||||
expectingProjectPatchError = false
|
||||
if (expectedProjectPatchConsoleErrorCount !== 1) {
|
||||
failures.push(`expected one simulated PATCH console error, got ${expectedProjectPatchConsoleErrorCount}`)
|
||||
}
|
||||
await settingsModal.getByRole('button', { name: '取消', exact: true }).click()
|
||||
}
|
||||
|
||||
await page.locator('.channel-sidebar').hover()
|
||||
const channelSidebarHoverMetrics = await collectMetrics()
|
||||
await page.locator('.stage').hover()
|
||||
|
||||
Reference in New Issue
Block a user