Ngiêm cấm sử đụng PROXY và VPS vào mục đích trái pháp luật bạn sẽ phải chịu toàn bộ trách nhiệm trước pháp luật khi sử dụng dịch vụ của chúng tôi tks!
TestCafe Hammerhead proxy: vì sao trang chạy khác khi test

TestCafe Hammerhead proxy: vì sao trang chạy khác khi kiểm thử

Chuyên viên Kỹ thuật ProxyVN 05-26-2026 Đang tính... phút đọc

TestCafe Hammerhead proxy là lớp trung gian chạy ngầm mỗi khi TestCafe mở trang ở chế độ proxy. Nó viết lại địa chỉ, chèn script điều khiển và tự quyết định request nào đi qua mình. Bài này của ProxyVN dựng một website thử và chạy hơn 20 lần với TestCafe 3.7.6. Mục tiêu là chỉ ra những chỗ trang chạy khác so với khi mở bình thường, cùng cách xử lý từng chỗ.

TestCafe Hammerhead proxy là lớp trung gian nằm sẵn trong TestCafe

Khác với Selenium hay Playwright, TestCafe ở chế độ cổ điển không điều khiển trình duyệt bằng driver. Nó dựng một máy chủ trung gian trên máy kiểm thử, đưa trang web qua đó và chèn script tự động hóa vào trang. Phần lõi làm việc này là thư viện testcafe-hammerhead.

Kho mã testcafe-hammerhead trên GitHub tự mô tả đây là một web proxy viết lại URL. Nó sửa mọi thuộc tính JavaScript chứa địa chỉ, ví dụ Location hay href của thẻ liên kết, và trả về giá trị gốc khi trang đọc chúng. Trang được kiểm thử không biết mình đang chạy dưới một proxy.

Vì vậy khi nói về proxy trong TestCafe, anh em cần tách hai lớp. Lớp thứ nhất là Hammerhead, luôn có ở chế độ proxy. Lớp thứ hai là proxy upstream anh em tự khai báo, nằm phía sau Hammerhead.

Khác với tùy chọn --proxy ở đâu

Tùy chọn --proxy chỉ định proxy mà tiến trình Node của TestCafe dùng để ra Internet. Cách cấu hình, xác thực và các lỗi 407, DNS, timeout đã có trong bài TestCafe proxy với 16 lần chạy thử. Bài này không nhắc lại phần đó.

Ở đây ta nói về chính Hammerhead: nó đổi địa chỉ thế nào, bỏ header nào, cho tài nguyên nào đi thẳng, và các cổng 1337, 1338 gây lỗi ra sao. Nhiều lỗi tưởng do proxy upstream thật ra sinh ra ở lớp này.

Khi nào trang còn đi qua Hammerhead

Từ bản 3.0, TestCafe mặc định bật native automation cho Chrome và Edge chạy cục bộ. Ở chế độ đó, TestCafe điều khiển trình duyệt qua giao thức CDP và trang không đi qua Hammerhead. Bài TestCafe Goes Native của nhóm phát triển ghi rõ điều này.

Hammerhead vẫn là đường chạy bắt buộc trong nhiều trường hợp mà anh em hay gặp:

  • Firefox và Safari: không dùng CDP nên luôn chạy qua Hammerhead.
  • Trình duyệt từ xa, trên điện thoại hoặc trên cloud: tài liệu CLI ghi các trường hợp này phải tắt native automation.
  • Dự án đã thêm --disable-native-automation: thường để dùng --proxy, vì native automation bỏ qua proxy upstream.
  • Phiên bản TestCafe cũ hơn 3.0: chỉ có chế độ proxy.

Nếu dự án rơi vào một trong các trường hợp trên, mọi hành vi trong bài này đều áp dụng.

Môi trường thử trong bài

Mình chạy trên Windows 10, Node 24.20, TestCafe 3.7.6 và testcafe-hammerhead 31.7.8. Trình duyệt là Edge 156 không giao diện, mở bằng Playwright rồi kết nối vào TestCafe theo chế độ remote. Cách này cho phép ghi lại mọi URL thật mà trình duyệt gọi.

Website thử là một máy chủ Node nhỏ chạy trên hai cổng, đóng vai hai origin khác nhau. Máy chủ ghi lại từng request nhận được, kèm header Host, Referer và Cookie. Proxy upstream là một chương trình Python nhỏ có ghi log, chỉ dùng ở các ca cần so sánh.

