Môi trường kiểm thử

Như đã giới thiệu trong phần Kiểm thử là gì, về cơ bản, kiểm thử trong JavaScript chỉ là mã mà chúng tôi xác nhận là đã chạy thành công, tức là không cần gửi Error. Tuy nhiên, một trong những cách định nghĩa này là sự đơn giản hoá quá mức là không xem xét nơi chúng tôi chạy mã, đó là môi trường kiểm thử của mã.

Môi trường kiểm thử thường được coi là 2 thành phần: môi trường thời gian chạy bạn sử dụng để chạy kiểm thử (chẳng hạn như Nút hoặc trình duyệt) cũng như các API có sẵn cho bạn.

Môi trường thời gian chạy

Các thời gian chạy như Node hoặc các công cụ tương tự như Deno hoặc Bun, đều nhằm mục đích hỗ trợ mã JS phía máy chủ hoặc mã JS đa năng. Môi trường của chúng không bao gồm những API mà bạn có thể mong đợi trong trình duyệt, chẳng hạn như tạo và làm việc với các phần tử DOM và HTML, cũng như bất kỳ khái niệm nào về thành phần hình ảnh hoặc mục tiêu hiển thị (tức là, không chỉ các phần tử, mà hiển thị các phần tử đó một cách trực quan bằng CSS cho một khung nhìn).

Do đó, các môi trường thời gian chạy đa năng này sẽ không thành công nếu bạn cố gắng kết xuất các phần tử React để có thể kiểm thử chúng vì không có đối tượng document hoặc window.

Mặt khác, nếu bạn chạy kiểm thử bên trong một trình duyệt, thì các API tích hợp mà bạn có thể mong đợi từ các môi trường thời gian chạy này có thể không hoạt động nếu không sử dụng tính năng polyfilling hoặc một số thao tác bổ sung. Một khái niệm phổ biến là đọc và ghi tệp: bạn không thể import { fs } from 'node:'fs'; bên trong trình duyệt và đọc tệp theo cách này trong quá trình kiểm thử.

Vấn đề API "web" so với "phần phụ trợ" này nằm ngoài phạm vi kiểm thử, bởi có thể khó hiểu khi có cơ sở mã với cả phần máy chủ và phần máy khách, nhưng nó liên quan đến ý tưởng viết mã có thể kiểm thử. Chúng ta sẽ xem lại trong suốt khoá học này.

Kiểm thử logic kinh doanh hoặc thuật toán

Một số mã của bạn sẽ không yêu cầu nhập Nút hoặc trình duyệt để hoạt động và do đó, để kiểm tra. Đây là nội dung mà chúng ta sẽ đề cập sau trong khoá học này, nhưng việc cấu trúc cơ sở mã sao cho "logic kinh doanh" thuần tuý đó tách biệt với việc kết xuất hoặc mã dành riêng cho nút có thể giúp bạn dễ dàng kiểm thử hơn.

Để xem ví dụ nhanh, bạn có thể có một hàm Nút đọc và ghi tệp từ ổ đĩa, sửa đổi tệp đó trong quá trình này. Bằng cách tái cấu trúc hàm để chấp nhận các hàm thực hiện việc đọc và ghi từ ổ đĩa, bạn đã cho phép kiểm thử ở bất cứ đâu.

Trong trường hợp này, bạn có thể sử dụng bất kỳ môi trường nào để kiểm thử mã này, trong thời gian chạy phía máy chủ hoặc trình duyệt. Trong kiểm thử, bạn có thể cung cấp các trình trợ giúp lưu trữ tệp ảo trong bộ nhớ hoặc trả về dữ liệu giữ chỗ. Bạn có thể giới thiệu loại trình trợ giúp này trong quá trình kiểm thử, vì việc kiểm tra xem fs.writeFileSync có hoạt động hay không thì không quan trọng. Tập trung vào mã của bạn và những điều khiến mã đó độc đáo hoặc có rủi ro.

Mô phỏng API trình duyệt

Nhiều khung kiểm thử, chẳng hạn như Vitest, cung cấp cho bạn một tuỳ chọn mô phỏng môi trường API của trình duyệt mà không cần chạy trình duyệt. Vitest sử dụng nội bộ một thư viện có tên là JSDOM. Đây có thể là lựa chọn tốt cho các kiểm thử thành phần đơn giản có mức hao tổn cao khi sử dụng trình duyệt.

Một đặc điểm phổ biến của thư viện mô phỏng bất kỳ là mặc dù có thể mô phỏng một trình duyệt (ví dụ: DOM, các phần tử và cookie) nhưng chúng không có thành phần hình ảnh. Điều này có nghĩa là các phần tử này sẽ cung cấp một cách bắt buộc để làm việc với các phần tử HTML và các dữ liệu gốc khác, nhưng bạn không thể kết xuất đầu ra cho hình ảnh hay màn hình, hoặc kiểm tra vị trí của phần tử tính bằng pixel trên trang.

