写 Next.js 项目的人,最终都会走上这样一条路:
写前端 → 写 API → 写数据库 → 写测试 → 坐牢(调试半天测试不通过)。
为了不让自己凌晨三点还在盯着 npm test
发呆,我们需要掌握 E2E(End-to-End)测试。
今天的主角是两位测试界的明星:
- 🎭 Playwright ------ 来自微软,擅长潜入浏览器底层搞事情。
- 🌲 Cypress ------ UI 界的老牌网红,界面友好,生态丰富。
接下来我们用 Next.js 做个全栈小例子,边写边比较。
🏗️ 1. 为什么要做 E2E 测试?
很多人觉得单元测试已经够了。
- 单元测试:就像检查螺丝钉是不是拧紧。
- E2E 测试:直接开上车,踩油门,看车会不会解体。
在全栈应用里,前端、后端、数据库之间任何一个环节崩了,用户体验就直接爆炸。E2E 测试帮我们模拟真实用户的操作,比如:
- 打开页面
- 填写表单
- 点击提交
- 检查后端是否真的保存成功
⚙️ 2. Next.js 项目准备
bash
# 创建一个 Next.js 项目
npx create-next-app e2e-demo
cd e2e-demo
我们加一个简单的 Todo 功能:
pages/api/todos.js
ini
let todos = [];
export default function handler(req, res) {
if (req.method === "POST") {
const todo = { id: Date.now(), text: req.body.text };
todos.push(todo);
return res.status(201).json(todo);
}
if (req.method === "GET") {
return res.status(200).json(todos);
}
}
pages/index.js
javascript
import { useState } from "react";
export default function Home() {
const [todos, setTodos] = useState([]);
const [text, setText] = useState("");
async function addTodo() {
const res = await fetch("/api/todos", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ text })
});
const newTodo = await res.json();
setTodos([...todos, newTodo]);
setText("");
}
return (
<div>
<h1>📝 Todo List</h1>
<input
value={text}
onChange={(e) => setText(e.target.value)}
placeholder="Write something..."
/>
<button onClick={addTodo}>Add</button>
<ul>
{todos.map((t) => (
<li key={t.id}>{t.text}</li>
))}
</ul>
</div>
);
}
到这里,我们有了一个最小可测的全栈应用。
🎭 3. 用 Playwright 写 E2E 测试
安装:
bash
npm install -D @playwright/test
npx playwright install
配置一个测试:
tests/todo.spec.js
erlang
import { test, expect } from "@playwright/test";
test("用户可以添加一个 Todo", async ({ page }) => {
await page.goto("http://localhost:3000");
await page.fill("input", "买一杯咖啡");
await page.click("button");
const todo = await page.locator("li").last().innerText();
expect(todo).toBe("买一杯咖啡");
});
运行:
bash
npx playwright test
Playwright 的优势:
- 多浏览器支持(Chromium、WebKit、Firefox)
- 速度快,底层用浏览器协议直连
- 内置截图、视频录制,调试时一目了然
🌲 4. 用 Cypress 写 E2E 测试
安装:
arduino
npm install -D cypress
npx cypress open
配置一个测试:
cypress/e2e/todo.cy.js
erlang
describe("Todo App", () => {
it("用户可以添加一个 Todo", () => {
cy.visit("http://localhost:3000");
cy.get("input").type("写测试代码");
cy.contains("Add").click();
cy.get("li").last().should("have.text", "写测试代码");
});
});
运行:
arduino
npx cypress open
Cypress 的优势:
- 界面化调试,像玩小游戏一样点点点
- 社区插件丰富
- 断言语法自然(
cy.get().should(...)
看起来比expect
更口语化)
🥊 5. Playwright vs Cypress 对比
特性 | Playwright 🎭 | Cypress 🌲 |
---|---|---|
浏览器支持 | Chromium / Firefox / WebKit | Chromium 系 |
速度 | ⚡ 更快 | 稍慢 |
调试体验 | 截图 & 视频 | 可视化界面强 |
API 风格 | 类似 Jest | 链式操作,更口语化 |
CI/CD 适配 | 强大 | 成熟 |
一句话总结:
- 如果你爱折腾底层,想要跨浏览器测试 → Playwright
- 如果你想要上手快、调试方便 → Cypress
🌌 6. 收尾
测试不是"写完交差"的工作,它本质上是 给自己未来省头发 。
E2E 测试就像一台自动驾驶仪:
- 让你放心上线
- 让你半夜睡得更香
- 让你的代码少点"玄学 Bug"
写代码的人和写测试的人,往往是同一个倒霉蛋。
但是相信我:测试写得好,未来的你会给现在的自己磕个头 🙇。
📌 作业:
- 用 Playwright 写一个"用户登录"E2E 测试。
- 用 Cypress 写一个"数据持久化"测试(刷新后还能看到 Todo)。