Nội dung bài viết
I. Script thực hiện search và check kết quả
Tiêu đề có vẻ ghê chết thôi chứ script của bài này cũng không phải là khó lắm, cứ bình tĩnh. Những bài trước đã nói về các script đơn giản vì các step không quá dài, cách thực hiện step không khó và việc check kết quả cũng không phức tạp. Bài này các bạn sẽ phải làm 1 test mà cách check kết quả của nó phức tạp hơn nhiều lần, còn các step thì vẫn đơn giản.
- Test chức năng search ở Page AllPosts
Lưu ý: Tìm kiếm của WordPress sẽ trả về kết quả là 1 list các bài viết mà có Title hoặc Body có chứa từ khóa đó. Ví dụ như trong hình, có đến 3 bài viết ở dưới là không có từ khóa trong Title.
Khi search thì kết quả trả về sẽ có 2 trường hợp:
- Không có kết quả nào match (các bạn tự xử lý)
- Có kết quả match
Nếu sau khi search, có nhiều kết quả trả về, ta lại gặp vào 2 trường hợp:
- Số lượng post có chứa keyword ít, nhỏ hơn hoặc bằng 1 page kết quả.
- Số lượng post có chứa keyword lớn, có nhiều hơn 1 page kết quả (sẽ viết 1 bài về phân trang sau).
Chốt lại testcase của ta sẽ xử lý là:
- Test chức năng search, khi có số lượng bài viết match với keyword chỉ nằm trên 1 page. Nói cách khác, số lượng bài viết lớn hơn 1 và nhỏ hơn hoặc bằng 20 vì page phân trang mặc định của wordpress là 20 items.
Với testcase này, ta sẽ có flow test như sau:
- Vào trang AllPosts
- Điền keyword và search
- Kiểm tra title và body của từng bài viết xem có chứa keyword hay không.
Nhưng sẽ không giống như những bài trước, ở bài này mình sẽ hướng dẫn cách viết Test theo phương pháp Test-Driven, có nghĩa là ta sẽ viết Test case trước khi viết các phần Implement code.
- Viết luôn test, mình muốn trình tự test và cách check kết quả thế nào thì phải xác định trước.
- Step nào chưa làm thì tự implement từng cái 1, theo thứ tự trừ trên xuống dưới.
Test case sẽ như sau:
@Test public void searchPost(){ loginPg = new LoginPage(driver); dashBoardPg = loginPg.loginSuccess(); allPostPg = dashBoardPg.moveToAllPostsPage(); allPostsPg.searchPost("ocean"); Assert.assertTrue(allPostPg.hasKeyword("ocean")); }
Với method searchPost, ta chỉ cần implement đơn giản như sau:
public class AllPostsPage extends BasePage { ... @FindBy(id = "post-search-input") private WebElement searchInput; @FindBy(id = "search-submit") private WebElement searchBtn; .... public void searchPost(String keyword) { searchInput.sendKeys(keyword); searchBtn.click(); } }
Với method hasKeyword, ta kỳ vọng là nó sẽ return lại kết quả là True, có nghĩa là Title hoặc Body sẽ có chứa keyword đó:
- Trong list các Post sau khi search, check lần lượt xem các Title có chứa keyword không.
- Nếu gặp Title không chứa keyword thì phải open post, rồi check body xem có keyword không.
- Sau khi so sánh trong body xong rồi thì back lại về trang list kết quả. Nếu cả Title và Body đều không có keyword thì return False.
- Tiếp tục làm tương tự với post tiếp theo. Nếu tất cả các post có chứa keyword thì return True.
Mình sẽ viết đoạn này như sau:
public class AllPostsPage extends BasePage { ... @FindBy(css = "#the-list strong a") private List<WebElement> postList; ... public boolean hasKeyword(String keyword) { String kw = keyword.toLowerCase(); List<Boolean> searchValues = new ArrayList<>(); for (int i = 0; i < postList.size(); i++) { boolean found = false; if(titleHasKeyword(i, kw)){ found = true; } else { found = bodyHasKeyword(kw); } searchValues.add(found); } return searchValues.stream().allMatch(v -> v); } private boolean titleHasKeyword(int index, String kw) { String postTitle = postList.get(index).getText().toLowerCase(); return postTitle.contains(kw); } private boolean bodyHasKeyword(String kw) { List<WebElement> paragraphs = driver.findElements(By.cssSelector("#tinymce p")); return paragraphs.stream() .map(p -> p.getText().toLowerCase()) .anyMatch(content -> content.contains(kw)); } }
Phân tích từng đoạn code:
Đây là khai báo PageFactory cho List các Elements, ở đây là list các Posts.
@FindBy(css = "#the-list strong a") private List<WebElement> postList;
Đây là đoạn check xem title có chứa keywork không.
private boolean titleHasKeyword(int index, String kw) { String postTitle = postList.get(index).getText().toLowerCase(); return postTitle.contains(kw); }
Check từng paragraph xem có keyword không, nếu chỉ cần 1 paragraph có keyword, lập tức return true. Mình dùng function anyMacth()
của Java Stream
private boolean bodyHasKeyword(String kw) { List<WebElement> paragraphs = driver.findElements(By.cssSelector("#tinymce p")); return paragraphs.stream() .map(p -> p.getText().toLowerCase()) .anyMatch(content -> content.contains(kw)); }
Vì sao lại check paragraphs? Đó là vì 1 body là tập hợp của nhiều paragraph khác nhau, và rất nhiều các thẻ loại khác như h1,h2,..,h6, pre nhưng mà mình lười nên mình chỉ viết cái method check paragraphs thôi, các loại khác cũng làm tương tự.
Cuối cùng check cả post có keyword hay không.
public boolean hasKeyword(String keyword) { String kw = keyword.toLowerCase(); List<Boolean> searchValues = new ArrayList<>(); for (int i = 0; i < postList.size(); i++) { boolean found = false; if(titleHasKeyword(i, kw)){ found = true; } else { found = bodyHasKeyword(kw); } searchValues.add(found); } return searchValues.stream().allMatch(v -> v); }
Logic của đoạn này như sau:
Vì mình có nhiều post phải check, nên mình sẽ gom tất cả kết quả check của các post vào trong 1 List List searchValues
- Với mỗi post –> check title trước –> nếu title có kw –> true và dừng luôn.
- Nếu title ko có kw –> check tiếp body –> body có kw –> true, nếu ko có return false.
- Lưu kết quả này vào trong
searchValues
Cuối cùng gom tất cả kết quả này bằng function allMatch()
của Java Stream. Nếu toàn bộ các post đều chứa keyword thì return true, nếu chỉ 1 post không thỏa mãn thì return false.
II. Kết bài
Vậy thôi, bài cũng hơi dài là lắm thứ loằng ngoằng, mình không thể giải thích được hết được, hi vọng là sau nhiều bài với độ phức tạp tăng dần, các bạn sẽ hiểu hơn về cách viết code Selenium Webdriver. Nó không khó cũng chẳng dễ, nó chỉ cần kỹ năng lập trình cơ bản và động lực để học thôi. 😀
#Edit 1: Sửa lại toàn bộ code, update sử dụng Java Stream function.
[…] [Bài 22] Webdriver script không đơn giản thứ nhất […]
Cảm ơn những bài viết vừa đáng yêu vừa bổ ích của anh.
Chờ đợi những bài kế tiếp ạ 🙂
Thanks em! 😀
Series của bạn đã giúp đỡ mình vượt qua được những bước đầu tiên với automation. Hi vọng là bạn có thể dành chút thời gian và cho ra nhiều bài hơn nữa.
Thanks bạn, mình cũng có dự định viết thêm những bài khác nữa, nhưng hiện tại chưa có thời gian để viết, đang tập trung làm việc khác. Tầm tháng 11 mình sẽ trở lại và viết tiếp.
em cũng đang hóng những bài viết của anh
Dạo này anh hơi bận, cũng ko làm selenium nên hơi lười viết bài. 😀
anh ơi cho em hỏi “postList” gọi từ đâu vậy ạ
postList chính là những posts có trong AllPostsPage thôi em, nó được tìm kiếm dựa trên css.
@FindBy(css = “#the-list strong a”)
private List WebElement> postList;
Nhờ anh giải thích hộ em đoạn này với ạ:
driver.switchTo().frame(“content_ifr”);
driver.switchTo().defaultContent();
Em đọc lại bài https://giangtester.com/bai-11-webdriver-script-don-gian-thu-hai/
Ở đây, anh có nói là phần body của bài viết nó nằm trong 1 cái iframe, nên muốn tìm được body thì phải chuyển driver từ DOM vào iframe trước. Sau khi mình vào vào iframe và thực hiện hành động xong rồi thì mình back lại về DOM như bình thường.
trong hasKeyword có dòng driver.navigate().back();
bạn có thể giải thích vì sao dùng dòng ở đây ko ?
thanks.
Mình trả lại đúng state sau khi trải qua 1 số step để check điều kiện, kiểu như bạn mở tủ lấy cốc, dùng cốc xong thì bạn trả lại vào tủ và đóng tủ lại. 😀 Bạn có thể không cần back lại, cũng không vấn đề gì.
với cốc cốc thì khởi tạo driver như thế nào a
Đây bạn https://sangbui.com/selenium-webdriver-test-with-coccoc/
Cảm ơn những bài viết của em . Nó giúp em rất nhiều.
Em muốn hỏi :
Trong đoạn này , mình chỉ cần check xem body của trang post đó có keyword mình tìm kiếm hay không thôi(là chỉ check content thôi đúng ko ạ), thì tại sao mình lại phải check thêm các thẻ như h1 h2 làm gì ạ?
Đúng là chỉ cần check content nhưng content của 1 bài viết bằng wordpress được thể hiện bằng nhiều thẻ khác nhau, vd: p, h1,h2..h6,pre,ol,ul…
Giả sử keyword của bạn search nó lại nằm ở thẻ h1 thì sao? Nếu chỉ check paragraphs thì đâu thấy được.
Dù gì đi chăng nữa, đây chỉ là tham khảo thôi, bạn cũng ko cần chi tiết quá, hiểu ý tưởng là được rồi.
Dòng 13 của phương thức hasKeyword, mình nghĩ lẽ ra nên check if bodyHasKeyword(keyword) == false thì return false. Để như hiện tại thì hàm check bodyHasKeyword đâu có giá trị gì
Cảm ơn bạn, để mình sửa lại.