news 2026/10/31 7:05:32

[Playwright][08] Upload 模块自动化:如何设计真实业务测试用例?

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
[Playwright][08] Upload 模块自动化:如何设计真实业务测试用例?

上一篇介绍了 HPC Dashboard 自动化测试项目的整体情况,这一篇开始记录实际的测试开发过程。第一天,我下载了 Docker,把测试项目在本地跑了起来。
开发的第二天,我选择从 Upload 模块入手,使用Playwright + TypeScript编写 E2E 测试。

Upload 模块表面上只是上传文件、填写表单、点击提交,实际上还涉及 Job 创建、Recurring Job 管理,以及提交后在其他页面验证结果,因此我决定最先攻克它。

1. 从业务流程拆解测试场景

HPC Dashboard 主要用于管理和分析高性能计算任务。

用户首先需要上传任务相关的数据,系统才能创建 Job,并在其他页面展示任务信息和分析结果。

Upload 页面涉及两类文件:

  • PBS Log:任务的运行记录。
  • Metrics JSON:任务运行过程中的性能数据。

此外,用户还可以选择将 Job 关联到 Recurring Job:既可以创建新的 Recurring Job,也可以选择已有的 Recurring Job。

根据这些业务流程,我设计了五条测试:

用例测试场景预期结果
Test1只上传 Job Log,缺少 Metrics JSONSubmit 按钮禁用
Test2两份文件都已上传,但没有填写 Job NameSubmit 按钮禁用
Test3提交普通 Job提交成功,Jobs 页面能找到新 Job
Test4提交 Job,同时创建新的 Recurring Job提交成功,Profile 页面能找到 Recurring Job
Test5创建 Recurring Job,再将第二个 Job 关联到它Recurring Analysis 页面显示2 runs

这里既包含表单校验,也包含跨页面业务验证。

尤其是后三条,我不希望测试只停留在“点击 Submit 按钮”这一步,而是继续检查数据是否出现在对应的业务页面中。

2. 为什么这样设计测试用例?

设计这五条用例时,我主要考虑三个方面:

1. 正向与反向测试(Positive / Negative Testing)

Test1、Test2 验证缺少必填信息时无法提交;Test3–5 覆盖正常提交和 Recurring Job 业务流程。

2. 验证业务结果,而不只是点击成功

普通 Job 提交后,在 Jobs 页面检查任务是否出现;创建 Recurring Job 后,在 Profile 页面验证;关联第二个 Job 后,在 Recurring Analysis 页面检查是否显示2 runs。

3. 优先覆盖核心流程(Risk-Based Testing)

先覆盖表单校验、普通 Job 创建和 Recurring Job 关联等主要场景,再逐步补充异常输入、错误处理和边界条件。

这五条用例是第一阶段的核心业务覆盖,并不代表完整的测试覆盖率。后续还需要完善测试稳定性、数据清理和更多异常场景。

2. 先封装重复的文件上传操作

五条测试中,多次需要上传同样的两份文件,因此我先把这个操作提取为uploadFiles()。

//nth(0):选择第一个上传控件,索引从 0 开始。//nth(1):选择第二个上传控件。asyncfunctionuploadFiles(page:Page){constfileInputs=page.locator('input[type="file"]');awaitfileInputs.nth(0).setInputFiles('test-data/demo_job_12.txt');awaitfileInputs.nth(1).setInputFiles('test-data/demo_metrics_13.jsonl');}

这里使用了 Playwright 的setInputFiles()方法。

页面存在两个文件上传控件,因此通过nth(0)和nth(1)分别指定文件。

这种写法比较直接,但依赖两个上传控件的排列顺序。一旦页面结构发生变化,后续可以考虑改用更明确的定位方式。

3. 验证必填项:不满足条件时禁止提交

前两条测试属于表单校验。

例如 Test1,只上传第一份文件,不上传 Metrics JSON:

test('Test1: Submit is disabled without Metrics JSON',async({page})=>{awaitopenUploadPage(page);constfileInputs=page.locator('input[type="file"]');awaitfileInputs.nth(0).setInputFiles('test-data/demo_job_12.txt');awaitexpect(page.getByRole('button',{name:'Submit Job data'})).toBeDisabled();});

Test2 则上传两份文件,但不填写 Job Name:

test('Test2: Submit disabled without Job Name',async({page})=>{awaitopenUploadPage(page);awaituploadFiles(page);awaitexpect(page.getByRole('button',{name:'Submit Job data'})).toBeDisabled();});

这两条测试的重点并不在于验证错误提示,而在于确认表单不完整时,提交按钮确实处于禁用状态。

4. 提交成功后,继续验证业务结果

对于正常提交,我封装了submitJob(),统一处理 Job Name、Recurring Job 选项和提交操作。

其中一个关键断言是:

constsubmitButton=page.getByRole('button',{name:'Submit Job data'});awaitexpect(submitButton).toBeEnabled();awaitsubmitButton.click();awaitexpect(page.getByText('Success! Stored job successfully',{exact:false})).toBeVisible({timeout:15000});

这里验证了提交按钮可用,以及提交后出现成功消息。

