5 phút để có bản demo chạy được
Thay vì sa đà vào mớ lý thuyết khô khan, chúng ta sẽ bắt tay vào làm luôn để thấy kết quả ngay lập tức. Cypress cực kỳ dễ tiếp cận. Nó không yêu cầu cài đặt driver phức tạp hay cấu hình rườm rà như Selenium trước đây.
Đầu tiên, bạn hãy tạo một thư mục mới và khởi tạo project bằng vài lệnh đơn giản:
mkdir cypress-demo && cd cypress-demo
npm init -y
npm install cypress --save-dev
Sau khi cài đặt xong, hãy khởi động giao diện điều khiển của Cypress:
npx cypress open
Một cửa sổ trực quan sẽ hiện ra. Bạn hãy chọn E2E Testing rồi nhấn Continue để Cypress tự động khởi tạo các file cấu hình cần thiết. Tiếp theo, hãy chọn trình duyệt yêu thích (như Chrome hoặc Edge) và nhấn Start E2E Testing.
Bây giờ, hãy tạo file test đầu tiên tại đường dẫn cypress/e2e/first_test.cy.js:
describe('My First Test', () => {
it('Truy cập itfromzero.com và kiểm tra tiêu đề', () => {
cy.visit('https://itfromzero.com')
cy.contains('Development').should('be.visible')
})
})
Quay lại giao diện Cypress và click vào file vừa tạo. Bạn sẽ thấy trình duyệt tự động mở ra, truy cập web và kiểm tra phần tử trong tích tắc. Vậy là bạn đã hoàn thành bản test E2E đầu tiên rồi đấy!
Tại sao Cypress lại vượt trội hơn các công cụ cũ?
Tôi từng tham gia refactor một hệ thống cũ với hơn 50,000 dòng code. Bài học đắt giá nhất lúc đó là nếu không có test coverage tốt, việc sửa logic cũ chẳng khác nào đi trên dây. Thời điểm dùng Selenium, đội của tôi thường xuyên đau đầu vì lỗi “flaky test” – test lúc chạy được lúc không do các phần tử chưa kịp load.
Cypress đã thay đổi hoàn toàn cuộc chơi nhờ 3 tính năng đáng tiền:
- Automatic Waiting: Bạn không cần phải dùng
time.sleep(5)một cách cảm tính nữa. Cypress sẽ tự động đợi cho đến khi element xuất hiện hoặc đạt trạng thái mong muốn. - Real-time Reloads: Ngay khi bạn nhấn Ctrl+S để lưu code test, Cypress sẽ tự động chạy lại. Quy trình debug nhờ đó trở nên cực kỳ nhanh chóng.
- Time Travel: Tính năng này cho phép bạn hover vào từng dòng lệnh đã chạy để xem lại trạng thái của UI tại đúng thời điểm đó. Nó giống như một cuốn băng ghi hình chi tiết vậy.
Cấu trúc một bộ test chuyên nghiệp
Khi dự án mở rộng lên hàng trăm test case, việc tổ chức thư mục khoa học là yếu tố sống còn. Một cấu trúc chuẩn thường bao gồm:
cypress/e2e/: Nơi chứa các kịch bản kiểm thử. Đây là trái tim của toàn bộ quy trình.cypress/fixtures/: Lưu trữ dữ liệu tĩnh như JSON. Ví dụ: thông tin user mẫu hoặc danh sách sản phẩm để mock API.cypress/support/: Nơi định nghĩa các Custom Commands. Thay vì lặp lại code đăng nhập ở 100 file khác nhau, bạn chỉ cần viết một lệnhcy.login()dùng chung.
Kịch bản thực tế: Kiểm thử luồng Đăng nhập
Đừng chỉ test trường hợp người dùng nhập đúng. Một bộ test chất lượng cần bao phủ cả các tình huống nhập sai hoặc để trống thông tin.
describe('Tính năng Đăng nhập', () => {
beforeEach(() => {
cy.visit('/login') // Base URL được cấu hình tập trung trong cypress.config.js
})
it('Hiển thị thông báo lỗi khi để trống mật khẩu', () => {
cy.get('input[name="email"]').type('[email protected]')
cy.get('button[type="submit"]').click()
cy.get('.error-message').should('contain', 'Mật khẩu không được để trống')
})
it('Chuyển hướng thành công với tài khoản hợp lệ', () => {
cy.get('input[name="email"]').type('[email protected]')
cy.get('input[name="password"]').type('password123')
cy.get('button[type="submit"]').click()
cy.url().should('include', '/dashboard')
cy.get('h1').should('contain', 'Chào mừng Admin')
})
})
Kỹ thuật Mock API với cy.intercept()
Đây là vũ khí bí mật giúp test của bạn chạy ổn định 100%. Đôi khi Backend đang bảo trì hoặc API bên thứ ba (như cổng thanh toán) phản hồi rất chậm. Cypress cho phép bạn “đánh chặn” các request này và trả về dữ liệu giả ngay lập tức.
it('Mock danh sách bài viết từ API', () => {
cy.intercept('GET', '/api/posts', { fixture: 'posts.json' }).as('getPosts')
cy.visit('/blog')
cy.wait('@getPosts')
cy.get('.post-item').should('have.length', 3)
})
Cách tiếp cận này giúp giảm thời gian chạy test từ vài phút xuống còn vài giây vì không phải chờ server thực xử lý.
Tự động hóa với GitHub Actions
Để đảm bảo không ai vô tình merge code lỗi, bạn cần đưa Cypress vào pipeline CI/CD. Việc này giúp hệ thống tự động kiểm tra code mỗi khi có ai đó tạo Pull Request.
Dưới đây là file cấu hình .github/workflows/main.yml đơn giản:
name: E2E Tests
on: [push]
jobs:
cypress-run:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Chạy Cypress
uses: cypress-io/github-action@v6
with:
build: npm run build
start: npm start
wait-on: 'http://localhost:3000'
Nếu bất kỳ test case nào thất bại, GitHub sẽ báo đỏ và ngăn chặn việc deploy, giúp bảo vệ môi trường Production của bạn luôn an toàn.
Kinh nghiệm thực chiến để tránh “vỡ trận”
Sau hơn 6 tháng áp dụng Cypress vào dự án thực tế, tôi đã rút ra được 4 quy tắc vàng:
- Ưu tiên dùng data-cy: Đừng bao giờ select element bằng class CSS (như
.btn-blue) vì chúng rất dễ thay đổi khi bạn refactor giao diện. Hãy dùngdata-cy="submit-button"để bộ test luôn bền vững. - Tuyệt đối tránh cy.wait(số_giây): Việc bắt script dừng lại 3-5 giây là cách nhanh nhất làm chậm dự án. Hãy dùng timeout linh hoạt hoặc đợi theo alias của API.
- Cô lập trạng thái (State): Mỗi test case nên là một thực thể độc lập. Hãy reset database hoặc xóa cookies ở
beforeEachđể đảm bảo test case trước không làm ảnh hưởng đến test case sau. - Tối ưu tài nguyên CI: Khi chạy trên server, hãy luôn dùng chế độ Headless (không giao diện). Điều này giúp tiết kiệm đáng kể RAM và CPU cho hệ thống CI.
Cypress không chỉ là một công cụ kiểm thử. Nó là giải pháp giúp developer ngủ ngon hơn trước mỗi kỳ release. Nếu bạn đang xây dựng ứng dụng web, hãy thử tích hợp nó ngay hôm nay.
Bạn có đang gặp khó khăn khi cấu hình Cypress trên Docker hay Next.js không? Hãy chia sẻ vấn đề của bạn ở phần bình luận bên dưới nhé!