Xin nhắc lại, lựa chọn này có thể phù hợp với kiểm thử thành phần, trong đó một thành phần đại diện cho một phần tử React hoặc Thành phần web, v.v. Các loại thành phần này thường tạo và tương tác với DOM theo một cách tương đối nhỏ và trình duyệt được mô phỏng có thể cung cấp đủ chức năng để xác nhận thành phần hoạt động theo cách bạn muốn. Phần sắp tới có ví dụ về một bài kiểm thử thành phần Phản ứng bằng Vitest và JSDOM.

Mô phỏng trình duyệt là một phương pháp phổ biến — JSDOM được phát hành vào năm 2014 — nhưng việc mô phỏng trình duyệt sẽ luôn khác với việc sử dụng một trình duyệt thực. Những điểm khác biệt này có thể rõ ràng: ví dụ: JSDOM không bao gồm công cụ bố cục, vì vậy, không có cách nào để kiểm tra kích thước của một phần tử hay kiểm thử một cử chỉ phức tạp như vuốt. Sự khác biệt cũng có thể nhỏ và không xác định. Do đó, tốt nhất bạn nên giữ cho các thử nghiệm dựa trên JSDOM ngắn gọn để có thể "đặt hộp thời gian" trước nguy cơ bất kỳ hành vi nào khác biệt so với thực tế.

Điều khiển một trình duyệt thực

Để kiểm thử mã của bạn theo cách người dùng sẽ trải nghiệm, thì tốt nhất là bạn nên sử dụng trình duyệt thực tế. Trong thực tế, việc kiểm thử các môi trường thời gian chạy hỗ trợ trình duyệt sẽ khởi động và kiểm soát các phiên bản của một trình duyệt thực tế, ngay cả khi chúng chạy "start" ("bắt đầu") bên trong Node.js.

Việc kiểm soát trình duyệt trong quá trình kiểm thử có nghĩa là trình duyệt sẽ mở giống như người dùng, cho phép kiểm thử kiểm soát trình duyệt bằng cách tải các URL, HTML và JS tuỳ chỉnh hoặc bất kỳ nội dung nào cần thiết để thực hiện kiểm thử. Sau đó, bạn có thể viết mã để hành động với tư cách người dùng, chẳng hạn như bằng cách điều khiển chuột hoặc nhập dữ liệu đầu vào vào hộp nhập.

Các công cụ hiện đại như WebdriverIO hoặc Web Test Runner có thể kiểm soát tất cả các trình duyệt chính và thậm chí là chạy nhiều thực thể cùng lúc. Các trình duyệt này có thể chạy bên cạnh trình chạy kiểm thử (ví dụ: trên máy tính của riêng bạn hoặc như một phần của một hành động CI) hoặc có thể thuê ngoài cho các dịch vụ thương mại bên ngoài sẽ chạy các trình duyệt đó cho bạn.

Các thư viện kiểm thử lâu đời hơn (bao gồm cả Vitest và Jest) thường có chế độ trình duyệt, nhưng vì nguồn gốc của các thư viện này đến từ Node.js, nên các chế độ trình duyệt của các thư viện này thường được "gắn kết" và thiếu các tính năng hữu ích. Ví dụ: Vitest không thể mô phỏng các mục nhập mô-đun trong trình duyệt. Đây là một yếu tố nguyên gốc mạnh mẽ mà chúng tôi sử dụng trong ví dụ ở trang tiếp theo.

Trong thực tế

Khi chương trình kiểm thử ngày càng phức tạp, việc sử dụng một trình duyệt thực càng quan trọng hơn.

  • Đối với các bài kiểm thử không sử dụng hoặc có rất ít tính năng từ DOM, ngay cả các tính năng có sẵn trong Node.js và các môi trường thời gian chạy tương tự (như fetch hoặc EventTarget), thì môi trường không quan trọng.
  • Đối với các thử nghiệm thành phần nhỏ, JSDOM có thể phù hợp.
  • Các chương trình kiểm thử lớn hơn (ví dụ: kiểm thử toàn diện), có thể mô phỏng hoạt động đăng nhập của người dùng và thực hiện một hành động cốt lõi. Điều này giúp đảm bảo việc chạy hoàn toàn trong một trình duyệt thực tế.

Phần này nặng về lý thuyết và trình bày nhiều quan điểm về nơi nên chạy kiểm thử. Trong thực tế, cơ sở mã của bạn thường sẽ dùng nhiều phương pháp cho các loại kiểm thử khác nhau dựa trên nhu cầu của bạn và nội dung mà công cụ kiểm thử cung cấp.

Kiểm tra kiến thức

Lớp mô phỏng jsdom *không* hỗ trợ những tính năng nào của trình duyệt?

Công cụ bố cục.
Vì JSDOM không phải là một công cụ hình ảnh, nên bạn không thể sử dụng công cụ này để kiểm tra vị trí của một phần tử trên trang, các thuộc tính CSS đã được phân giải hoặc bất kỳ phần nào khác trên bố cục của trang web.
WebSocket
JSDOM bao gồm polyfill WebSocket, vì vậy, mã sử dụng polyfill này sẽ hoạt động.
requestAnimationFrame
Với cờ "pretendToBeVisual", jsdom sẽ gọi lệnh gọi lại 'animation' ở tốc độ 60 khung hình/giây, mặc dù thực sự không có gì được vẽ.