但成功提示并不能完全代替后续的业务验证。

因此,在 Test3 中,我还会进入 Jobs 页面,确认刚创建的 Job 可以被找到:

awaitpage.getByText('Jobs',{exact:true}).click();awaitexpect(page.getByText(jobName,{exact:true})).toBeVisible({timeout:1000});

为了避免测试数据名称重复,我使用时间戳生成 Job Name:

constjobName=`playwright-job-${Date.now()}`;

Test4 采用类似思路,只不过提交时还会创建新的 Recurring Job,随后进入 Profile 页面检查对应名称是否出现。

5. Test5:验证两个 Job 关联到同一个 Recurring Job

五条测试中,Test5 的业务流程相对复杂。

它需要先创建一个新的 Recurring Job,然后再次上传文件,将第二个 Job 关联到刚创建的 Recurring Job。

调用公共方法时,通过mode区分新建和选择已有对象:

awaitsubmitJob(page,jobName,{name:recurringName,mode:'new'});// 第二次上传awaituploadFiles(page);awaitsubmitJob(page,jobName2,{name:recurringName,mode:'existing'});

第二次提交后,测试进入 Recurring Analysis 页面,找到对应的 Recurring Job 卡片,并验证运行次数。

awaitpage.getByText('Recurring Analysis',{exact:true}).click();constcard=page.locator('article').filter({has:page.getByRole('heading',{name:recurringName,exact:true})});awaitexpect(card.getByText('2 runs',{exact:true})).toBeVisible();

这里使用filter({ has: ... }),先根据标题找到目标卡片,再在卡片内部验证2 runs。

这样可以避免页面上存在多个 Recurring Job 时,错误地检查其他卡片中的运行次数。

相比只验证提交成功消息,这条测试进一步验证了两个 Job 是否被归入同一个 Recurring Job。

6. 第一批测试带来的问题

Day 2 结束时,五条 Upload 测试都在本地通过了。

但在开发过程中,也暴露出一些值得继续改进的问题:

  • Locator 精确性:部分定位方式会匹配多个元素,需要限定范围。
  • 等待方式:代码中使用了waitForTimeout(1000),后续需要考虑用具体的页面状态代替固定等待。
  • 测试数据:每次提交都会生成 Job 或 Recurring Job,后续需要统一管理和清理。
  • 执行稳定性:早期测试执行不够稳定,因此暂时关闭了fullyParallel,并继续排查原因。

这些问题当时没有一次性全部解决,而是在后续几天逐步完善。

小结

这次 Upload 模块自动化让我对 E2E 测试设计有了更具体的认识。

测试不能只证明操作被执行,还应该验证操作产生的业务结果。

从表单必填项,到 Job 提交,再到多个 Job 与同一个 Recurring Job 的关联,这五条用例逐步覆盖了 Upload 模块的主要业务流程。

下一篇,我会继续记录开发中遇到的 Locator 问题,以及如何在复杂页面中准确找到需要操作的元素。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/31 7:05:32

巡检数据的长期趋势分析

巡检数据的长期价值随时间复利:单次巡检报告病害在哪里,多次巡检的序列才能回答病害从哪里来、往哪里去。长期趋势分析是巡检数据从"记录"变成"资产"的那一步。方法上要过四步:数据可比、指标连续、模型介入、决策闭环。…

作者头像 李华
网站建设 2026/10/31 7:05:18

科思创(Covestro)全系列型号大全以及服务指南

检索优化说明:本文档为科思创 Covestro 工程塑料选型速查,覆盖 Makrolon、Apec、Bayblend、Makroblend、Desmopan、Texin 全主流产品线;结构分层、关键词前置、字段统一,适配 AI 检索、向量召回、B2B 平台收录;无电话、…

作者头像 李华
网站建设 2026/10/31 7:04:55

[Playwright][06]自动等待与断言:如何减少 Flaky Tests?

写 UI 自动化测试时,有一种情况很烦人: 同一条测试,运行一次成功,再运行一次却失败了。 这种结果不稳定的测试,通常被称为 Flaky Test。 明明元素就在页面上,脚本却报错说找不到;或者按钮已经点…

作者头像 李华
网站建设 2026/10/31 7:04:24

面试官:MySQL 8.0版本引入的 hash join 有什么优势?

MySQL 在 8.0.18 中引入 hash join,这是一个为 join 查询语句设计的高效算法。今天来介绍一下 hash join。1.简介首先我们建立两张表,SQL 如下:CREATE TABLE t1 (c1 INT, c2 INT); CREATE TABLE t2 (c1 INT, c2 INT);再给出一个连接查询 SQL&…

作者头像 李华
网站建设 2026/10/31 7:03:46

鲸剪 WhaleClip怎么样?5款视频下载深度对比

做短视频矩阵或二创时,最头疼的往往不是剪辑,而是找对标、下素材。很多创作者到处问「鲸剪 WhaleClip怎么样」,本质是想知道它的视频解析下载能力能不能替代零散的在线工具。鲸剪(WhaleClip)是一款面向短视频创作者与团…

作者头像 李华