test(e2e): stabilize publish and search waits

This commit is contained in:
dongmucat 2026-04-14 13:55:33 +08:00
parent 5dd89097e5
commit 7dff8dc697
2 changed files with 73 additions and 33 deletions

View file

@ -1,4 +1,5 @@
import { expect, test } from '@playwright/test'
import path from 'node:path'
import { setEnglishLocale } from './helpers/auth-fixtures'
import { registerSession } from './helpers/session'
import { E2eTestDataBuilder } from './helpers/test-data-builder'
@ -20,11 +21,27 @@ test.describe('Publish Flow UI (Real API)', () => {
await page.goto('/dashboard/publish')
await expect(page.getByRole('heading', { name: 'Publish Skill' })).toBeVisible()
await page.locator('#namespace').click()
await page.getByText(new RegExp(`\\(@${namespace.slug}\\)`)).first().click()
const namespaceTrigger = page.locator('#namespace')
await expect(namespaceTrigger).toBeVisible()
await namespaceTrigger.click()
const namespaceOption = page.getByRole('option', {
name: new RegExp(`\\(@${namespace.slug}\\)`),
}).first()
await expect(namespaceOption).toBeVisible()
await namespaceOption.evaluate((element: HTMLElement) => {
element.scrollIntoView({ block: 'center' })
element.click()
})
await expect(namespaceTrigger).toContainText(`@${namespace.slug}`)
await page.locator('input[type="file"]').setInputFiles(packagePath)
await page.getByRole('button', { name: 'Confirm Publish' }).click()
await expect(page.getByText(path.basename(packagePath))).toBeVisible()
const confirmButton = page.getByRole('button', { name: 'Confirm Publish' })
await expect(confirmButton).toBeEnabled()
await Promise.all([
page.waitForURL('**/dashboard/skills'),
confirmButton.click(),
])
await expect(page).toHaveURL('/dashboard/skills')
await expect(page.getByRole('heading', { name: 'My Skills' })).toBeVisible()

View file

@ -30,38 +30,61 @@ async function waitForCards(page: Page) {
const keyword = basicSeed?.keyword
const encodedKeyword = keyword ? encodeURIComponent(keyword) : null
let reloaded = false
for (let attempt = 0; attempt < 4; attempt += 1) {
await page.waitForLoadState('networkidle')
const waitForMatchingResponse = async () => {
if (!encodedKeyword) {
return
}
await page.waitForResponse(async (response) => {
if (!response.url().includes('/api/web/skills?') || !response.url().includes(`q=${encodedKeyword}`)) {
return false
}
if (response.status() !== 200) {
return false
}
try {
const payload = await response.json() as { data?: { items?: Array<unknown> } }
return Array.isArray(payload.data?.items) && payload.data.items.length > 0
} catch {
return false
}
}, { timeout: 15_000 }).catch(() => null)
}
const waitForCardCount = async () => {
await expect.poll(
async () => cards.count(),
{
timeout: 20_000,
intervals: [250, 500, 1_000, 2_000],
},
).toBeGreaterThan(0)
}
await page.waitForLoadState('networkidle')
await expect(page.getByRole('textbox', { name: 'Search skills...' })).toBeVisible({ timeout: 8_000 })
if (await cards.count() > 0) {
return cards
}
await waitForMatchingResponse()
try {
await waitForCardCount()
} catch {
if (reloaded) {
throw new Error('Timed out waiting for search cards after one reload fallback')
}
reloaded = true
await page.reload({ waitUntil: 'networkidle' })
await expect(page.getByRole('textbox', { name: 'Search skills...' })).toBeVisible({ timeout: 8_000 })
if (await cards.count() > 0) {
return cards
}
if (attempt < 3) {
const responsePromise = encodedKeyword
? page.waitForResponse(async (response) => {
if (!response.url().includes('/api/web/skills?') || !response.url().includes(`q=${encodedKeyword}`)) {
return false
}
if (response.status() !== 200) {
return false
}
try {
const payload = await response.json() as { data?: { items?: Array<unknown> } }
return Array.isArray(payload.data?.items) && payload.data.items.length > 0
} catch {
return false
}
}, { timeout: 12_000 }).catch(() => null)
: Promise.resolve(null)
await page.waitForTimeout(750 * (attempt + 1))
await page.reload({ waitUntil: 'networkidle' })
await responsePromise
}
await waitForMatchingResponse()
await waitForCardCount()
}
return cards