Mình cũng thử chế độ native với lệnh testcafe edge:headless, nhưng trên máy này TestCafe không mở được trình duyệt và báo Cannot establish one or more browser connections. Vì vậy, phần nào nói về native automation trong bài đều dựa theo tài liệu chính thức, không phải kết quả chạy.

npm install testcafe@3.7
npx testcafe --version          # 3.7.6
npx testcafe remote tests.js --hostname 127.0.0.1 --ports 1337,1338

Lệnh cuối in ra một Connect URL. Trình duyệt nào mở địa chỉ đó sẽ thành trình duyệt chạy test. Đây là cách đơn giản nhất để quan sát Hammerhead từ phía trình duyệt.

Chuẩn bị môi trường

Chuẩn bị môi trường

Cách TestCafe Hammerhead proxy viết lại địa chỉ trang

Muốn hiểu vì sao trang chạy khác, trước hết phải xem Hammerhead đặt trang ở đâu. Câu trả lời nằm ở thanh địa chỉ thật của trình duyệt, khác với địa chỉ mà script trong trang nhìn thấy.

Địa chỉ thật trên thanh địa chỉ

Test mở trang http://127.0.0.1:9470/info. Log của Playwright cho thấy trình duyệt thật ra tải một địa chỉ khác, nằm trên cổng 1337 của TestCafe:

NAV main  http://127.0.0.1:1337/yq7fCDGlF/http://127.0.0.1:9470/info
REQ script http://127.0.0.1:1337/hammerhead.js
REQ script http://127.0.0.1:1337/testcafe-core.js
REQ script http://127.0.0.1:1337/testcafe-driver.js
REQ script http://127.0.0.1:1337/yq7fCDGlF!s!utf-8/http://127.0.0.1:9470/app.js
REQ fetch  http://127.0.0.1:1337/yq7fCDGlF!a!1/http://127.0.0.1:9470/api
REQ xhr    http://127.0.0.1:1337/messaging

Đoạn yq7fCDGlF là mã phiên, mỗi lần chạy một mã khác. Sau mã phiên là các cờ: !s!utf-8 cho script kèm bảng mã, !a!1 cho request fetch hay XHR. Phần cuối là địa chỉ gốc giữ nguyên.

Trước khi trang chạy, Hammerhead chèn thêm sáu file script và một file CSS của TestCafe. Ngoài ra trình duyệt gửi request /messaging về cổng 1337 liên tục trong suốt test. Mọi thứ trang tải đều phải đi vòng qua máy chạy TestCafe, trừ một ngoại lệ sẽ nói ở phần sau.

Script trong trang vẫn thấy địa chỉ gốc

Dù đang nằm ở cổng 1337, script của trang vẫn đọc ra địa chỉ gốc. Mình cho trang ghi lại location và vài thuộc tính chứa URL, rồi đọc ra bằng ClientFunction:

seen        {"href":"http://127.0.0.1:9470/info","host":"127.0.0.1:9470","origin":"http://127.0.0.1:9470",
             "ref":"http://127.0.0.1:1337/browser/idle/PXcBvXy","cookie":"sid=lab123"}
rawLinkProp "http://127.0.0.1:9470/next?a=1"
formAction  "http://127.0.0.1:9470/post"
scriptsInDom ["http://127.0.0.1:9470/app.js"]
hammerheadGlobal "object"

Location, href của liên kết, action của form và src của script đều trả về địa chỉ gốc, đúng như README mô tả. Riêng document.referrer bị lộ: nó trỏ về trang chờ /browser/idle trên cổng 1337, vì trình duyệt thật sự đi từ trang đó sang.

Biến toàn cục %hammerhead% cũng có mặt trong trang. Đây là dấu hiệu dễ nhận ra nhất nếu ứng dụng có đoạn mã tự kiểm tra môi trường. Với ứng dụng nội bộ thì không sao, nhưng anh em nên biết trang có thể phát hiện mình đang chạy dưới TestCafe.

Website nhận được header gì

Ở phía máy chủ, Hammerhead khôi phục header về như trình duyệt gửi thẳng. Request /api mà trang gọi bằng fetch tới máy chủ với Host 127.0.0.1:9470, Referer là http://127.0.0.1:9470/info và Cookie sid=lab123. Không có dấu vết nào của cổng 1337.

User-Agent vẫn là của Edge không giao diện, có chữ HeadlessChrome. Nếu website chặn bot theo User-Agent, lớp proxy không giúp gì. Muốn đổi User-Agent thì phải đổi ngay ở trình duyệt.

