Previous
Day 18 · Network Interception and Mocking
Next
Day 20 · Weekly Review 4: Real Business Flow E2E
真实场景
Day 1960-120 minutesPlaywright QA hands-on drill

第 19 天:文件上传下载、Dialog 与 Frame

今日目标

  • 掌握常见复杂页面交互。
  • 能处理文件、弹窗、iframe。

学习时间安排(60–120 分钟)

时间模块做什么
0-20 分钟核心概念与词汇读概念表,重点理解 download 事件和 frameLocator。
20-45 分钟官方文档阅读读 Uploads、Downloads、Dialogs、Frames 相关文档。
45-75 分钟实操练习分别练习上传、下载、dialog、iframe 四类交互。
75-105 分钟示例代码改写把四类交互整理成模板代码笔记。
105-120 分钟复盘与作业完成今日问题,标记最容易 flaky 的点。

核心概念与词汇

English中文场景用法
setInputFiles()设置上传文件用于说明该术语在 Playwright 测试中的使用场景。
waitForEvent('download')等待下载事件用于说明该术语在 Playwright 测试中的使用场景。
download.saveAs()保存下载文件用于说明该术语在 Playwright 测试中的使用场景。
dialog原生弹窗用于说明该术语在 Playwright 测试中的使用场景。
page.on('dialog')弹窗监听用于说明该术语在 Playwright 测试中的使用场景。
frameLocator()Frame 定位器用于说明该术语在 Playwright 测试中的使用场景。
iframe内嵌框架用于说明该术语在 Playwright 测试中的使用场景。
dialog.accept() / dismiss()接受/取消弹窗用于说明该术语在 Playwright 测试中的使用场景。
multipart/form-data表单文件上传用于说明该术语在 Playwright 测试中的使用场景。
download path下载路径用于说明该术语在 Playwright 测试中的使用场景。

学习材料

  • 必读:[Uploads](https://playwright.dev/docs/input#upload-files)
  • 必读:[Downloads](https://playwright.dev/docs/downloads)
  • 必读:[Dialogs](https://playwright.dev/docs/dialogs)
  • 必读:[Frames](https://playwright.dev/docs/frames)

重点理解

上传文件:

await page.getByLabel('Upload file').setInputFiles('tests/fixtures/file.pdf');

下载文件:

const downloadPromise = page.waitForEvent('download');
await page.getByRole('button', { name: 'Download' }).click();
const download = await downloadPromise;
await download.saveAs('downloads/report.pdf');

Dialog:

page.on('dialog', async dialog => {
  expect(dialog.message()).toContain('Are you sure');
  await dialog.accept();
});

Frame:

const frame = page.frameLocator('iframe[name="payment"]');
await frame.getByLabel('Card number').fill('4242424242424242');

实操步骤

分别练习:

  • 上传一个文件。
  • 下载一个文件。
  • 处理 confirm dialog。
  • 定位 iframe 中的元素。

示例代码

import { test, expect } from '@playwright/test';

test('upload and download report', async ({ page }) => {
  await page.goto('/reports');

  // 上传
  await page.getByLabel('Upload file').setInputFiles('tests/fixtures/sample.csv');

  // 下载:先建 promise 再点击
  const downloadPromise = page.waitForEvent('download');
  await page.getByRole('button', { name: 'Generate report' }).click();
  const download = await downloadPromise;
  await download.saveAs('downloads/report.csv');

  await expect(page.getByText('Report ready')).toBeVisible();
});

test('confirm deletion dialog', async ({ page }) => {
  page.on('dialog', async dialog => {
    expect(dialog.type()).toBe('confirm');
    await dialog.accept();
  });

  await page.goto('/orders');
  await page.getByRole('button', { name: 'Delete order #42' }).click();
  await expect(page.getByText('Order #42 deleted')).toBeVisible();
});

常见坑

  • 先点击下载按钮再等 download 事件,事件已经错过。
  • dialog 监听注册在点击之后,弹窗没人处理导致测试挂起。
  • 直接 page.getByLabel() 找 iframe 里的元素——必须先 frameLocator。
  • CI 里 saveAs('downloads/...') 目录不存在或没有写权限。
  • 上传路径用绝对路径,换机器/CI 环境后文件找不到。

今日产出

  • 一个复杂交互测试文件。
  • 记录每类交互的模板代码。

今日问题

  1. 文件下载为什么要先创建 waitForEvent promise?
  2. Dialog 监听应该在点击前还是点击后?
  3. FrameLocator 和普通 Locator 有什么区别?
  4. 文件路径在 CI 中可能有什么问题?
  5. 复杂交互最容易 flaky 的点是什么?

复盘要点

  • 事件类交互的口诀:先监听、后触发(download、dialog、popup 全部如此)。
  • iframe 是页面里的页面:先 frameLocator 切入,再沿用你会的所有 locator 技巧。
  • 复杂交互的 flaky 大多来自时序——事件错过、弹窗未处理、文件未落盘。

AI 时代扩展:AI 辅助 Playwright 测试

新增概念

English中文
event timing事件时序
cross-frame interaction跨 frame 交互
file handling文件处理

适用场景

让 AI 解释“为什么要先建 promise 再点击”,或者审查你的复杂交互测试里的时序问题。iframe 内的 locator 建议也可以让 AI 先给草稿。

可复用表达 / 提示词

请解释 Playwright 处理 download 事件时为什么必须「先 waitForEvent 再点击」,不这样做会怎样。
这是 iframe 的 HTML 片段,请给出 frameLocator 切入后的元素定位草稿。

追问加练

  • AI 建议用 waitForTimeout 等弹窗出现,正确做法是什么?
  • dialog 没被处理时测试会卡住还是失败?你遇到过吗?
  • 多级嵌套 iframe 怎么一层层切入?

今日作业

  • 完成四类交互各 1 条测试并跑通。
  • 整理“复杂交互模板库”:上传、下载、dialog、iframe、popup 各一段可复制代码。
  • 让 AI 审查你的模板库,找出时序问题并修正。

自检清单

Previous
Day 18 · Network Interception and Mocking
Next
Day 20 · Weekly Review 4: Real Business Flow E2E