Cypress 入門 + vs Playwright 完整對比
「我們公司用 Cypress、面試問 Playwright 我不會、該轉嗎?」 — 看到太多 QA 卡在這。實話:Cypress 還很好用、但 Playwright 全方位贏。這篇講清楚兩者差異 + 何時該轉。
一張圖看完差異
flowchart TD
Choose{選 framework} --> Q1{多瀏覽器?}
Q1 -->|Chrome only| Cyp1[Cypress 可]
Q1 -->|Safari / WebKit| PW1[Playwright]
Choose --> Q2{Cross-origin?}
Q2 -->|不需要| Cyp2[Cypress 可]
Q2 -->|要 OAuth / 多 domain| PW2[Playwright]
Choose --> Q3{多 tab / iframe?}
Q3 -->|不需要| Cyp3[Cypress 可]
Q3 -->|要| PW3[Playwright]
Choose --> Q4{平行跑 CI 預算?}
Q4 -->|沒限制| Both[都行]
Q4 -->|要免費| PW4[Playwright]
style PW1 fill:#10b981,color:#fff
style PW2 fill:#10b981,color:#fff
style PW3 fill:#10b981,color:#fff
style PW4 fill:#10b981,color:#fff
style Cyp1 fill:#06b6d4,color:#fff
style Cyp2 fill:#06b6d4,color:#fff
style Cyp3 fill:#06b6d4,color:#fff
Cypress 30 分鐘入門
安裝
npm init -y
npm install --save-dev cypress
npx cypress open
GUI 介面選「E2E Testing」、Cypress 會自動建好 demo。
第一個 test
// cypress/e2e/login.cy.js
describe('Login', () => {
beforeEach(() => {
cy.visit('https://app.example.com/login');
});
it('登入成功跳轉 dashboard', () => {
cy.get('input[name=email]').type('[email protected]');
cy.get('input[name=password]').type('Test@123');
cy.contains('button', '登入').click();
cy.url().should('include', '/dashboard');
cy.contains('Welcome').should('be.visible');
});
it('錯密碼顯示錯誤', () => {
cy.get('input[name=email]').type('[email protected]');
cy.get('input[name=password]').type('wrong');
cy.contains('button', '登入').click();
cy.contains('帳號或密碼錯誤').should('be.visible');
});
});
跑:
npx cypress run # headless
npx cypress run --browser chrome # 指定瀏覽器
npx cypress open # GUI 互動
Cypress 最大強項 — Time Travel Debugger
flowchart LR
Tests[跑 test] --> Snap[每步 snapshot DOM]
Snap --> GUI[GUI 介面]
GUI --> Click[點任一步 → 看當下 DOM]
Click --> Console[Console 直接 query]
style GUI fill:#a855f7,color:#fff
style Console fill:#10b981,color:#fff
這個 UX 至今沒對手。Playwright trace viewer 接近但體驗仍差一截。
Cypress vs Playwright 全方位對比
| 維度 | Cypress | Playwright | 贏家 |
|---|---|---|---|
| 學習曲線 | 低(chainable API 直覺) | 中(async/await 標準) | Cypress |
| Debug UX | 神級 time travel | 好的 trace viewer | Cypress |
| 多瀏覽器 | Chrome / Edge / Firefox | + WebKit (Safari) | Playwright |
| Cross-origin | 受限(需 setting) | 原生支援 | Playwright |
| Multi-tab / window | 困難 / hack | 原生 | Playwright |
| iframe | 困難 | 原生 page.frame() | Playwright |
| 平行測試 | 要付費 Cypress Cloud | 免費內建 sharding | Playwright |
| API 測試 | cy.request() | request fixture | 平手 |
| Component testing | 強 | 弱 | Cypress |
| Mobile emulation | 受限 | 強 | Playwright |
| Auto-wait | 是 | 是 | 平手 |
| TypeScript | 支援 | 一等公民 | Playwright |
| CI 整合 | 好 | 更好 | Playwright |
| 企業支援 | Cypress Cloud | Microsoft 支持 | Playwright |
| 社群活躍 | 大但減 | 暴增中 | Playwright |
| NPM downloads | 5M/week | 12M/week (2026) | Playwright |
Selector 哲學差異
// Cypress — chainable + 自家 API
cy.get('button')
.contains('Submit')
.click();
cy.get('[data-testid=email]')
.type('[email protected]');
// Playwright — standard async/await
await page.getByRole('button', { name: 'Submit' }).click();
await page.getByLabel('Email').fill('[email protected]');
Playwright 用 getByRole 跟 accessibility tree 走、跨 UI 改動更穩。
Cypress 鼓勵 data-testid、要前端配合。
Cross-origin 痛點實戰
// Cypress — OAuth 登入會死
it('OAuth login', () => {
cy.visit('/login');
cy.contains('Sign in with Google').click();
// ❌ 跳到 accounts.google.com → cy.url() fail
// 需要 cy.origin() 或 mock 整段 flow
});
// Playwright — 沒事
test('OAuth login', async ({ page }) => {
await page.goto('/login');
await page.click('text=Sign in with Google');
await page.fill('input[type=email]', '[email protected]');
await page.click('button:has-text("Next")');
// ✓ 跨域沒問題
});
OAuth 工作流 = Playwright 絕對選。
Component Testing — Cypress 還領先
// Cypress + React component test
import Button from './Button';
describe('Button', () => {
it('renders text', () => {
cy.mount(<Button>Click me</Button>);
cy.contains('Click me').should('be.visible');
});
it('handles click', () => {
const onClick = cy.stub();
cy.mount(<Button onClick={onClick}>Click</Button>);
cy.contains('Click').click();
cy.wrap(onClick).should('have.been.calledOnce');
});
});
這塊 Cypress UX 還是最好。但新案推 Vitest + Testing Library(更快、更輕量)。
平行測試 — Cypress 收費痛
flowchart LR
PW[Playwright] -->|內建免費| PWS[--shard=N/4]
PWS --> Free[$0]
Cy[Cypress] --> CC{Cypress Cloud?}
CC -->|是| Pay["$75 / month start"]
CC -->|否| Slow[全部 serial 跑]
style Free fill:#10b981,color:#fff
style Pay fill:#ef4444,color:#fff
style Slow fill:#f59e0b,color:#fff
Cypress 平行測試需要 Cypress Cloud 訂閱。150 個 case 跑 30 分鐘、付費後變 8 分鐘 — 但每月 $75 起跳。
Playwright --shard=1/4 免費就有。
遷移 Cypress → Playwright 實戰
Step 1: 評估
flowchart TD
Eval[評估] --> Q1{case 數 < 100?}
Q1 -->|是| Big[全部重寫快]
Q1 -->|否| Q2[漸進]
Q2 --> S1[新 case 用 Playwright]
S1 --> S2[舊 case 慢慢轉]
S2 --> S3[Cypress 停止接受 new case]
style Big fill:#10b981,color:#fff
style S2 fill:#06b6d4,color:#fff
Step 2: API 對照表
| Cypress | Playwright |
|---|---|
cy.visit(url) |
await page.goto(url) |
cy.get(sel).click() |
await page.click(sel) |
cy.get(sel).type(val) |
await page.fill(sel, val) |
cy.contains(text) |
await page.getByText(text) |
cy.url().should('include') |
await expect(page).toHaveURL() |
cy.intercept('POST', url) |
await page.route(url) |
cy.fixture('users.json') |
import users from './users.json' |
cy.task('db:reset') |
直接呼叫 helper function |
beforeEach() |
test.beforeEach() |
Step 3: codemod 工具
npx playwright-codemod-cypress ./cypress/e2e/
會幫你轉 80%、剩 20% 手工。
Step 4: 跑舊新平行 1-2 週
確認 case behavior 一致、再下架 Cypress。
反模式 — Cypress 該換的訊號
flowchart TD
Sig{該換訊號} --> S1["每天遇 cy.origin 卡關"]
Sig --> S2["想測 Safari / iPad"]
Sig --> S3["Cypress Cloud 月費 > $200"]
Sig --> S4["跑 E2E > 30 分鐘"]
Sig --> S5["平行常常 flaky"]
Sig --> S6["招新人都會 Playwright 不會 Cypress"]
Sig --> S7["AI workflow 工具都支援 Playwright"]
style S1 fill:#ef4444,color:#fff
style S2 fill:#ef4444,color:#fff
style S3 fill:#ef4444,color:#fff
style S4 fill:#ef4444,color:#fff
style S5 fill:#ef4444,color:#fff
style S6 fill:#ef4444,color:#fff
style S7 fill:#ef4444,color:#fff
任 3 個 → 啟動遷移討論。
面試常考題
Q1: Cypress 跟 Playwright 差別?
好答案(30 秒版):
Cypress 是 chainable API、time travel debugger 神級、Chrome-only 體驗最好。Playwright 是 async/await 標準、原生 cross-origin / multi-tab / 多瀏覽器 / 免費平行。新案推 Playwright、舊 Cypress 案不一定要遷。
Q2: 你會選哪個?
好答案:
看情境。新案 90% 選 Playwright(多平台 + 免費平行)。Component testing 有時保留 Cypress。但團隊現在大多走 Playwright + Vitest 組合、Cypress 漸式微。
Q3: Cypress 如何處理 cross-origin?
好答案:
用
cy.origin('https://other.com', () => { ... })、但仍有 cookie 限制與環境變數設置麻煩。Playwright 原生支援、寫起來像同 domain。
給仍在 Cypress 的人
不要急著遷。但:
1. 學 Playwright(找工作必備)
2. 新 case 開始用 Playwright
3. 舊 case 維持 Cypress 直到痛點累積
4. 痛了再 codemod 遷
兩個都會的 QA = 求職市場熱門。
最後
Cypress 是好工具、time travel UX 至今沒對手。但整體生態 + 跨平台支援 + 免費平行 → Playwright 全方位贏。2026 年的新案沒理由選 Cypress、但 5 年的 Cypress 案也不用急遷。會兩個 = 最強。
延伸: - Playwright 入門 — 30 分鐘上手 - Page Object Model 實戰 - GitHub Actions × Playwright 完整實戰