📌 背景
在日常测试中,我们经常需要验证多个账号是否能正常登录系统。手动一个个输入不仅效率低,还容易出错。
本文将用 Playwright 配合 Excel/CSV 数据文件,实现自动化批量登录测试,并检查登录是否成功
🧩 方案选择
方案一:直接读取 .xlsx 文件(推荐)
需要:安装 xlsx 库(npm install xlsx)。
代码最简洁:用列名取值,不怕列顺序变化。
方案二:读取 .csv 文件(轻量)
优点:无需额外依赖,Node.js 原生 fs 模块即可。
需要:先用 Excel 将文件另存为 "CSV UTF-8 (逗号分隔)"。
注意:确保 CSV 是真正的逗号分隔,且编码为 UTF-8。
🚀 方案一:读取 .xlsx(列名版)
- 安装依赖
bash
2026-06-16 14:39 with jianju in Test/playwright_tests/gxnydsj on master [?] is 📦 v1.0.0 via ⬢ v22.22.0
➜ npm install xlsx --save-dev
added 9 packages in 2s
- 代码
bash
import { test, expect } from '@playwright/test';
import XLSX from 'xlsx';
//=====从 Excel 文件(/Users/jianju/Downloads/区域人员管理列表.xlsx)里,
// 把"用户名"和"密码"两列的数据提取出来,存成一个列表(数组),方便后面逐个登录。
// 1. 读取文件,并把所有的内容,都存在"workbook"里面
const workbook = XLSX.readFile('/Users/Downloads/区域人员管理列表.xlsx');
// 2.一个 Excel 可能有多个工作表(Sheet),这个代码取第一个工作表(Sheet0),存到 sheet 里。
const sheet = workbook.Sheets[workbook.SheetNames[0]];
// 3. 转换成一张"大表格"(二维数组)。不要把第一行当作列名,而是把每一行都当成一个普通数组,
const data = XLSX.utils.sheet_to_json(sheet, { header: 1 });
// 4. 从第二行开始提取用户名(第4列,索引3)和密码(第5列,索引4)
const users = data
.slice(1) // 跳过第一行,即跳过表头
.map(row => ({
//第4个元素(索引3) → 因为索引从0开始,所以 row[3] 就是"用户名"列。
//|| '' 表示如果这一格是空的,就当作空字符串。
//.toString() 保证它一定是文本。
//.replace(/\0/g, '') 是去掉一些看不见的"空字符"(之前数据库报错就是因为这个),就像把杂物剔除。
// .trim() 去掉首尾多余的空格。
u: (row[3] || '').toString().replace(/\0/g, '').trim(),
p: (row[4] || '').toString().replace(/\0/g, '').trim()
}))
.filter(item => item.u && item.p); // 过滤空值
for (const { u, p } of users) {
test(`登录 ${u}`, async ({ page }) => {
await page.goto('http://1.1.1.1/test/home');
// 如果不需要点击菜单,可以注释掉下面这行(根据您手动测试的结果)
await page.getByRole('listitem').filter({ hasText: '农用薄膜残留监测' }).click();
await page.getByRole('textbox', { name: '用户名' }).fill(u);
await page.getByRole('textbox', { name: '密码' }).fill(p);
await page.getByRole('button', { name: '登 录' }).click();
await expect(page.getByRole('heading', { name: '农用薄膜调查监测' })).toBeVisible({
timeout: 10000
});
});
}
📄 方案二:读取 .csv
bash
import fs from 'fs'; //专门读取csv文件
import { test, expect } from '@playwright/test';
//读取文件内容,并通过换行符,切成一行一行,放在lines里面
const lines = fs.readFileSync('/Users/Downloads/区域人员管理列表.csv', 'utf-8').split('\n');
//从第 2 行开始,一直循环到最后一行"。(i从0开始,0是第一行)
for (let i = 1; i < lines.length; i++) {
//比如某一行是 "测试,北海,测试账号,shiboom29,shiboom29,管理员",用 split(',') 切成 ["测试", "北海", "测试账号", "shiboom29", "shiboom29", "管理员"]。
//.map(s => s.trim()) 是把每个字段前后的空格都去掉(比如有时候 Excel 导出会在字段末尾带空格,去掉更干净)。
//处理完的结果存在 cols 里,这就是当前用户的各个字段。
const cols = lines[i].split(',').map(s => s.trim());
const u = cols[3]; //第 4 列是"用户名",在数组里索引是 3
const p = cols[4];
if (!u || !p) continue; //如果用户名或密码是空的,就跳过这一行
test(`登录 ${u}`, async ({ page }) => {
await page.goto('http://1.1.1.1/test/home');
await page.getByRole('listitem').filter({ hasText: '农用薄膜残留监测' }).click();
await page.getByRole('textbox', { name: '用户名' }).fill(u);
await page.getByRole('textbox', { name: '密码' }).fill(p);
await page.getByRole('button', { name: '登 录' }).click();
await expect(page.getByRole('heading', { name: '农用薄膜调查监测' })).toBeVisible({ timeout: 10000 });
});
}
运行结果
