Danh sách bài viết

Bài 60: CLI --project <name> — Chạy 1 Project Cụ Thể

Bài này đào sâu vào flag --project của Playwright CLI: chạy nhiều project cùng lúc, cách dependency tự động được include, --no-deps và risk đi kèm, sự khác biệt giữa exact match và wildcard, kết hợp --project với --grep để filter smoke test theo browser, sharding interaction, CI matrix GitHub Actions per-project, và 4 pitfall hay gặp khi dùng flag này trên thực tế.

28/05/2026
0 lượt xem
1

Mục Tiêu Bài Học

Sau bài này bạn sẽ:

  • Nắm chắc cú pháp --project=name, multiple --project, và khi nào không truyền flag.
  • Hiểu cơ chế dependency auto-include: project có dependencies: ['setup'] tự kéo setup chạy trước.
  • Biết khi nào dùng --no-deps và risk đi kèm khi setup artifact đã cũ.
  • Phân biệt exact match (case-sensitive) với wildcard (bài 61 deep dive riêng).
  • Kết hợp đúng --project với --grep--shard mà không bị nhầm phạm vi.
  • Tránh 4 pitfall: typo tên project, silent skip do testMatch không khớp, empty run khi combine với --grep, và tính nhầm shard khi combine.

Bài này khác với Series 1 bài 66: Flag --project đã trình bày cú pháp cơ bản, wildcard v1.46, project name có space, use case CI matrix và multiple viewport. Ở đây tập trung vào phần mà bài 66 chỉ đề cập ngắn: interaction giữa --project và dependency, combine flag, edge case thực tế.

2

Cú Pháp Cơ Bản và Multiple --project

Chạy đúng 1 project:

npx playwright test --project=chromium

Cả 2 form đều hợp lệ — = và space:

npx playwright test --project=chromium
npx playwright test --project chromium

Dùng dấu = giúp tránh ambiguity khi shell parse argument tiếp theo (ví dụ file path sau đó).

Chạy nhiều project — lặp flag:

npx playwright test --project=chromium --project=firefox
# Chạy cả chromium + firefox, bỏ qua webkit

Mỗi lần lặp --project thêm 1 entry vào danh sách cần chạy. Playwright gộp các entry đó thành OR — chromium HOẶC firefox. Thứ tự liệt kê không ảnh hưởng thứ tự thực thi; Playwright schedule theo số worker và dependency graph.

3

Behavior Khi Không Truyền --project

Không truyền --project → Playwright chạy tất cả project trong projects[]. Config 3 browser (chromium, firefox, webkit) với 1 test file → report có 3 dòng:

Running 3 tests using 3 workers

  ✓  [chromium] › login.spec.ts:5:5 › login flow (1.2s)
  ✓  [firefox]  › login.spec.ts:5:5 › login flow (1.5s)
  ✓  [webkit]   › login.spec.ts:5:5 › login flow (1.9s)

3 passed (2.1s)

Nếu config có setup project và các browser project depend vào setup, Playwright tự resolve dependency: setup chạy trước, rồi mới đến các browser project song song.

Default không truyền flag là lựa chọn hợp lý cho CI full-run. Trên dev local khi chỉ cần verify nhanh 1 browser, --project=chromium tiết kiệm đáng kể thời gian.

4

Dependency Auto-Include

Project có thể khai báo dependencies — mảng tên project cần chạy trước. Khi truyền --project=main, Playwright tự động resolve toàn bộ dependency chain và chạy theo thứ tự đúng:

// playwright.config.ts
export default defineConfig({
  projects: [
    {
      name: 'setup',
      testMatch: /.*\.setup\.ts/,
    },
    {
      name: 'chromium',
      use: {
        ...devices['Desktop Chrome'],
        storageState: 'playwright/.auth/user.json',
      },
      dependencies: ['setup'],
    },
    {
      name: 'firefox',
      use: {
        ...devices['Desktop Firefox'],
        storageState: 'playwright/.auth/user.json',
      },
      dependencies: ['setup'],
    },
  ],
});

Khi chạy:

npx playwright test --project=chromium
# Thứ tự thực tế: setup → chromium

Playwright in rõ trong log khi dependency được kéo vào:

Running 2 projects: setup, chromium
  [setup]    › auth.setup.ts:3:1 › authenticate (1.8s) ✓
  [chromium] › dashboard.spec.ts:5:5 › show widget (0.9s) ✓

Cơ chế này hoạt động theo dependency graph — nếu chromium depend vào setup và setup depend vào một project khác (hiếm nhưng có thể), Playwright giải toàn bộ chain. Vòng tròn dependency (circular) bị reject ngay khi load config với error rõ ràng.

