Khi bắt đầu tìm hiểu và học về Selenium Webdriver, mình thấy rất nhiều sách chỉ ra các cách để xác định vị trí của các elements trên trang web, đọc muốn hoa mắt và cảm thấy rất mơ hồ. Ngày đó, mình thấy ai cũng dạy là tìm theo thứ tự id, name, class… cuối cùng là CSS và Xpath, nên những project demo của mình lúc nào thì cứ id và name mà phang, sau đó là Xpath, còn CSS thì không bao giờ đụng đến. Sau này, khi đọc nhiều hơn về Selenium Webdriver, mới thấy là trước đây mình chỉ hiểu cái bề mặt, thật ra chỉ có 2 loại chính là CSS Selector và Xpath Selector. Tại sao lại như vậy??? Đọc tiếp thì biết. 😀
Nội dung bài viết
I. Vậy CSS selectors là gì?
1 CSS selector là 1 đoạn chuỗi String được thiết kế để xác định 1 hay nhiều elements trên 1 trang web bằng cách sử dụng các attributes và / hoặc dùng thứ tự cha – con của các elements trong DOM.
Đây là các API xác định element do Selenium Webdriver cung cấp:
- By.ByClassName
- By.ByCssSelector
- By.ById
- By.ByLinkText
- By.ByName
- By.ByPartialLinkText
- By.ByTagName
- By.ByXPath
Đọc định nghĩa về CSS Selector ở trên và xem list API, thì thấy có vẻ như là đúng là chỉ có 2 loại: CSS và XPath vì Id, class, name, Tag… là các attributes của 1 Element. Khi gọi các methods trên, thực chất đều chuyển thành CssSelector.
Nếu chỉ có 2 loại thì sao Selenium Webdriver lại cung cấp nhiều API thế kia? Cung cấp nhiều methods để giảm bớt sự phức tạp cho người sử dụng thôi, chứ không phải có các cách khác nhau để xác định Element.
II. Cách CSS xác định 1 element
Mô tả các trường hợp dưới đây đều dùng trang web này: https://letskodeit.teachable.com/p/practice
1. Xác định theo ID
Trong hầu hết các trường hợp, sử dụng ID (nếu có) là lựa chọn số 1.
Nó trông giống như vậy:
<select id="carselect" name="cars">
Nếu dùng CSS Selector thì nó là: #carselect
findElement(By.id("carselect")) = findElement(By.CssSelector("#carselect"))
Tất nhiên là có 1 vài ngoại lệ…(đùa, cái gì cũng có ngoại lệ, học mệt ghê). Đó là khi Dev dùng 1 ID cho 2 elements khác nhau, do lỗi lập trình, chứ không phải là do cố ý. Hoặc là việc sử dụng ID động chứ ko phải ID tĩnh. ID động là dạng ID sẽ thay đổi sau mỗi lần load trang, nó có dạng:
<input id="email-28742" value="" />
Để xử lý cái “của nợ” này, thì có 2 cách và sẽ được nói ở phía dưới:
- 1 là matching Id theo kiểu wild card
- 2 là sử dụng cách xác định khác
2. Xác định theo các attributes
Một attribute về cơ bản là 1 tính chất của 1 element. Và 1 element thì có rất các loại tính chất khác nhau. Ví dụ:
<input id="name" name="enter-name" class="inputs" placeholder="Enter Your Name" type="text">
Những attributes có thể được xác định bằng cách viết sau:
[name ='enter-name']
findElement(By.name("enter-name")) = findElement(By.CssSelector("[name ='enter-name']"))
Tất nhiên là sẽ có những trường hợp mà nếu chỉ dùng 1 attribute thì không thể xác định được vị trí của element đó vì nó có nhiều element được đánh dấu giống nhau. Ví dụ:
<input type="radio" name="point" value="1"> <input type="radio" name="point" value="2"> <input type="radio" name="point" value="3">
Ta chỉ cần thêm thông tin attribute là xong:
[name="point"][value="2"]
Nếu muốn rõ ràng hơn, ta có thể cho thêm tag của element đó:
input[name="point"][value="2"]
Như đã nói ở trên, CSS Selector còn cung cấp 1 số tính năng của wild card, như matching với đoạn đầu, đoạn cuối và vị trí bất kỳ.
^= (match với đoạn đầu)
<input id="email-28742" value=""> --> input[id^="email"]
$= (match với đoạn cuối)
<a href="/user/12345/edit/">Edit User</a> --> a[href$="/edit/"]
*= (match với vị trí bất kỳ)
<a href="https://staging.company.com/dashboard/?session=3284792">Dashboard</a> --> a[href*="/dashboard/"]
Và ta cũng có thể kếp hợp những cái này với nhau
a[href^="/user/"][href$="/edit/"]
3. Xác định theo class names
Hầu hết các elements đều có 1 attribute class, trong đó có chứa các giá trị class ngăn cách nhau bằng 1 khoảng trống, class=”class1 class2 class3″
Ví dụ:
<div class="block large-row-spacer">
Để match với element mà sử dụng class thì t dùng cú pháp:
.class1.class2
Tuy nhiên, dùng với class thì không an toàn, vì thông thường class để style cho 1 group nhiều element. Check thử ví dụ trên, ta sẽ thấy có 5 kết quả trả về.
4. Xác định theo hierarchy
Xác định theo Hierarchy là kiểu đi theo dạng thác nước, có vẻ giống với Xpath, đi từ trên xuống dưới, khá phức tạp. Nhưng đôi khi attributes không đủ để xác định, ta buộc phải dùng đến nó.
a. Ví dụ 1
<div class="name"> <label>Justin</label> </div> <div class="email"> <label>test@email.com</label> </div>
Cú pháp của nó sẽ là:
element1 element2...
Giả sử trong ví dụ trên, ta muốn lấy cái label có chứa Justin, ta phải dùng 1 attribute để xác định được thằng element cha của nó rồi mới đi tới nó. Giữa 2 cha con có 1 khoảng trống.
CSS Selector lúc đó sẽ là:
.name label
b. Ví dụ 2
#supportForm .comments textarea
Trong selector này, mình muốn tìm 1 <textarea>, nằm trong 1 element có class .comment mà nó lại là con của 1 element có id là supportForm.
5. Xác định theo ordering
Trong hầu hết các trường hợp liên quan đến list dữ liệu, ta đều phải xử lý bằng các xác định thứ tự của chúng trong list đấy.
Ví dụ:
<ul class="fruits"> <li>Apple</li> <li>Orange</li> <li>Pear</li> </ul>
Muốn trỏ tới vị trí nào, chúng ta chỉ cần add thêm:
nth-of-type(order)
Ví dụ, ta muốn trỏ tới vị trí số 2 “Orange”, selector của chúng ta sẽ là:
.fruits li:nth-of-type(2)
6. Kỹ thuật CSS Selector cho case khó
Đôi khi bạn thử những cách trên riêng rẽ, bạn sẽ thấy là nó sẽ matching nhiều hơn 1 node. Do đó, ta cần phải thêm điều kiện để nó chỉ matching đúng 1 note duy nhất. Hãy đọc bài này để biết cách xử lý.
III. Làm thế nào để biết mình đã lấy đúng CSS selectors?
Bật Chrome > Inspect
Sau đó trỏ chuột vào phần Element, bấm CTRL + F, nó sẽ xuất hiện như hình.
Bạn hãy thử các CSS Selector vào khung kia để kiểm tra kết quả. Have Fun!
Nếu có bất cứ thắc mắc gì, hãy để lại comment nhé.
Bài viết có lấy tư liệu từ bài https://ghostinspector.com/blog/css-selector-strategies-automated-browser-testing/
Bài viết rất hay, Cảm ơn bạn rất nhiều, bổ sung cho mình rất nhiều kiến thức, mong rằng bạn sẽ cập nhật nhiều bài viết nữa nha, mình sẽ luôn theo dõi, Chúc bạn thật nhiều sức khoẻ, thành công.
Thank bạn nhiều. Cảm ơn vì đã luôn ủng hộ mình và hi vọng những cái mình viết giúp ích phần nào đó cho bạn. ^^
[…] [Bài 3] Xác định elements bằng CSS Selector trong Selenium Webdriver […]
Tiếp tục ra lò những bài hướng dẫn mới nha anh, ủng hộ anh
Thank em. Anh sẽ viết tiếp nhưng mà đọc 10 mới viết được 1, nên viết chắc sẽ hơi chậm.
Em đã đọc các bài viết trên blog của anh, rất hay và bổ ích ạ. Hi vọng anh cập nhật thêm nhiều bài học về chủ đề này, luôn dõi theo blog của anh ^^
Hi, tks em nhiều. Sẽ cố gắng trong thời gian tới vậy.
=)))) mỗi ngày bớt 30 mins đế chế là đc mà
vâng. haha
Tôi tìm 1 element trong web bằng CSS, ví du như .prev và tui xài FirePath để kiểm tra mình lấy CSS đúng ko.
Kết quả ra 5 matching nodes, làm sao tôi có thể lấy chính xác cái CSS tôi mong muốn?
Hi bạn, để lấy được css mong muốn, thông thường phải kết hợp thêm điều kiện, bạn có thể kết hợp những phần mình đã hướng dẫn ở toàn bài. Bạn cũng có thể đọc thêm bài này tham khảo: https://giangtester.com/bai-21-cach-su-dung-css-selector-cho-nhung-case-kho/
Cảm ơn tác giả
Cảm ơn bạn đã ghé thăm blog của mình. ^^
[…] Post” bằng cssSelector, bạn nào chưa biết cách sử dụng chúng thì đọc lại bài này […]
[…] sao mình lại có thể xác định được cái css thế kia, các bạn hãy đọc lại bài 3 […]
[…] đã có 1 bài nói về những cách sử dụng CSS cơ bản nhưng vì trong thực tế, sẽ không có nhiều trường hợp chỉ cần dùng 1 attribute […]
Để xử lý cái “của nợ” này, thì có 2 cách và sẽ được nói ở phía dưới:
1 là matching Id theo kiểu wild card
2 là sử dụng cách xác định khác
Mình thắc mắc kiểu wild card ở đây là gi?
Đó chính là các ký tự *, ^, $, muốn biết detail thêm thì google nhé.
Hay thật, xưa em mù cách xác định các thẻ trong css, bài của ad vừa chi tiết mà đụng trọng tâm nên bây giờ vấn đề này được giải quyết nhanh gọn. Cảm ơn ad nhiều
Yeah. 😀