Điểm đáng nhớ của phần này là Hammerhead che giấu khá kỹ ở phía máy chủ, nhưng không che hết ở phía trình duyệt. Referrer, biến toàn cục và scope của service worker là ba chỗ lộ ra.

Tài nguyên không đi qua TestCafe Hammerhead proxy

Đây là phát hiện lạ nhất trong cả lab. Mình tưởng mọi request đều đi qua Hammerhead, nhưng log cho thấy ảnh được tải thẳng từ website.

Thẻ img tải thẳng từ website

Trang thử có hai thẻ img, một ảnh cùng origin và một ảnh từ origin thứ hai, cùng một ảnh nền khai báo trong CSS. Log trình duyệt khi chạy bình thường:

REQ image http://127.0.0.1:9470/pic.png
REQ image http://127.0.0.1:9471/pic2.png
REQ image http://127.0.0.1:1337/abcvisQUZ/http://127.0.0.1:9470/bg.png

Hai ảnh trong thẻ img đi thẳng tới website, không qua cổng 1337. Chỉ ảnh nền CSS đi qua Hammerhead. Đọc mã nguồn hàm xử lý thuộc tính src trong lib/processing/dom/index.js, mình thấy đây là chủ ý: với thẻ img, Hammerhead chỉ đổi đường dẫn tương đối thành địa chỉ đầy đủ của website, trừ khi cờ forceProxySrcForImage được bật.

Cờ forceProxySrcForImage và RequestLogger

Cờ này không có tùy chọn CLI riêng. Trong lib/session/index.js, nó được gán bằng việc phiên test có request hook nào lắng nghe hay không. Nói cách khác, chỉ cần gắn RequestLogger hoặc RequestMock, ảnh sẽ bị ép đi qua proxy.

import { RequestLogger } from 'testcafe';
 
const logger = RequestLogger(/pic|bg\.png/);
 
fixture('anh')
    .page('http://127.0.0.1:9470/imgpage')
    .requestHooks(logger);

Chạy lại cùng trang với hook này, cả ba ảnh đều đi qua cổng 1337 và RequestLogger ghi nhận đủ ba URL. Không có hook thì không ghi được ảnh nào bằng hook, vì hook không tồn tại, nhưng quan trọng hơn là ảnh không hề chạm vào Hammerhead.

Hậu quả khi dùng chung với proxy upstream

Hệ quả thực tế xuất hiện khi dự án dùng --proxy để kiểm website từ một vùng khác. Mình chạy cùng trang với --proxy trỏ tới proxy lab, rồi đối chiếu log proxy:

Bảng: Hậu quả khi dùng chung với proxy upstream

Trường hợp

pic.png (img)

pic2.png (img, origin khác)

bg.png (CSS)

--proxy, không hook

Đi thẳng, proxy không thấy

Đi thẳng, proxy không thấy

Qua proxy

--proxy, có RequestLogger

Qua proxy

Qua proxy

Qua proxy

Không có hook, proxy upstream chỉ thấy trang HTML, file JS và ảnh nền. Hai ảnh trong thẻ img đi từ IP của máy kiểm thử. Nếu website trả ảnh khác nhau theo vùng, ví dụ banner hay giá theo quốc gia, test sẽ thấy HTML của vùng A nhưng ảnh của vùng B.

Có một chi tiết phụ trong lab: vì cổng 1337 và website cùng nằm trên 127.0.0.1, request ảnh đi thẳng còn mang theo cookie nội bộ của Hammerhead, dạng s|yq7fCDGlF|sid|127.0.0.1|%2F||...=lab123. Cookie trình duyệt gắn theo tên máy, không theo cổng. Khi chạy thật, nên để TestCafe và website ở hai tên máy khác nhau để tránh lẫn cookie.

Công cụ và dữ liệu

Công cụ và dữ liệu

TestCafe Hammerhead proxy với CSP, service worker, iframe và WebSocket

Phần này gom các tính năng web hiện đại mà anh em hay lo sẽ hỏng khi đi qua proxy. Kết quả lab cho thấy phần lớn vẫn chạy, nhưng chạy theo cách khác với khi mở trang bình thường.

Header CSP bị bỏ đi

Trang /csp gửi header Content-Security-Policy với script-src 'self', kèm một script inline. Mở trực tiếp bằng Edge, trình duyệt chặn script inline và báo lỗi vi phạm CSP trên console. Chạy qua TestCafe, cả script inline và script ngoài đều chạy.

