Playwright多同类测试用例执行时超时错误的解决方法问询
我用TypeScript编写Playwright自动化脚本,单个测试用例均可正常运行,但在同一文件中加入5-6个同类测试用例后,执行2-3个就会出现超时错误,且超时发生在beforeEach()阶段。已尝试增加超时时间、在测试用例中使用waitForTimeout(),但问题仍未解决。附上示例代码,寻求在单个文件中编写多个测试用例且避免超时的可行方案。
示例代码
import { test, expect, Locator } from '@playwright/test'; import { waitFor } from '@testing-library/react'; let businessSidebar: Locator; let search: Locator; let advanceFilter: Locator; test.beforeEach(async({ page }) => { await page.goto('/'); //login await page.locator("input[name='email']").fill('admin@gmail.com'); await page.locator("input[name='password']").fill('admin'); await page.locator("button:text('Login')").click(); businessSidebar = page.locator('text=Business Profile'); await businessSidebar.click(); search = page.locator("input[name='search']"); advanceFilter = page.locator("//button[text()='Filters']") }) test.skip('Verify user can filter business profile by: Industries', async({ page }) => { const industryFilter = await page.locator("(//button[contains(@class,'flex w-full')])[1]"); await industryFilter.click(); const select = await page.locator("//span[text()='Agriculture and Fisheries']"); await select.click(); await expect(page).toHaveURL(`http://localhost:3000/dashboard/business`); }) test.skip('Verify user can filter business profile by: Business Type', async({ page }) => { const businessTypeFilter = await page.locator("(//button[contains(@class,'flex w-full')])[2]"); await businessTypeFilter.click(); const select = await page.locator("//span[text()='Association']"); await select.click(); await expect(page).toHaveURL(`http://localhost:3000/dashboard/business`); })
当前超时配置
timeout: 40 * 1000, expect: { /** * Maximum time expect() should wait for the condition to be met. * For example in `await expect(locator).toHaveText();` */ timeout: 5000 },
可行解决方案
移除全局定位器变量:当前使用的全局
businessSidebar、search等Locator会导致测试间的状态污染,因为每个测试用例的page实例是隔离的。改为在beforeEach中使用局部变量,或通过测试上下文存储:test.beforeEach(async({ page, context }) => { await page.goto('/'); // 登录步骤 await page.locator("input[name='email']").fill('admin@gmail.com'); await page.locator("input[name='password']").fill('admin'); await page.locator("button:text('Login')").click(); // 等待登录完成后页面跳转 await page.waitForURL('**/dashboard/**', { timeout: 10000 }); const businessSidebar = page.locator('text=Business Profile'); await businessSidebar.click(); // 等待页面跳转完成 await page.waitForURL('http://localhost:3000/dashboard/business', { timeout: 10000 }); // 将定位器存入测试上下文 context.businessSidebar = businessSidebar; context.search = page.locator("input[name='search']"); context.advanceFilter = page.locator("//button[text()='Filters']"); }) // 测试用例中从上下文获取定位器 test('Verify user can filter business profile by: Industries', async({ page }) => { const industryFilter = page.locator("[data-testid='industry-filter']"); await industryFilter.click(); // ... 其余步骤 })确保操作前页面状态稳定:在
beforeEach的关键步骤后添加等待,避免页面未加载完成就执行下一步。比如登录后等待URL变化或目标元素出现,点击侧边栏后等待页面跳转完成,不要依赖固定延迟。优化定位器稳定性:避免使用依赖元素位置的XPath(如
(//button[contains(@class,'flex w-full')])[1]),这类定位器极易因页面结构变化失效。建议给页面元素添加data-testid属性,使用page.locator("[data-testid='xxx']")进行定位,大幅提升稳定性。单独设置beforeEach超时:全局
timeout是整个测试用例的超时时间,可单独给beforeEach配置更长的超时,避免因登录、页面跳转等耗时操作导致超时:test.beforeEach(async({ page }) => { // ... 步骤内容 }, { timeout: 60000 }); // 设置beforeEach超时为60秒强制清除上下文状态:如果应用存在缓存或会话残留问题,在
beforeEach开头清除上下文的Cookie和权限,确保每个测试用例从干净状态开始:test.beforeEach(async({ page }) => { await page.context().clearCookies(); await page.context().clearPermissions(); await page.goto('/'); // ... 其余步骤 })
内容的提问来源于stack exchange,提问作者Taj99