Khi truyền nhiều project và chúng share cùng dependency:

npx playwright test --project=chromium --project=firefox
# Thứ tự: setup (1 lần) → chromium + firefox (song song)

Playwright chỉ chạy setup 1 lần dù nhiều project depend vào nó — đây là điểm quan trọng, tránh nhầm rằng setup sẽ chạy N lần theo số project.

5

Flag --no-deps — Skip Dependency

--no-deps bỏ qua toàn bộ dependency — chỉ chạy đúng project được chỉ định:

npx playwright test --project=chromium --no-deps
# Chỉ chạy chromium, KHÔNG chạy setup

Use case chính:

  • Debug nhanh 1 test cụ thể sau khi setup đã chạy trước đó — không muốn chờ setup re-run (đặc biệt khi setup là login flow mất 3–5s).
  • Dev local đang iterate test logic, storageState trên disk còn hợp lệ từ lần chạy trước.
  • CI job có artifact upload/download riêng cho storageState — shard sau không cần re-run setup.

Risk khi dùng --no-deps:

# Scenario 1: file storageState chưa tồn tại lần nào
npx playwright test --project=chromium --no-deps
# → test chạy ở trạng thái không login
# → tất cả test cần auth redirect về /login → fail

# Scenario 2: storageState tồn tại nhưng session đã expire
# → test chạy, đến bước cần authenticated action → 401
# → fail với error "Unexpected page: /login" thay vì auth error rõ ràng

Để kiểm tra storageState còn hợp lệ không trước khi dùng --no-deps, xem file playwright/.auth/user.json — nếu file không tồn tại hoặc quá cũ (so với session lifetime của app), cần chạy setup lại.

6

Exact Match vs Wildcard

Không truyền ký tự đặc biệt → --project dùng exact match, case-sensitive:

npx playwright test --project=chromium    # match chính xác name: 'chromium'
npx playwright test --project=Chromium    # KHÔNG match — C hoa khác c thường

Từ Playwright v1.46, truyền * trong value → wildcard match, case-insensitive:

npx playwright test --project='*chromium*'
# Match: chromium, mobile-chromium, chromium-canary (bất kể chữ hoa/thường)

Luôn quote wildcard pattern để shell không tự expand * theo file trong thư mục hiện tại:

# SAI — shell có thể expand * thành tên file
npx playwright test --project=*chromium*

# ĐÚNG
npx playwright test --project='*chromium*'

Bài 61 sẽ đi sâu toàn bộ wildcard pattern: prefix, suffix, glob ?, behavior khi không match, combine nhiều pattern. Bài này chỉ ghi nhận ranh giới: exact match dùng khi biết đúng tên, wildcard dùng khi muốn nhóm theo prefix/suffix.

7

Project Không Tồn Tại — Error Message

Khi truyền tên project không có trong config, Playwright báo lỗi và dừng ngay — không silent fallback chạy hết:

npx playwright test --project=safari
Error: Project(s) "safari" not found. Available projects: "chromium", "firefox", "webkit"

Error message liệt kê sẵn các project hợp lệ — tiện debug khi làm việc với config lạ.

Với wildcard không match project nào:

npx playwright test --project='*opera*'
Error: No projects matched filter "*opera*". Available projects: "chromium", "firefox", "webkit"

Cả 2 trường hợp đều exit non-zero → CI pipeline nhận failure ngay, không lãng phí CI time chạy nhầm context.

8

Kết Hợp --project Với --grep

Hai flag hoạt động theo lớp độc lập, áp dụng AND:

  • --project: lọc project nào sẽ chạy.
  • --grep: lọc test nào (theo tên/tag) trong số project đã chọn.
# Chỉ smoke tests trên chromium
npx playwright test --project=chromium --grep="@smoke"

# Chỉ smoke tests trên chromium + firefox
npx playwright test --project=chromium --project=firefox --grep="@smoke"

# Test tên chứa "login" trên webkit
npx playwright test --project=webkit --grep="login"

Combine này hữu ích khi cần chạy nhanh nhất có thể: PR check chỉ smoke test trên 1 browser.

Thứ tự filter thực tế:

  1. Playwright chọn project theo --project.
  2. Trong số project đó, lọc test theo --grep.
  3. Nếu test còn lại = 0 → Playwright báo "0 tests found" và exit 0 (không phải error) — đây là edge case dễ bỏ sót trên CI.
# Edge case: combine không match test nào
npx playwright test --project=webkit --grep="@chrome-only"
# Output: 0 tests found. Exit code: 0
# → CI job "green" nhưng không chạy gì cả

Cần verify rằng combination có ít nhất 1 test trước khi dùng trên CI. Dùng --list để kiểm tra trước:

