Hiểu rõ kiến trúc của Selenium WebDriver sẽ giúp chúng ta có một cái nhìn tổng quan hơn về cách mà framework này hoạt động. Đây cũng là một trong những câu hỏi phỏng vấn automation engineer mà tôi đã từng gặp, tiếc là lúc đó tôi lại chưa nắm được kiến thức này. Hình vẽ bên trên cho thấy WebDriver hoạt động theo mô hình Client - Server, thông qua một thành phần trung gian là JSON Wire Protocol, trong đó REST APIs đóng một vai trò rất quan trọng. Diễn giải chi tiết mời các bạn đọc bên dưới.
Chức năng của Selenium Client Library (SCL)
SCL nằm ở phía client, hỗ trợ các ngôn ngữ lập trình khác nhau như Java, Python, .NET, Ruby, Javascript v.v... Ví dụ để sử dụng được SCL cho Java, bạn có thể download các thư viện dưới dạng file jar tương ứng ở đây: https://www.selenium.dev/downloads/, sau đó nhúng các file này vào project của mình, hoặc đơn giản hơn là sử dụng Maven https://mvnrepository.com/artifact/org.seleniumhq.selenium/selenium-java/4.27.0 để tải và quản lý các thư viện này một cách tự động. Những câu lệnh mà bạn thường dùng để tương tác với các element, chẳng hạn như: driver.get("https://www.giaphi.com"), driver.findElement(), .click() v.v... chính là từ các thư viện này mà ra.
Vai trò của JSON Wire Protocol (JWP)
JWP đóng vai trò trung gian giữa SCL (client) và driver + browser (server). Nó có nhiệm vụ gửi đi các request từ phía SCL tới browser driver HTTP server thông qua các REST APIs. Request từ client sẽ được serialize (chuyển từ object data thành dạng JSON), sau đó mới được gửi tới server và ngược lại, khi server trả về response gì đó dưới dạng JSON, JWP sẽ deserialize kết quả này trước khi giao lại cho client.
Ví dụ, khi bạn viết câu lệnh driver.get("https://www.giaphi.com/") để navigate tới trang "https://www.giaphi.com/" chẳng hạn.
1) Câu lệnh này sẽ được gửi tới JWP để serialize data thành JSON payload, cụ thể là URL của trang web cần navigate tới.
2) JWP sau đó chuyển tiếp câu lệnh tới ChromeDriver thông qua một REST API có URL là https://localhost:{{DEBUGGING_PORT}}/session/:sessionId/url với method là POST. Cách để lấy được thông tin DEBUGGING_PORT và sessionId tôi sẽ trình bày ở phần sau của bài viết. cURL của câu lệnh sẽ trông giống như bên dưới.
curl --location 'http://localhost:18633/session/c826aa2828884e046f5de30cf624694a/url' \
--header 'Content-Type: application/json' \
--data '{
"url": "https://www.giaphi.com"
}'
3) Cuối cùng, request sẽ được Chrome driver gửi tới trình duyệt Chrome và thực thi việc chuyển hướng tới đường dẫn mới. Đồng thời kết quả của việc chuyển hướng cũng sẽ được trả về theo chiều ngược lại: từ trình duyệt về driver, từ driver về JWP, và từ JWP về phía client.
👉Thông tin về API trên được tôi lấy ở đây: https://www.selenium.dev/documentation/legacy/json_wire_protocol/#sessionsessionidurl.
👉Mọi câu lệnh trong Selenium đều có một REST API tương ứng, bạn có thể tra cứu chi tiết cách sử dụng từng API thông qua đường link sau: https://www.selenium.dev/documentation/legacy/json_wire_protocol/
WebDriver là gì?
WebDriver driver = new ChromeDriver();
Ở ví dụ trên thì "driver" chính là object (instance), ChromeDriver là một class có implements WebDriver. Chính xác hơn, ChromeDriver kế thừa ChromiumDriver, ChromiumDriver lại kế thừa RemoteWebDriver, và RemoteWebDriver implements WebDriver. Các bạn có thể xem thêm ở đây: https://www.selenium.dev/selenium/docs/api/java/org/openqa/selenium/chrome/ChromeDriver.html
Vì trong ví dụ này, chúng ta làm việc với trình duyệt Chrome, nên chúng ta sử dụng Chrome driver. Ngoài ra chúng ta còn có FirefoxDriver, InternetExplorerDriver, SafariDriver để làm việc với các trình duyệt tương ứng như Firefox, InternetExplorer, Safari.
Kiểm nghiệm bằng thực chứng
Đến đây, chúng ta đã hiểu được cách một câu lệnh Selenium chạy như thế nào. Tuy nhiên, làm sao để chứng minh tất cả những gì tôi trình bày là đúng? Tôi đã tạo video dưới đây để các bạn có thể hình dung một cách rõ ràng hơn. Về cơ bản, cách thức mà tôi làm như sau:
- Ở bước khởi chạy trình duyệt, tôi sẽ thêm vào các tham số để in toàn bộ log của các request/response vào file chromedriver.log
- Chạy một test case bất kỳ ở chế độ debug, chúng ta sẽ lấy được thông tin Debugging Port, sau đó gọi tới API /sessions để lấy được sessionId.
- Có được 2 thông tin này, chúng ta sẽ gọi tới API /session/:sessionId/url để navigate tới một trang web bất kỳ.
Hy vọng bài viết này đã mang tới cho các bạn những thông tin hữu ích về cách thức mà Selenium hoạt động. Nếu có thắc mắc hoặc ý kiến đóng góp, vui lòng để lại comment bên dưới. Chúc các bạn một ngày vui vẻ.