Mở trực tiếp:  out = 'chua chay'      (inline bị CSP chặn)
Qua TestCafe:  out = 'inline da chay' (inline vẫn chạy)

Trong lib/request-pipeline/header-transforms/transforms.js, header content-security-policy được đánh dấu skip, tức là không chuyển cho trình duyệt. Điều này hợp lý với Hammerhead, vì nó phải chèn script của mình vào trang. Nhưng hệ quả là test ở chế độ proxy không bắt được lỗi do CSP. Nếu đội anh em vừa siết CSP, cần một lần kiểm riêng bằng trình duyệt thường hoặc native automation.

Service worker đăng ký dưới origin của TestCafe

Trang /sw đăng ký một service worker đơn giản. Qua TestCafe, việc đăng ký thành công, nhưng scope trả về là http://127.0.0.1:1337/, không phải origin của website. Mở trực tiếp thì scope là http://127.0.0.1:9470/.

Service worker là phần Hammerhead không che được, vì trình duyệt đăng ký nó theo origin thật đang mở. Ứng dụng nào kiểm tra scope, hoặc cache theo đường dẫn, có thể chạy khác lúc test. Với ứng dụng PWA, anh em nên coi kết quả test service worker ở chế độ proxy chỉ mang tính tham khảo.

iframe khác origin vẫn vào được

Trang /iframe nhúng một iframe từ origin thứ hai trên cổng 9471. Lệnh t.switchToIframe chuyển vào được, đọc đúng nội dung bên trong, và location.href trong iframe trả về địa chỉ gốc. Máy chủ thứ hai nhận Referer là trang cha ở cổng 9470, đúng như trình duyệt thường gửi.

Theo mã nguồn, Hammerhead phục vụ iframe khác origin qua cổng thứ hai, tức là cổng 1338 mặc định. Đó là lý do TestCafe luôn đòi hai cổng. Nếu tường lửa chỉ mở một cổng cho máy kiểm thử, test có iframe khác origin sẽ hỏng trước.

WebSocket chạy thẳng, nhưng cẩn thận với proxy upstream

Không khai báo --proxy, WebSocket tới ws://127.0.0.1:9470/echo mở được, gửi ping và nhận lại ping. Máy chủ nhận Origin là http://127.0.0.1:9470, không phải cổng 1337. Hammerhead có hỗ trợ WebSocket như README liệt kê.

Khi bật --proxy trỏ tới proxy lab, WebSocket báo lỗi. Log proxy cho thấy Hammerhead gửi yêu cầu nâng cấp dưới dạng GET http://127.0.0.1:9470/echo kiểu địa chỉ đầy đủ, không mở đường hầm CONNECT. Proxy lab của mình không chuyển tiếp header Upgrade theo dạng này nên kết nối hỏng.

Mình không khẳng định mọi proxy đều hỏng như vậy, vì proxy lab chỉ là một chương trình đơn giản. Nhưng nếu ứng dụng có chat hay thông báo thời gian thực, hãy đưa một test WebSocket vào bộ kiểm proxy upstream trước khi tin vào kết quả.

TestCafe Hammerhead proxy, tên máy và secure context

Phần này giải thích một lỗi rất hay gặp khi chạy test từ máy khác: trang đang chạy tốt bỗng mất hẳn vài API. Nguyên nhân nằm ở việc Hammerhead phục vụ trang qua HTTP.

Chạy bằng IP LAN làm mất API của trình duyệt

Một số API chỉ có trong secure context, tức trang mở qua HTTPS hoặc từ localhost. Tài liệu MDN về secure context liệt kê các API này, trong đó có service worker, Web Crypto và Clipboard. Mình kiểm cùng một trang ở ba cấu hình:

Bảng: Chạy bằng IP LAN làm mất API của trình duyệt

Cấu hình

isSecureContext

crypto.subtle

serviceWorker

clipboard

--hostname 127.0.0.1

true

có

có

có

--hostname 192.168.0.93

false

không

không

không

--hostname 192.168.0.93 --ssl

true

có

có

có

Với tên máy là IP LAN, trang trở thành HTTP thường và mất cả bốn tính năng. Đây là lý do test chạy tốt trên máy cá nhân nhưng hỏng khi đưa lên máy ảo hay điện thoại. Trang Test HTTPS Features and HTTP/2 Websites cũng cảnh báo trang có thể báo lỗi JavaScript hoặc tải dở khi dùng các API này qua proxy HTTP.