npx playwright test --list --project=webkit --grep="@smoke"
# In danh sách test sẽ match — nếu rỗng, combination cần xem lại
9

Sharding Interaction

--shard=M/N chia test theo file thành N phần đều, job M nhận phần M. Khi kết hợp với --project, phạm vi shard thay đổi:

# Không có --project: shard chia toàn bộ (tất cả project × tất cả file)
npx playwright test --shard=1/4

# Có --project: shard chỉ chia test của project đó
npx playwright test --project=chromium --shard=1/4

Ví dụ cụ thể: config 3 project, 60 test file. Không có --project:

Tổng: 3 × 60 = 180 test units
--shard=1/4 nhận khoảng 45 units (mix 3 project)

Với --project=chromium:

Chỉ 60 test units của chromium
--shard=1/4 nhận khoảng 15 units (chỉ chromium)

Pattern CI thường gặp: tách browser ra job riêng, rồi shard từng browser:

# GitHub Actions — shard theo browser
strategy:
  matrix:
    project: [chromium, firefox, webkit]
    shard: ["1/3", "2/3", "3/3"]
steps:
  - run: npx playwright test --project=${{ matrix.project }} --shard=${{ matrix.shard }}

Với matrix trên: 3 browser × 3 shard = 9 job song song. Lưu ý: tính toán shard phải dựa trên số test của project đó — không dùng số shard của toàn matrix. Nếu chromium có 60 file và webkit có 20 file, --shard=3/3 của webkit nhận ít test hơn đáng kể so với chromium — job webkit kết thúc nhanh, job chromium chậm hơn.

10

Reporter — Project Đã Filter

Khi dùng --project, reporter chỉ hiển thị project đã filter. Project không được chọn không xuất hiện trong output — không có dòng "skipped", không có cảnh báo:

npx playwright test --project=chromium
Running 3 tests using 1 worker

  ✓  [chromium] › login.spec.ts:5:5 › login flow (1.1s)
  ✓  [chromium] › cart.spec.ts:8:3 › add to cart (0.9s)
  ✓  [chromium] › checkout.spec.ts:12:1 › place order (1.4s)

3 passed (3.4s)

Không có dòng nào về firefox hoặc webkit. Đây là hành vi "filtered out" — khác với "skipped" (test được chọn nhưng bị skip bởi test.skip() hay test.fixme()).

HTML report (file playwright-report/index.html) cũng chỉ chứa test của project đã filter. Nếu cần merge report từ nhiều job (mỗi job 1 project), dùng npx playwright merge-reports — deep dive ở bài riêng về CI report strategy.

Trong summary cuối cùng, Playwright in rõ số test theo project:

3 passed (3.4s)
# Hoặc khi có nhiều project:
# 6 passed (4 chromium, 2 webkit)
11

CI Matrix Per-Project (GitHub Actions)

Pattern phổ biến nhất: 1 job = 1 browser. Tổng thời gian = max(thời gian 1 browser) thay vì sum:

# .github/workflows/playwright.yml
jobs:
  e2e:
    runs-on: ubuntu-latest
    strategy:
      fail-fast: false
      matrix:
        project: [chromium, firefox, webkit]
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with: { node-version: 22 }
      - run: npm ci
      - run: npx playwright install --with-deps ${{ matrix.project }}
      - run: npx playwright test --project=${{ matrix.project }}

Điểm cần chú ý:

  • fail-fast: false — 1 browser fail không cancel 2 job còn lại. Vẫn lấy được report từ cả 3 browser để biết regression ở đâu.
  • npx playwright install --with-deps ${{ matrix.project }} — chỉ tải binary của browser cần thiết. Nếu dùng --with-deps không có tên browser, tải cả 3 (tốn bandwidth và thời gian).
  • Mỗi job có HTML report riêng. Nếu cần 1 report gộp, cần artifact upload + merge job sau.

Khi config có setup project (login), cần xử lý riêng vì setup phải chạy trước test:

steps:
  - run: npm ci
  - run: npx playwright install --with-deps ${{ matrix.project }}
  # Chạy setup riêng trước
  - run: npx playwright test --project=setup
  # Chạy browser project, skip re-run setup
  - run: npx playwright test --project=${{ matrix.project }} --no-deps

Hoặc dùng artifact để share storageState giữa các job (upload sau setup, download trước test) — phù hợp khi setup project tốn nhiều thời gian.

12

4 Pitfalls

Pitfall 1: Typo tên project → error thay vì silent

Exact match case-sensitive dễ gây nhầm lẫn khi tên project chứa chữ hoa hoặc dấu gạch ngang:

npx playwright test --project=Chrome    # sai nếu config là 'chromium'
npx playwright test --project=mobile    # sai nếu config là 'mobile-chrome'

