Trong bài viết này, mình rất hào hứng được giới thiệu với các bạn về SafeTest - một thư viện cách mạng mang đến một góc nhìn mới mẻ về các bài kiểm thử End-To-End (E2E) cho các ứng dụng giao diện người dùng (UI) trên nền web.
Những thách thức của kiểm thử UI truyền thống
Truyền thống, các bài kiểm thử UI thường được thực hiện thông qua unit test hoặc integration test (còn được gọi là kiểm thử End-To-End). Tuy nhiên, mỗi phương pháp này đều có những đánh đổi riêng: bạn phải lựa chọn giữa việc kiểm soát fixture và setup của bài test, hoặc kiểm soát test driver.
Ví dụ, khi sử dụng react-testing-library - một giải pháp unit test, bạn có toàn quyền kiểm soát những gì sẽ render và cách các service, import bên dưới hoạt động như thế nào. Nhưng bạn sẽ mất khả năng tương tác với một trang thực tế, điều này có thể dẫn đến vô vàn các điểm đau đớn:
-
Khó khăn trong việc tương tác với các thành phần UI phức tạp như dropdown, modal, drag & drop, v.v. Bạn phải mô phỏng các hành vi này một cách thủ công.
-
Không thể kiểm tra các tác động phụ như network requests, local storage, cookies. Bạn phải giả lập chúng một cách tay chân.
-
Khó khăn trong việc kiểm tra các tính năng liên quan đến điều hướng như routing, redirects.
-
Không thể bắt các lỗi liên quan đến trình duyệt như lỗi JavaScript, các vấn đề về hiệu suất, tương thích.
Mặt khác, khi sử dụng các công cụ E2E như Cypress hay Playwright, bạn có thể dễ dàng tương tác với một trang thực tế và bắt được mọi tác động phụ. Nhưng bạn lại mất đi sự kiểm soát về việc render những gì và cách ứng dụng được thiết lập. Điều này có thể gây ra:
-
Các bài test chậm và không ổn định do phụ thuộc vào môi trường, dữ liệu và các dịch vụ bên ngoài. Một sự thay đổi nhỏ trong backend có thể phá vỡ nhiều bài test.
-
Khó debug khi các bài test thất bại, vì bạn không biết chính xác nguyên nhân là do frontend hay backend.
-
Khó viết các bài test với nhiều trường hợp khác nhau, vì mỗi bài test đều phải thao tác trên toàn bộ ứng dụng.
-
Không thể test các luồng xử lý phức tạp liên quan đến nhiều request bất đồng bộ.
SafeTest - Kết hợp những điểm mạnh của Unit Test và E2E Test
SafeTest sinh ra nhằm mục đích kết hợp những ưu điểm của cả unit test và E2E test, đồng thời khắc phục những nhược điểm của chúng. Với SafeTest, bạn vừa có thể kiểm soát những gì được render, vừa có thể tương tác với một trang thực sự.
Về cơ bản, SafeTest cung cấp một môi trường giả lập trình duyệt (browser-like environment) được tích hợp sẵn với các công cụ kiểm thử như Jest. Môi trường này cho phép bạn mount bất kỳ component React nào, giống như cách bạn làm với react-testing-library. Nhưng khác ở chỗ, component của bạn được render bên trong một iframe thực sự, tương tự như cách nó được hiển thị trong một tab trình duyệt.
import { render, screen, fireEvent } from 'safetest'; test('my test', async () => { render(<MyComponent />); // Tương tác với component bằng các query và event của testing-library const button = screen.getByText('Click me'); fireEvent.click(button); // Kiểm tra kết quả bằng các assertion của Jest expect(screen.getByText('Button clicked')).toBeInTheDocument();
});
Với cách tiếp cận này, SafeTest mang lại những lợi ích sau:
-
Bạn có thể kiểm tra component một cách đơn lẻ, độc lập với phần còn lại của ứng dụng. Điều này giúp các bài test chạy nhanh hơn và dễ debug hơn.
-
Bạn có toàn quyền setup môi trường test, mock các module phụ thuộc, và kiểm soát chính xác những gì được render. Điều này giúp các bài test trở nên đáng tin cậy và ổn định hơn.
-
Đồng thời, component của bạn được render trong một môi trường giống như thật, cho phép bạn tương tác với nó một cách tự nhiên thông qua các event như click, input, v.v. Bạn cũng có thể quan sát các side effect như network request, cookie, local storage.
-
Ngoài ra, SafeTest còn tích hợp sẵn các công cụ để giả lập API request và response, giúp bạn dễ dàng test các luồng bất đồng bộ phức tạp.
import { render, screen, fireEvent, waitFor } from 'safetest';
import { setupServer } from 'msw/node';
import { rest } from 'msw'; const server = setupServer( rest.get('/api/data', (req, res, ctx) => { return res(ctx.json({ name: 'John' })) }),
) beforeAll(() => server.listen())
afterAll(() => server.close()) test('my async test', async () => { render(<MyComponent />); fireEvent.click(screen.getByText('Load data')); await waitFor(() => screen.getByText('John'));
});
Kết luận
SafeTest là một sự bổ sung đáng giá cho hệ sinh thái công cụ kiểm thử front-end. Nó kết hợp sức mạnh của unit test và E2E test, cho phép chúng ta viết các bài test vừa đáng tin cậy, vừa linh hoạt và dễ bảo trì. Với SafeTest, việc kiểm thử các ứng dụng React trở nên dễ dàng và hiệu quả hơn bao giờ hết.
Các tính năng chính của SafeTest bao gồm:
- Render component React trong môi trường giả lập trình duyệt
- Tương tác với component bằng các công cụ của testing-library
- Hỗ trợ đầy đủ các assertion và tiện ích của Jest
- Dễ dàng mock các module và API request
- Chạy song song và tích hợp với các framework CI/CD phổ biến
Nếu bạn là một lập trình viên React và đang tìm kiếm một giải pháp kiểm thử hiệu quả, thì SafeTest chắc chắn là một lựa chọn đáng cân nhắc. Hãy thử dùng SafeTest cho dự án tiếp theo của bạn và cảm nhận sự khác biệt nhé!