Bật HTTPS cho Hammerhead bằng --ssl

Tùy chọn --ssl nhận các tham số khởi tạo HTTPS của Node.js, nối bằng dấu chấm phẩy. Tài liệu dùng file pfx làm ví dụ. Trong lab, mình dùng cặp key và cert tạo bằng OpenSSL, có IP LAN trong subjectAltName, và cách này cũng chạy được:

openssl req -x509 -newkey rsa:2048 -nodes -keyout lab.key -out lab.crt -days 3 \
  -subj "/CN=192.168.0.93" -addext "subjectAltName=IP:192.168.0.93"
 
npx testcafe remote tests.js --hostname 192.168.0.93 --ports 1352,1353 \
  --ssl "key=lab.key;cert=lab.crt"

Connect URL chuyển thành https://192.168.0.93:1352/browser/connect, và test đọc lại isSecureContext là true. Nhớ đặt chuỗi --ssl trong dấu nháy, vì dấu chấm phẩy là ký tự đặc biệt trong nhiều shell.

Lỗi PEM no start line

Lần đầu chạy, lệnh tạo chứng chỉ của mình hỏng nên không có file lab.key. TestCafe không báo thiếu file mà báo ERROR Error: error:0480006C:PEM routines::no start line. Lý do là khi giá trị không phải đường dẫn tồn tại, nó được hiểu như nội dung chứng chỉ, và nội dung đó không bắt đầu bằng dòng BEGIN.

Gặp lỗi này, việc đầu tiên là kiểm đường dẫn file tính từ thư mục đang chạy lệnh. Sau đó mở file xem có dòng -----BEGIN hay không. Trên Git Bash, lệnh openssl có -subj còn có thể hỏng vì shell đổi /CN thành đường dẫn Windows. Đặt MSYS_NO_PATHCONV=1 trước lệnh là chạy được.

Trình duyệt không tin chứng chỉ tự ký

Mở Connect URL bằng Edge không kèm cờ gì, trình duyệt dừng ngay với net::ERR_CERT_AUTHORITY_INVALID. TestCafe chỉ ngồi chờ, đến hết thời gian khởi tạo thì báo không kết nối được trình duyệt. Cách xử lý theo tài liệu là chạy Chrome hay Edge với --ignore-certificate-errors khi tên máy không phải localhost.

Nếu muốn hiểu thêm vì sao lỗi chứng chỉ này xuất hiện và cách đọc nó, anh em xem bài lỗi NET ERR CERT AUTHORITY INVALID. Với máy chạy test lâu dài, nên dùng chứng chỉ do CA nội bộ ký và cài CA đó vào máy kiểm thử, thay vì tắt kiểm tra chứng chỉ của trình duyệt.

Kiểm theo từng ca

Kiểm theo từng ca

Cổng của TestCafe Hammerhead proxy và các lỗi kết nối

Hammerhead cần hai cổng: một cho trang chính, một cho iframe khác origin. Phần lớn lỗi khó hiểu khi khởi động TestCafe đều liên quan tới hai cổng này hoặc tới tên máy.

--ports phải đủ hai cổng

Khai báo một cổng, TestCafe dừng ngay với The "--ports" option requires two arguments. Lỗi này dễ sửa. Khi không khai báo, TestCafe tự chọn hai cổng trống, nhưng trên máy CI có tường lửa, anh em nên ghi cố định để mở đúng cổng.

Cổng bị chiếm trên Windows mà không báo lỗi

Lỗi này mất thời gian nhất trong lab. Mình cho một chương trình Python nghe trên 127.0.0.1:1344, rồi chạy TestCafe với --ports 1344,1345. TestCafe không báo cổng bận, vẫn in Connect URL như bình thường.

TCP    0.0.0.0:1344      LISTENING   34132   <- TestCafe
TCP    127.0.0.1:1344    LISTENING   32108   <- chương trình khác
 
curl http://127.0.0.1:1344/browser/connect
PY_SOCKET_NHAN b'GET /browser/connect HTTP/1.1 ...'

Lệnh netstat cho thấy TestCafe nghe trên 0.0.0.0, còn chương trình kia nghe riêng trên 127.0.0.1. Windows cho phép cả hai cùng tồn tại, và request tới 127.0.0.1 rơi vào chương trình kia. Trình duyệt mở Connect URL nhưng không bao giờ tới được TestCafe.

