Hướng dẫn toàn diện về Cypress, framework kiểm thử end-to-end mạnh mẽ, bao gồm cài đặt, viết test, gỡ lỗi, tích hợp CI/CD và các phương pháp hay nhất.
Cypress: Hướng Dẫn Toàn Diện về Kiểm Thử End-to-End cho Ứng Dụng Web
Trong bối cảnh phát triển web đang phát triển nhanh chóng ngày nay, việc đảm bảo chất lượng và độ tin cậy của các ứng dụng web là vô cùng quan trọng. Kiểm thử End-to-End (E2E) đóng một vai trò quan trọng trong việc xác minh rằng tất cả các thành phần của một ứng dụng hoạt động liền mạch với nhau từ góc độ của người dùng. Cypress đã nổi lên như một framework kiểm thử E2E hàng đầu, mang lại trải nghiệm thân thiện với nhà phát triển, các tính năng mạnh mẽ và hiệu suất xuất sắc. Hướng dẫn toàn diện này sẽ dẫn dắt bạn qua mọi thứ cần biết để bắt đầu với Cypress và kiểm thử hiệu quả các ứng dụng web của bạn.
Cypress là gì?
Cypress là một công cụ kiểm thử front-end thế hệ mới được xây dựng cho web hiện đại. Không giống như các framework kiểm thử truyền thống chạy thử nghiệm trong một trình duyệt, Cypress hoạt động trực tiếp trong trình duyệt, cho phép bạn kiểm soát và có cái nhìn sâu sắc chưa từng có về hành vi của ứng dụng. Nó được thiết kế để nhanh, đáng tin cậy và dễ sử dụng, khiến nó trở thành lựa chọn phổ biến của các nhà phát triển và kỹ sư QA trên toàn thế giới. Cypress được viết bằng JavaScript và thực thi bên trong trình duyệt, giúp nó có hiệu suất rất cao và cung cấp quyền truy cập tuyệt vời vào các thành phần bên trong của ứng dụng.
Các lợi ích chính khi sử dụng Cypress
- Thân thiện với Lập trình viên: Cypress cung cấp một API sạch sẽ và trực quan, giúp việc viết và gỡ lỗi các bài kiểm thử trở nên dễ dàng.
- Du hành thời gian: Cypress chụp lại các ảnh tức thời (snapshots) về trạng thái ứng dụng của bạn trong mỗi lệnh kiểm thử, cho phép bạn quay ngược thời gian và xem chính xác những gì đã xảy ra tại bất kỳ thời điểm nào.
- Tải lại theo thời gian thực: Cypress tự động tải lại khi bạn thay đổi các bài kiểm thử của mình, cung cấp phản hồi tức thì.
- Tự động chờ: Cypress tự động chờ các phần tử trở nên hiển thị hoặc có thể tương tác trước khi thực hiện các hành động, loại bỏ sự cần thiết của việc chờ đợi tường minh.
- Kiểm soát Mạng: Cypress cho phép bạn giả lập (stub) các yêu cầu và phản hồi mạng, cho phép bạn mô phỏng các kịch bản khác nhau và kiểm tra khả năng xử lý lỗi của ứng dụng.
- Khả năng Gỡ lỗi: Cypress cung cấp các công cụ gỡ lỗi xuất sắc, bao gồm một trình gỡ lỗi mạnh mẽ và các thông báo lỗi chi tiết.
- Kiểm thử Đa trình duyệt: Cypress hỗ trợ nhiều trình duyệt, bao gồm Chrome, Firefox, Edge và Electron.
- Kiểm thử không giao diện (Headless): Chạy các bài kiểm thử ở chế độ headless để thực thi nhanh hơn trong môi trường CI/CD.
- Assertion tích hợp sẵn: Cypress cung cấp một bộ phong phú các assertion tích hợp sẵn để xác minh hành vi mong đợi của ứng dụng.
Cài đặt và Thiết lập
Bắt đầu với Cypress rất đơn giản. Dưới đây là cách cài đặt nó:
- Điều kiện tiên quyết: Đảm bảo bạn đã cài đặt Node.js và npm (Node Package Manager) trên hệ thống của mình. Bạn có thể tải chúng từ trang web chính thức của Node.js.
- Cài đặt Cypress: Mở terminal hoặc command prompt của bạn, điều hướng đến thư mục dự án và chạy lệnh sau:
- Mở Cypress: Sau khi cài đặt hoàn tất, bạn có thể mở Cypress Test Runner bằng cách chạy:
npm install cypress --save-dev
npx cypress open
Lệnh này sẽ khởi chạy Cypress Test Runner, cung cấp một giao diện đồ họa để chạy và gỡ lỗi các bài kiểm thử của bạn.
Viết bài kiểm thử Cypress đầu tiên của bạn
Hãy tạo một bài kiểm thử đơn giản để xác minh rằng trang chủ của một trang web tải đúng. Tạo một tệp mới có tên `example.cy.js` trong thư mục `cypress/e2e` của dự án của bạn.
// cypress/e2e/example.cy.js
describe('Bài kiểm thử đầu tiên của tôi', () => {
it('Truy cập Kitchen Sink', () => {
cy.visit('https://example.cypress.io')
cy.contains('type').click()
cy.url().should('include', '/commands/actions')
cy.get('.action-email')
.type('fake@email.com')
.should('have.value', 'fake@email.com')
})
})
Hãy phân tích bài kiểm thử này:
- `describe()`: Định nghĩa một bộ kiểm thử (test suite), là một tập hợp các bài kiểm thử liên quan.
- `it()`: Định nghĩa một trường hợp kiểm thử (test case) riêng lẻ trong bộ kiểm thử.
- `cy.visit()`: Điều hướng đến URL được chỉ định.
- `cy.contains()`: Tìm một phần tử chứa văn bản được chỉ định.
- `.click()`: Nhấp vào phần tử đã chọn.
- `cy.url()`: Lấy URL hiện tại của trang.
- `.should()`: Thực hiện một assertion về trạng thái của ứng dụng.
- `cy.get()`: Chọn một phần tử bằng CSS selector.
- `.type()`: Gõ văn bản vào phần tử đã chọn.
- `.should('have.value', 'fake@email.com')`: Khẳng định rằng giá trị của phần tử bằng 'fake@email.com'.
Chạy bài kiểm thử này trong Cypress Test Runner để xem nó hoạt động. Bạn sẽ thấy trình duyệt điều hướng đến trang web Cypress Kitchen Sink, nhấp vào liên kết "type" và xác minh URL.
Các lệnh Cypress
Cypress cung cấp một loạt các lệnh để tương tác với ứng dụng của bạn. Dưới đây là một số lệnh được sử dụng phổ biến nhất:
- `cy.visit(url)`: Điều hướng đến URL được chỉ định.
- `cy.get(selector)`: Chọn một phần tử bằng CSS selector.
- `cy.contains(content)`: Chọn một phần tử chứa văn bản được chỉ định.
- `cy.click()`: Nhấp vào phần tử đã chọn.
- `cy.type(text)`: Gõ văn bản vào phần tử đã chọn.
- `cy.clear()`: Xóa nội dung của một phần tử input hoặc textarea.
- `cy.submit()`: Gửi một biểu mẫu.
- `cy.check()`: Chọn một hộp kiểm hoặc nút radio.
- `cy.uncheck()`: Bỏ chọn một hộp kiểm.
- `cy.select(value)`: Chọn một tùy chọn từ danh sách thả xuống.
- `cy.scrollTo(position)`: Cuộn trang đến vị trí được chỉ định.
- `cy.trigger(event)`: Kích hoạt một sự kiện DOM trên phần tử đã chọn.
- `cy.request(url, options)`: Thực hiện một yêu cầu HTTP đến URL được chỉ định.
- `cy.intercept(route, handler)`: Chặn các yêu cầu HTTP khớp với tuyến đường được chỉ định.
- `cy.wait(time)`: Chờ trong một khoảng thời gian được chỉ định.
- `cy.reload()`: Tải lại trang hiện tại.
- `cy.go(direction)`: Điều hướng đến trang trước hoặc trang tiếp theo trong lịch sử trình duyệt.
- `cy.url()`: Lấy URL hiện tại của trang.
- `cy.title()`: Lấy tiêu đề của trang.
- `cy.window()`: Lấy đối tượng window.
- `cy.document()`: Lấy đối tượng document.
- `cy.viewport(width, height)`: Đặt kích thước viewport.
Đây chỉ là một vài trong số rất nhiều lệnh có sẵn trong Cypress. Hãy tham khảo tài liệu của Cypress để có danh sách đầy đủ các lệnh và tùy chọn của chúng.
Assertion trong Cypress
Assertion được sử dụng để xác minh hành vi mong đợi của ứng dụng của bạn. Cypress cung cấp một bộ phong phú các assertion tích hợp sẵn mà bạn có thể sử dụng để kiểm tra trạng thái của các phần tử, URL, tiêu đề, và nhiều hơn nữa. Các assertion được nối chuỗi sau các lệnh Cypress bằng phương thức `.should()`.
Dưới đây là một số ví dụ assertion phổ biến:
- `.should('be.visible')`: Khẳng định rằng một phần tử có thể nhìn thấy.
- `.should('not.be.visible')`: Khẳng định rằng một phần tử không thể nhìn thấy.
- `.should('be.enabled')`: Khẳng định rằng một phần tử được bật.
- `.should('be.disabled')`: Khẳng định rằng một phần tử bị vô hiệu hóa.
- `.should('have.text', 'expected text')`: Khẳng định rằng một phần tử có văn bản được chỉ định.
- `.should('contain', 'expected text')`: Khẳng định rằng một phần tử chứa văn bản được chỉ định.
- `.should('have.value', 'expected value')`: Khẳng định rằng một phần tử có giá trị được chỉ định.
- `.should('have.class', 'expected class')`: Khẳng định rằng một phần tử có lớp được chỉ định.
- `.should('have.attr', 'attribute name', 'expected value')`: Khẳng định rằng một phần tử có thuộc tính và giá trị được chỉ định.
- `.should('have.css', 'css property', 'expected value')`: Khẳng định rằng một phần tử có thuộc tính CSS và giá trị được chỉ định.
- `.should('have.length', expected length)`: Khẳng định rằng một phần tử có độ dài được chỉ định (ví dụ: số lượng phần tử trong một danh sách).
Bạn cũng có thể tạo các assertion tùy chỉnh để phù hợp với nhu cầu cụ thể của mình.
Các phương pháp tốt nhất để viết Test Cypress
Việc tuân theo các phương pháp tốt nhất có thể giúp bạn viết các bài kiểm thử Cypress dễ bảo trì, đáng tin cậy và hiệu quả hơn. Dưới đây là một số khuyến nghị:
- Viết các bài kiểm thử rõ ràng và ngắn gọn: Mỗi bài kiểm thử nên tập trung vào một chức năng hoặc kịch bản cụ thể. Tránh viết các bài kiểm thử quá phức tạp, khó hiểu và khó bảo trì.
- Sử dụng tên kiểm thử có ý nghĩa: Đặt cho các bài kiểm thử của bạn những cái tên mô tả rõ ràng chúng đang kiểm thử điều gì.
- Tránh hard-code giá trị: Sử dụng biến hoặc tệp cấu hình để lưu trữ các giá trị có thể thay đổi theo thời gian.
- Sử dụng các lệnh tùy chỉnh: Tạo các lệnh tùy chỉnh để đóng gói logic có thể tái sử dụng và làm cho các bài kiểm thử của bạn dễ đọc hơn.
- Cách ly các bài kiểm thử: Mỗi bài kiểm thử phải độc lập với các bài kiểm thử khác. Tránh phụ thuộc vào trạng thái của ứng dụng từ các bài kiểm thử trước đó.
- Dọn dẹp sau các bài kiểm thử: Đặt lại trạng thái của ứng dụng sau mỗi bài kiểm thử để đảm bảo rằng các bài kiểm thử tiếp theo bắt đầu từ một trạng thái sạch.
- Sử dụng thuộc tính dữ liệu: Sử dụng các thuộc tính dữ liệu (ví dụ: `data-testid`) để chọn các phần tử trong bài kiểm thử của bạn. Các thuộc tính dữ liệu ít có khả năng thay đổi hơn các lớp CSS hoặc ID, giúp bài kiểm thử của bạn bền vững hơn trước những thay đổi trong giao diện người dùng.
- Tránh chờ đợi tường minh: Cypress tự động chờ các phần tử trở nên hiển thị hoặc có thể tương tác. Tránh sử dụng các lệnh chờ tường minh (ví dụ: `cy.wait()`) trừ khi thực sự cần thiết.
- Kiểm tra luồng người dùng: Tập trung vào việc kiểm tra các luồng người dùng thay vì các thành phần riêng lẻ. Điều này sẽ giúp bạn đảm bảo rằng ứng dụng của bạn hoạt động chính xác từ góc độ của người dùng.
- Chạy kiểm thử thường xuyên: Tích hợp các bài kiểm thử Cypress vào quy trình CI/CD của bạn và chạy chúng thường xuyên để phát hiện lỗi sớm trong quá trình phát triển.
Các kỹ thuật Cypress nâng cao
Stubbing và Mocking
Cypress cho phép bạn giả lập (stub) các yêu cầu và phản hồi mạng, cho phép bạn mô phỏng các kịch bản khác nhau và kiểm tra khả năng xử lý lỗi của ứng dụng. Điều này đặc biệt hữu ích để kiểm tra các tính năng phụ thuộc vào các API hoặc dịch vụ bên ngoài.
Để giả lập một yêu cầu mạng, bạn có thể sử dụng lệnh `cy.intercept()`. Ví dụ, đoạn mã dưới đây giả lập một yêu cầu GET đến `/api/users` và trả về một phản hồi giả:
cy.intercept('GET', '/api/users', {
statusCode: 200,
body: [
{ id: 1, name: 'John Doe' },
{ id: 2, name: 'Jane Doe' }
]
}).as('getUsers')
Sau đó, bạn có thể chờ yêu cầu bị chặn bằng `cy.wait('@getUsers')` và xác minh rằng ứng dụng của bạn xử lý phản hồi giả một cách chính xác.
Làm việc với Local Storage và Cookies
Cypress cung cấp các lệnh để tương tác với local storage và cookie. Bạn có thể sử dụng các lệnh này để đặt, lấy và xóa local storage và cookie trong các bài kiểm thử của mình.
Để đặt một mục trong local storage, bạn có thể sử dụng lệnh `cy.window()` để truy cập đối tượng window và sau đó sử dụng phương thức `localStorage.setItem()`. Ví dụ:
cy.window().then((win) => {
win.localStorage.setItem('myKey', 'myValue')
})
Để lấy một mục từ local storage, bạn có thể sử dụng lệnh `cy.window()` và sau đó sử dụng phương thức `localStorage.getItem()`. Ví dụ:
cy.window().then((win) => {
const value = win.localStorage.getItem('myKey')
expect(value).to.equal('myValue')
})
Để đặt một cookie, bạn có thể sử dụng lệnh `cy.setCookie()`. Ví dụ:
cy.setCookie('myCookie', 'myCookieValue')
Để lấy một cookie, bạn có thể sử dụng lệnh `cy.getCookie()`. Ví dụ:
cy.getCookie('myCookie').should('have.property', 'value', 'myCookieValue')
Xử lý Tải lên Tệp
Cypress cung cấp một plugin có tên `cypress-file-upload` giúp đơn giản hóa việc tải lên tệp trong các bài kiểm thử của bạn. Để cài đặt plugin, hãy chạy lệnh sau:
npm install -D cypress-file-upload
Sau đó, thêm dòng sau vào tệp `cypress/support/commands.js` của bạn:
import 'cypress-file-upload';
Sau đó, bạn có thể sử dụng lệnh `cy.uploadFile()` để tải lên một tệp. Ví dụ:
cy.get('input[type="file"]').attachFile('example.txt')
Làm việc với IFrame
Kiểm thử IFrame có thể phức tạp, nhưng Cypress cung cấp cách để tương tác với chúng. Bạn có thể sử dụng lệnh `cy.frameLoaded()` để chờ IFrame tải xong, và sau đó sử dụng lệnh `cy.iframe()` để lấy đối tượng document của IFrame.
cy.frameLoaded('#myIframe')
cy.iframe('#myIframe').find('button').click()
Cypress và Tích hợp Liên tục/Triển khai Liên tục (CI/CD)
Tích hợp Cypress vào quy trình CI/CD của bạn là điều cần thiết để đảm bảo chất lượng ứng dụng. Bạn có thể chạy các bài kiểm thử Cypress ở chế độ headless trong môi trường CI/CD của mình. Đây là cách thực hiện:
- Cài đặt Cypress: Đảm bảo Cypress được cài đặt như một dependency trong dự án của bạn.
- Cấu hình CI/CD: Cấu hình quy trình CI/CD của bạn để chạy các bài kiểm thử Cypress sau mỗi lần build.
- Chạy Cypress Headless: Sử dụng lệnh `cypress run` để chạy các bài kiểm thử Cypress ở chế độ headless.
Ví dụ cấu hình CI/CD (sử dụng GitHub Actions):
name: Cypress Tests
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
cypress-run:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: 16
- name: Install dependencies
run: npm install
- name: Cypress run
uses: cypress-io/github-action@v5
with:
start: npm start
wait-on: 'http://localhost:3000'
Cấu hình này sẽ chạy các bài kiểm thử Cypress bất cứ khi nào mã được đẩy lên nhánh `main` hoặc một pull request được tạo vào nhánh `main`. Action `cypress-io/github-action` đơn giản hóa quá trình chạy các bài kiểm thử Cypress trong GitHub Actions.
Gỡ lỗi Test Cypress
Cypress cung cấp các công cụ gỡ lỗi xuất sắc để giúp bạn xác định và khắc phục các sự cố trong bài kiểm thử của mình. Dưới đây là một số mẹo để gỡ lỗi các bài kiểm thử Cypress:
- Sử dụng Cypress Test Runner: Cypress Test Runner cung cấp một giao diện trực quan để chạy và gỡ lỗi các bài kiểm thử của bạn. Bạn có thể thực hiện từng bước qua các bài kiểm thử của mình, kiểm tra trạng thái của ứng dụng và xem các thông báo lỗi chi tiết.
- Sử dụng lệnh `cy.pause()`: Lệnh `cy.pause()` tạm dừng việc thực thi bài kiểm thử của bạn và cho phép bạn kiểm tra trạng thái của ứng dụng trong công cụ dành cho nhà phát triển của trình duyệt.
- Sử dụng lệnh `cy.debug()`: Lệnh `cy.debug()` in phần tử đã chọn ra console, cho phép bạn kiểm tra các thuộc tính của nó.
- Sử dụng Công cụ dành cho nhà phát triển của trình duyệt: Công cụ dành cho nhà phát triển của trình duyệt cung cấp rất nhiều thông tin về ứng dụng của bạn, bao gồm DOM, các yêu cầu mạng và nhật ký console.
- Đọc kỹ thông báo lỗi: Cypress cung cấp các thông báo lỗi chi tiết có thể giúp bạn xác định nguyên nhân của lỗi. Hãy chú ý đến thông báo lỗi và dấu vết ngăn xếp (stack trace).
Cypress so với các Framework Kiểm thử khác
Mặc dù Cypress là một framework kiểm thử end-to-end mạnh mẽ, việc hiểu nó so sánh với các lựa chọn phổ biến khác là điều cần thiết. Dưới đây là một cái nhìn tổng quan ngắn gọn:
- Selenium: Selenium là một framework kiểm thử tự động được sử dụng rộng rãi. Mặc dù linh hoạt và hỗ trợ nhiều ngôn ngữ, nó có thể phức tạp để thiết lập và bảo trì. Cypress cung cấp trải nghiệm đơn giản hơn và thân thiện với nhà phát triển hơn, đặc biệt đối với các ứng dụng dựa trên JavaScript.
- Puppeteer: Puppeteer là một thư viện Node cung cấp một API cấp cao để điều khiển Chrome hoặc Chromium không giao diện. Nó rất tuyệt vời cho việc scraping và tự động hóa các tác vụ trình duyệt nhưng có thể yêu cầu cấu hình thủ công nhiều hơn so với Cypress để kiểm thử end-to-end.
- Playwright: Playwright là một framework tự động hóa đa trình duyệt khác được phát triển bởi Microsoft. Nó có những điểm tương đồng với Puppeteer nhưng cung cấp hỗ trợ trình duyệt rộng hơn. Cypress có một trình gỡ lỗi du hành thời gian độc đáo và trải nghiệm kiểm thử tích hợp hơn.
Việc lựa chọn framework phụ thuộc vào nhu cầu và yêu cầu cụ thể của dự án của bạn. Cypress là một lựa chọn tuyệt vời cho các ứng dụng web hiện đại yêu cầu kiểm thử end-to-end nhanh, đáng tin cậy và thân thiện với nhà phát triển.
Ví dụ thực tế về Cypress trong hoạt động
Hãy khám phá một vài ví dụ thực tế về cách Cypress có thể được sử dụng để kiểm tra các loại ứng dụng web khác nhau:
Kiểm thử một ứng dụng Thương mại điện tử
Bạn có thể sử dụng Cypress để kiểm tra các luồng người dùng khác nhau trong một ứng dụng thương mại điện tử, chẳng hạn như:
- Tìm kiếm sản phẩm
- Thêm sản phẩm vào giỏ hàng
- Thanh toán và đặt hàng
- Quản lý cài đặt tài khoản
Đây là một ví dụ về bài kiểm thử Cypress xác minh rằng người dùng có thể thêm thành công một sản phẩm vào giỏ hàng của họ:
it('Thêm một sản phẩm vào giỏ hàng', () => {
cy.visit('/products')
cy.get('.product-card').first().find('button').click()
cy.get('.cart-count').should('have.text', '1')
})
Kiểm thử một ứng dụng Mạng xã hội
Bạn có thể sử dụng Cypress để kiểm tra các tương tác của người dùng trong một ứng dụng mạng xã hội, chẳng hạn như:
- Tạo một bài đăng mới
- Thích một bài đăng
- Bình luận về một bài đăng
- Theo dõi những người dùng khác
Đây là một ví dụ về bài kiểm thử Cypress xác minh rằng người dùng có thể tạo thành công một bài đăng mới:
it('Tạo một bài đăng mới', () => {
cy.visit('/profile')
cy.get('#new-post-textarea').type('Chào, thế giới!')
cy.get('#submit-post-button').click()
cy.get('.post').first().should('contain', 'Chào, thế giới!')
})
Kiểm thử một ứng dụng Ngân hàng
Đối với các ứng dụng ngân hàng, Cypress có thể được sử dụng để kiểm tra các chức năng quan trọng như:
- Đăng nhập an toàn
- Kiểm tra số dư tài khoản
- Chuyển tiền
- Quản lý người thụ hưởng
Một bài kiểm thử để xác minh việc chuyển tiền có thể trông như thế này (với việc giả lập phù hợp để bảo mật):
it('Chuyển tiền thành công', () => {
cy.visit('/transfer')
cy.get('#recipient-account').type('1234567890')
cy.get('#amount').type('100')
cy.intercept('POST', '/api/transfer', { statusCode: 200, body: { success: true } }).as('transfer')
cy.get('#transfer-button').click()
cy.wait('@transfer')
cy.get('.success-message').should('be.visible')
})
Kết luận
Cypress là một framework kiểm thử end-to-end mạnh mẽ và linh hoạt có thể giúp bạn đảm bảo chất lượng và độ tin cậy của các ứng dụng web của mình. API thân thiện với nhà phát triển, các tính năng mạnh mẽ và hiệu suất xuất sắc của nó làm cho nó trở thành một lựa chọn phổ biến của các nhà phát triển và kỹ sư QA trên toàn thế giới. Bằng cách tuân theo các phương pháp tốt nhất được nêu trong hướng dẫn này, bạn có thể viết các bài kiểm thử Cypress hiệu quả sẽ giúp bạn phát hiện lỗi sớm trong quá trình phát triển và cung cấp phần mềm chất lượng cao cho người dùng của mình.
Khi các ứng dụng web tiếp tục phát triển, tầm quan trọng của việc kiểm thử end-to-end sẽ chỉ tăng lên. Việc áp dụng Cypress và tích hợp nó vào quy trình phát triển của bạn sẽ giúp bạn xây dựng các trải nghiệm web mạnh mẽ, đáng tin cậy và thân thiện với người dùng hơn.