Playwright 的 set_input_files() 不触发 onChange 是因直接设置文件列表而不模拟用户选择行为;需手动 dispatchEvent 或用 force:true 处理隐藏元素,注意路径、超时及服务端验证。

Playwright 中 set_input_files() 为什么没触发 onChange?
因为 Playwright 的 set_input_files() 是直接设置 <input type="file"> 的文件列表,不模拟真实用户点击选择文件的行为,所以不会触发浏览器原生的文件选择弹窗,也不会触发某些依赖 change 或 input 事件的前端逻辑(比如预览、校验、自动提交)。
实操建议:
- 优先用
set_input_files()—— 它快、稳定、跨平台,适用于 90% 的后端文件接收验证场景 - 如果页面 JS 显式监听了
change且没做兼容,手动触发:await input.evaluate("el => el.dispatchEvent(new Event('change', { bubbles: true }))"); - 避免用
click()+press()模拟弹窗 —— Playwright 不支持操作系统级文件对话框,强行用page.keyboard会失败或仅在特定本地环境偶然生效
Selenium 的 SendKeys() 上传路径在 CI 上总报错
错误现象通常是 System.IO.FileNotFoundException 或 “path not found”,本质是 Selenium 要求传入的路径必须是**绝对路径**,且该路径需存在于运行 WebDriver 的机器上 —— 这在 Docker 容器或远程 CI agent(如 GitHub Actions runner)里极易出错,因为测试代码里的相对路径指向的是开发机。
实操建议:
- 用
Path.GetFullPath("test-file.pdf")而不是"./test-file.pdf",确保路径解析准确 - 把测试文件放进
bin/Debug或bin/Release目录下,并用AppContext.BaseDirectory拼接:var filePath = Path.Combine(AppContext.BaseDirectory, "test-file.pdf");
- CI 环境中别依赖本地桌面路径(如
C:\Users\...),所有文件应随代码一起提交或通过 artifact 下载
上传大文件时 Playwright 报 TimeoutError: page.setInputFiles: Timeout 30000ms exceeded
这不是网络慢的问题,而是 Playwright 默认等待 input 元素可交互(visible + enabled)+ 文件写入完成的总超时时间只有 30 秒。大文件(如 >100MB)在内存映射或底层文件句柄准备阶段可能卡住,尤其在低配 CI 机器上。
实操建议:
- 显式加大超时:
await input.setInputFiles(filePath, { timeout: 120_000 }); - 确认
input元素没有被 CSSdisplay: none或visibility: hidden隐藏 —— Playwright 会等它 visible,而很多上传组件用opacity: 0+position: absolute隐藏原生 input,这时要用force: true:await input.setInputFiles(filePath, { force: true }); - 避免在
setInputFiles()后立刻断言服务器响应 —— 文件上传是异步的,需等后续 API 请求完成再验证
如何验证上传后的服务端行为?
自动化测试里只点上传按钮、填路径、就认为“上传成功”,是常见盲区。真正要测的是:文件是否抵达后端?内容是否完整?业务逻辑(如转码、入库、回调)是否执行?
实操建议:
- 不要只截图或检查 UI 文字提示 —— 那些容易伪造或延迟渲染
- 在测试中调用后端健康检查接口或数据库查询(如查
Files表新增记录):var count = await dbContext.Files.CountAsync(f => f.Name == "test.pdf");
- 若用 Mock 服务(如 WireMock),在
setInputFiles()后捕获实际发出的POST /upload请求,断言Content-Type和二进制长度 - 上传多个文件时注意:Playwright 的
setInputFiles()接收string[],但部分后端框架(如 ASP.NET Core)默认只绑定第一个文件,需确认控制器参数是IFormFile[]而非IFormFile