Khi TestCafe báo không kết nối được trình duyệt mà mọi thứ trông bình thường, hãy chạy netstat -ano xem cổng có hai tiến trình cùng nghe hay không. Cách tránh là đổi sang cặp cổng khác, hoặc tìm tiến trình đang giữ cổng trước khi chạy.

Tên máy sai và lỗi DNS giả

Với --hostname 10.254.254.254, một IP không thuộc máy nào, TestCafe báo Cannot resolve hostname "10.254.254.254". Thông báo nói là không phân giải được, dù đó là IP. Thực chất TestCafe kiểm xem tên máy có thuộc card mạng nào trên máy hay không.

Một lỗi tương tự xảy ra ở phía website. Lần chạy đầu, máy chủ website của mình chưa bật, và cả tám test đều báo Failed to find a DNS-record for the resource at "http://127.0.0.1:9470/...". Địa chỉ là IP nên không có DNS nào ở đây, lỗi thật là kết nối bị từ chối.

Vì vậy, thấy lỗi DNS-record với địa chỉ IP thì kiểm website có đang chạy và cổng có mở không, đừng đi sửa DNS. Với tên miền thật, lỗi này mới có thể là DNS, hoặc là proxy upstream không phân giải được tên miền.

TestCafe Hammerhead proxy, chứng chỉ website và lỗi JavaScript

Hai hành vi dưới đây khiến kết quả test khác với trải nghiệm của người dùng thật. Một cái làm test dễ dãi hơn, một cái làm test khắt khe hơn.

Chứng chỉ website lỗi vẫn được cho qua

Mình dựng một website HTTPS dùng chứng chỉ tự ký, cấp cho IP 192.168.0.93 nhưng mở bằng 127.0.0.1, tức sai cả CA lẫn tên. Trình duyệt thường sẽ hiện trang cảnh báo. Qua Hammerhead, test mở trang bình thường, đọc được nội dung và báo đạt.

Trong mã nguồn, file lib/request-pipeline/destination-request/agent.js và request-options.js đều đặt rejectUnauthorized: false khi Hammerhead gọi tới website. Nghĩa là lớp proxy của TestCafe không kiểm chứng chỉ của website đích. Chứng chỉ hết hạn, sai tên hay thiếu chứng chỉ trung gian đều không làm test đỏ.

Điều này có lợi ở môi trường thử nội bộ dùng chứng chỉ tự ký. Nhưng nếu muốn kiểm chứng chỉ của trang thật, phải có một bước riêng, ví dụ lệnh curl không kèm -k hoặc công cụ giám sát chứng chỉ.

Lỗi JavaScript của trang làm test đỏ

Ngược lại, trang /jserr có một dòng gọi hàm không tồn tại. Người dùng thật không thấy gì vì phần nội dung vẫn hiện. TestCafe thì báo A JavaScript error occurred, kèm ReferenceError: undefinedFunctionCall is not defined, và đánh test hỏng dù selector vẫn đọc được chữ.

Khi lỗi thuộc script bên thứ ba mà đội không sửa được, thêm --skip-js-errors thì test đạt. Tài liệu CLI cho phép lọc theo message, stack hoặc pageUrl, nên chỉ bỏ qua đúng lỗi đã biết thay vì bỏ qua tất cả:

npx testcafe remote tests_err.js --skip-js-errors
 
# chỉ bỏ qua lỗi đã biết
npx testcafe chrome tests/ --skip-js-errors message="undefinedFunctionCall"

Lưu ý thêm: nếu một lỗi JavaScript chỉ xuất hiện khi chạy qua TestCafe, rất có thể nó do Hammerhead viết lại script. Thông báo lỗi của TestCafe cũng gợi ý báo lên kho mã của dự án trong trường hợp này.

Hiệu năng TestCafe Hammerhead proxy và khi nào chuyển sang native automation

Viết lại địa chỉ có giá của nó. Mình đo bằng một file JavaScript khoảng 2 MB chứa 60.000 hàm nhỏ, đặt mốc thời gian trước và sau thẻ script.

Số đo trong lab

Bảng: Số đo trong lab

Cách mở

Lần 1

Lần 2

Lần 3

Mở trực tiếp bằng Edge

105 ms

92 ms

97 ms

Qua Hammerhead

418 ms

73 ms

73 ms