Playwright báo error với danh sách available — đọc error message để biết đúng tên, không đoán.

Pitfall 2: testMatch không khớp → silent skip

Đây là pitfall nguy hiểm nhất: project được chọn đúng, nhưng không có test nào match testMatch của project đó → Playwright chạy 0 test và exit 0 (không phải error):

// Config:
{
  name: 'smoke',
  testMatch: '**/smoke/**/*.spec.ts',
  use: { ...devices['Desktop Chrome'] },
}
npx playwright test --project=smoke
# Nếu không có file nào trong tests/smoke/:
# Output: "No tests found"
# Exit code: 0 → CI job "green" nhưng chẳng test gì

Cần verify test file tồn tại trước khi setup CI. Dùng --list để check trước khi commit workflow.

Pitfall 3: --project + --grep → empty run

Combine 2 filter quá hẹp dễ ra kết quả rỗng:

npx playwright test --project=webkit --grep="@chrome-only"
# webkit không có test nào có tag @chrome-only
# → 0 tests, exit 0, CI "green"

Trước khi đưa combination này vào CI, verify bằng --list. Nếu kết quả rỗng là expected (ví dụ branch không có smoke test), thêm check riêng thay vì dựa vào exit code.

Pitfall 4: Nhầm phạm vi shard khi combine

Khi đã filter --project=chromium, shard chia trên phạm vi chromium — không phải toàn matrix:

# Config 3 project, mỗi project 60 file = 180 units
# Không có --project:
npx playwright test --shard=1/6
# Mỗi shard nhận ~30 units (mix browser)

# Có --project:
npx playwright test --project=chromium --shard=1/6
# Mỗi shard nhận ~10 units (chỉ chromium 60 file / 6 shard)
# 5 shard còn lại của chromium cũng chỉ ~10 units
# firefox và webkit không chạy gì trong setup này

Nếu muốn shard toàn matrix (cả 3 browser), không truyền --project. Nếu muốn shard từng browser riêng, cần tính số shard theo số test của browser đó, không theo tổng matrix.

13

Quiz + Bài Tiếp

Quiz

1. Config có project setupe2e với dependencies: ['setup']. Khi chạy npx playwright test --project=e2e, setup có chạy không? Còn --project=e2e --no-deps thì sao?

Đáp án

Lệnh 1: setup chạy trước rồi mới đến e2e — Playwright tự resolve dependency chain. Không cần truyền thêm flag nào.

Lệnh 2: chỉ e2e chạy, setup bị skip. Nếu storageState đã tồn tại và còn hợp lệ → e2e chạy bình thường. Nếu chưa có hoặc expired → test cần auth sẽ fail với lỗi không liên quan đến auth (redirect, 401, element not found).

2. Chạy npx playwright test --project=chromium --grep="@smoke" trả về "0 tests found". Exit code là gì? CI pipeline xử lý thế nào?

Đáp án

Exit code là 0 — "0 tests found" không phải failure. CI job sẽ "green" dù không chạy test nào. Đây là trường hợp nguy hiểm: pipeline pass nhưng không verify gì. Cần verify combination có ít nhất 1 test bằng --list trước khi đưa vào CI, hoặc thêm check riêng nếu 0 test là unexpected.

3. Config 2 project chromium và firefox, cả 2 depend vào project setup. Lệnh npx playwright test --project=chromium --project=firefox sẽ chạy setup mấy lần?

Đáp án

1 lần — Playwright chạy setup 1 lần dù nhiều project depend vào nó. Sau khi setup xong, chromium và firefox chạy song song. Đây là behavior quan trọng: không lo setup chạy N lần theo số project.

4. Lệnh npx playwright test --project=chromium --shard=1/4 với config có 3 project (chromium 60 file, firefox 60 file, webkit 60 file). Shard 1/4 nhận bao nhiêu test units?

Đáp án

Khoảng 15 units — shard chia trên phạm vi 60 file của chromium (đã filter bằng --project), không phải 180 file của toàn matrix. 60 / 4 = 15 file mỗi shard. Firefox và webkit không được chạy trong lệnh này.

5. Trong GitHub Actions matrix, tại sao cần fail-fast: false khi chạy 3 browser song song?

Đáp án

Mặc định fail-fast: true — khi 1 job fail, GitHub Actions cancel tất cả job còn lại. Với browser matrix, nếu webkit fail thì chromium và firefox job bị cancel trước khi xong. Không thu thập được report đủ để biết regression chỉ ở webkit hay còn ở browser khác. fail-fast: false cho 3 job chạy độc lập đến khi xong, kể cả khi 1 job fail.

Bài Tiếp Theo

Bài 61: CLI --project Wildcard Pattern