Lần đầu qua Hammerhead chậm gấp khoảng bốn lần, vì script phải được viết lại trước khi tới trình duyệt. Hai lần sau còn nhanh hơn mở trực tiếp, nhiều khả năng do bản đã xử lý được lưu lại và trình duyệt cache theo URL proxy. Đây là số đo trên máy cục bộ, một file và ba lần chạy, nên chỉ để hình dung xu hướng.

Với bộ test lớn, mỗi phiên test mới lại có một mã phiên mới trong URL. Vì vậy test đầu tiên của mỗi trang thường chậm hơn các test sau. Đặt pageLoadTimeout và pageRequestTimeout có tính tới lần tải đầu này sẽ giảm các lỗi chập chờn.

Con số của nhóm phát triển TestCafe

Bài TestCafe Goes Native kể lại phép đo của nhóm ASP.NET Grid Components: 98 test, mỗi test chạy 4 lần ở mỗi chế độ. Thời gian trung bình ở chế độ proxy là 17 phút 50 giây, so với 6 phút 28 giây ở native. Một số test chạy được ở native nhưng hỏng ở proxy.

Chế độ proxy không sai, nó chỉ là một môi trường khác với trình duyệt của người dùng. Test đạt trong môi trường đó vẫn cần một lần đối chứng ngoài môi trường đó.

Chọn chế độ theo việc cần làm

Từ các kết quả trên, cách chọn khá rõ ràng:

  • Chỉ chạy Chrome hoặc Edge cục bộ, không cần proxy upstream: để native automation mặc định, nhanh hơn và gần trình duyệt thật hơn.
  • Cần --proxy để kiểm theo vùng: buộc phải tắt native, nên nhớ các điểm về ảnh, WebSocket và CSP ở trên.
  • Chạy Firefox, Safari, điện thoại hay trình duyệt từ xa: chỉ có Hammerhead, nên bật --ssl nếu trang dùng API cần secure context.
  • Cần kiểm CSP, chứng chỉ hay service worker: thêm một bước kiểm ngoài TestCafe, hoặc chạy phần đó bằng công cụ khác như Playwright với proxy.

Bàn giao có bằng chứng

Bàn giao có bằng chứng

Bảng ca kiểm TestCafe Hammerhead proxy đã chạy

Bảng dưới gom các lần chạy thật trong bài, để anh em đối chiếu nhanh khi gặp hiện tượng tương tự. Cột cuối là việc nên làm, không phải cấu hình bắt buộc.

Bảng: Bảng ca kiểm TestCafe Hammerhead proxy đã chạy

Ca thử

Kết quả quan sát

Nên làm

Website tắt

Failed to find a DNS-record dù địa chỉ là IP

Kiểm website và cổng trước DNS

Đọc location trong trang

Trả địa chỉ gốc, referrer lộ cổng 1337

Không dựa vào referrer khi test

Header tới website

Host, Referer, Cookie như gửi thẳng

Không cần xử lý

Thẻ img, không hook

Tải thẳng, không qua proxy upstream

Gắn RequestLogger nếu cần ảnh qua proxy

Thẻ img, có RequestLogger

Đi qua Hammerhead và proxy upstream

Dùng khi kiểm theo vùng

CSP script-src 'self'

Header bị bỏ, script inline vẫn chạy

Kiểm CSP ngoài chế độ proxy

Service worker

Đăng ký được, scope là cổng 1337

Coi kết quả là tham khảo

iframe khác origin

Vào được qua cổng thứ hai

Mở đủ hai cổng trên tường lửa

WebSocket không proxy

Gửi nhận bình thường

Không cần xử lý

WebSocket qua proxy lab

Lỗi, yêu cầu Upgrade gửi dạng GET đầy đủ

Kiểm riêng với proxy thật

IP LAN, không --ssl

Mất crypto.subtle, serviceWorker, clipboard

Bật --ssl

IP LAN, có --ssl

Secure context trở lại

Dùng chứng chỉ có đúng IP hoặc tên

--ssl sai đường dẫn

PEM routines::no start line

Kiểm đường dẫn file

Trình duyệt không tin chứng chỉ

ERR_CERT_AUTHORITY_INVALID

Cờ trình duyệt hoặc CA nội bộ

Cổng bị chiếm ở 127.0.0.1

Không báo lỗi, request vào chương trình khác

netstat -ano trước khi chạy

--hostname không thuộc máy

Cannot resolve hostname

Dùng IP của card mạng thật

Website HTTPS tự ký

Test vẫn đạt

Kiểm chứng chỉ bằng bước riêng

Lỗi JavaScript trong trang

Test đỏ, --skip-js-errors thì đạt

Lọc theo message

JS 2 MB lần đầu

418 ms so với khoảng 97 ms

Tăng timeout lần tải đầu

Mỗi ca được chạy ít nhất một lần, với TestCafe 3.7.6 trên Windows. Hành vi có thể đổi ở bản khác, nên khi nâng cấp TestCafe, anh em nên chạy lại vài ca quan trọng như ảnh, WebSocket và secure context.

Checklist dùng TestCafe Hammerhead proxy cùng proxy upstream

Phần lớn đội kiểm thử đụng tới Hammerhead vì muốn dùng --proxy. Checklist dưới đây gom những việc nên làm khi ghép hai lớp proxy này với nhau.

  • Tắt native automation có chủ đích và ghi lý do vào tệp cấu hình, để người sau không vô tình bật lại.
  • Gắn một RequestLogger cho cả bộ test nếu muốn mọi ảnh đi qua proxy upstream, kể cả khi không cần đọc log.
  • Thêm một test kiểm IP ra trên trang trả về IP người gọi, đặt chạy đầu tiên.
  • Thêm một test WebSocket nếu ứng dụng dùng kết nối thời gian thực.
  • Cố định --hostname và --ports, mở đủ hai cổng trên tường lửa, bật --ssl nếu tên máy không phải localhost.
  • Tách bước kiểm CSP và chứng chỉ ra khỏi TestCafe ở chế độ proxy.

Proxy upstream cần ổn định trong suốt lần chạy, vì Hammerhead giữ cookie và phiên theo từng test. Proxy chập chờn sẽ biến thành lỗi tải trang ngẫu nhiên, rất khó phân biệt với lỗi ứng dụng. Nếu anh em cần proxy dân cư hay datacenter Việt Nam có xác thực user và password cho việc này, có thể mua proxy tại ProxyVN rồi chạy thử bộ test IP ra trước khi đưa vào CI.

Danh sách bỏ qua proxy nên giữ ngắn và có kiểm. Cú pháp và cách dùng ký tự đại diện có trong bài no_proxy là gì. Nếu muốn so cách các công cụ khác xử lý proxy, anh em xem thêm bài Cypress proxy.

Câu hỏi thường gặp về TestCafe Hammerhead proxy

Có tắt được Hammerhead mà vẫn dùng TestCafe không?

Có, với Chrome và Edge chạy cục bộ. Native automation là mặc định từ bản 3.0 và không dùng Hammerhead. Với Firefox, Safari hay trình duyệt từ xa thì không tắt được.

Hammerhead có phải proxy dùng để đổi IP không?

Không. Hammerhead chạy ngay trên máy kiểm thử, nên IP ra vẫn là IP của máy đó. Muốn đổi IP phải khai báo proxy upstream bằng --proxy. Khái niệm proxy viết lại URL kiểu này gần với web proxy hơn là proxy mạng.

Vì sao proxy upstream không thấy request ảnh?

Vì ảnh trong thẻ img đi thẳng từ trình duyệt tới website khi phiên test không có request hook. Gắn một RequestLogger, kể cả với bộ lọc rộng, là ảnh sẽ đi qua Hammerhead rồi mới tới proxy upstream.

Vì sao test đạt trên máy mình nhưng hỏng trên máy ảo?

Hay gặp nhất là do tên máy. Trên máy mình, TestCafe dùng localhost nên trang ở secure context. Trên máy ảo, trình duyệt mở bằng IP LAN qua HTTP và mất các API như crypto.subtle. Bật --ssl với chứng chỉ đúng IP sẽ xử lý được.

Có cần mở cổng 1338 không?

Cần, nếu trang có iframe khác origin. Hammerhead dùng cổng thứ hai cho iframe đó. Tường lửa chỉ mở một cổng thì test có iframe sẽ không tải được khung bên trong.

TestCafe Hammerhead proxy và những điều cần nhớ

TestCafe Hammerhead proxy viết lại địa chỉ, bỏ header CSP, không kiểm chứng chỉ website và cho ảnh trong thẻ img đi thẳng khi không có hook. Nắm mấy điểm này, anh em sẽ đọc đúng kết quả test và ghép proxy upstream an toàn hơn. Theo dõi Proxy.vn - Nhà cung cấp dịch vụ proxy chất lượng hàng đầu Việt Nam để đọc thêm các bài kiểm thử có chạy thật về TestCafe Hammerhead proxy.

TIN TỨC LIÊN QUAN