Chào các bạn đã đến với chủ đề tiếp theo của mình. Hôm nay, mình sẽ tiếp tục giới thiệu về các loại wait trong Selenium. Trong Selenium, việc wait này rất quan trọng khi thực thi test case. Nó sẽ giúp cho test case chạy ổn định hơn giữa những lần run test. Vì 1 lý do nào đó (ví dụ như server yếu, hoặc là đường truyền internet có vấn đề), nên ở mỗi lần chạy, trang web có thể chạy nhanh/chậm khác nhau. Lúc này, test script của chúng ta có thể gặp 1 số lỗi như NoSuchElementException hoặc StaleElementReferenceException … Để giải quyết vấn đề này, Selenium webdriver cung cấp cho chúng ta 3 loại Wait như hình bên dưới:
Ở những ví dụ trước, mình đang sử dụng wait dưới dạng hard code: Thread.sleep(timeout). Cách dùng này có lẽ là các bạn đã quá quen thuộc với các bạn, nhất là khi mới bắt đầu học automation. Tuy nhiên, cách này có 1 số hạn chế nhất định. Nên khi build framework, ít ai sử dụng cách này. Thay vào đó, chúng ta sẽ sử dụng các loại wait mà Selenium cung cấp.
Bây giờ chúng ta hãy đi vào nội dung chính của bài hôm nay nhé.
1. Implicit Wait
Dịch ra tiếng việt là “đợi ngầm”, có nghĩa là nó sẽ luôn tìm kiếm Element trong 1 khoảng thời gian ngầm định trước khi ném ra lỗi No Such Element Exception.
Ví dụ:
driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(10));
Trong ví dụ trên, mình sẽ luôn tìm kiếm 1 element trong khoảng thời gian timeout là 10s. Sau 10s mà không tìm thấy thì sẽ văng ra Exception.
Lưu ý:
Phương thức Wait này nó là static setting, có nghĩa là nó sẽ áp dụng cho tất cả các trường hợp có sử dụng method findElement(). Điều này dẫn đến 2 kết quả:
- Bạn chỉ cần viết 1 dòng này duy nhất ở trong project, không cần viết đến dòng thứ 2. Thi thoảng mình vẫn thấy các bạn fresher mới học viết dòng này tràn lan ở bất kỳ chỗ nào mà bạn cho là phải đợi.
- Giả sử bạn viết dòng này ở trong test1() thì nó vẫn sẽ có tác dụng test2(), test3()….
Và hậu quả của việc này là:
- Như đã nói ở trên, thời gian run test vì nhiều nguyên nhân nên chẳng có lần nào giống lần nào. Khi page load nhanh, bạn để timeout là 5s, khi page load chậm, bạn bị lỗi, phải tăng lên 10s. Sau 1 hồi sửa đi sửa lại, có thể bạn sẽ setup timeout là 30s và đặt nó ở trong @BeforeTest cũng nên. Và thế là bạn tự làm chậm test automation, cái mà được coi là tiết kiệm thời gian cho manual.
- Có những khi Web thay đổi UI, thay vì test fail ngay lập tức thì nó sẽ phải đợi 1 khoảng thời gian để báo fail. Nếu 1, 2 test thì cũng không vấn đề nhưng nếu có 100 tests thì thời gian chờ lãng phí rất là nhiều.
Vì vậy để sử dụng hiệu quả thì nhiều test expert khuyên:
- Không nên sử dụng Implicit Wait vì nó lãng phí thời gian hơn là lợi ích nó mang lại.
- Nếu có sử dụng Implicit Wait trong 1 test nào đó thì khi clean up ở @AfterTest nên reset lại thời gian timeouts, để nó không còn ảnh hưởng đến những test khác.
@AfterTest
public void tearDown(){
driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(0));
driver.quit();
}
2. Explicit Wait
Dich tiếng việt là “cố tình đợi”, Explicit wait được sử dụng để tạm dừng việc thực thi script cho đến khi một điều kiện cụ thể được chỉ định được đáp ứng.
Khác với Implicit wait, Explicit wait chỉ được áp dụng cho một trường hợp cụ thể thay vì dùng cho toàn bộ các lệnh trong script.
Nó đợi theo trạng thái (state) của Element và Page thay vì phụ thuộc vào thời gian (timeout).
Nếu chúng ta đang sử dụng kết hợp cả hai loại Wait trên thì có 2 trường hợp như sau:
- Nếu Explicit Wait dùng câu lệnh tìm kiếm là đối tượng By thì Explicit Wait sẽ được ưu tiên đầu tiên.
- Nếu Explicit Wait dùng câu lệnh tìm kiếm là findElement thì Implicit Wait sẽ được ưu tiên đầu tiên.
Explicit Wait nằm trong pagekage org.openqa.selenium.support.ui
với 2 package con:
import org.openqa.selenium.support.ui.ExpectedConditions
import org.openqa.selenium.support.ui.WebDriverWait
Và nó hoạt động theo cơ chế:
- Nó sẽ bảo WebDriver là đợi cho đến khi điều kiện (ExpectedCondition) được thỏa mãn hoặc hết thời gian timeouts, nó sẽ bắn ra exception tùy theo điều kiện, ví dụ như ElementNotVisibleException, ElementNotInteractableException, TimeoutException…
Có 2 điểm lưu ý:
- Nếu trong thời gian đợi, nếu có exception NotFoundException thì exception cũng sẽ bị bỏ qua.
- Và WebDriver sẽ check điều kiện có được thỏa mãn không sau 1 khoảng interval là 500ms
Khởi tạo Object cho class WebDriverWait
explicitWait = new WebDriverWait(driver, Duration.ofSeconds(10));
- Chúng ta sẽ tạo một biến tham chiếu “explicitWait ” cho lớp WebDriverWait và khởi tạo nó bằng cách sử dụng WebDriver và khai báo thời gian timeout. Thời gian chờ tối đa này được tính bằng “giây” (trong ví dụ này đang set là 10s)
- Ví dụ:
explicitWait = new WebDriverWait(driver, Duration.ofSeconds(10));
wait.until(ExpectedConditions.visibilityOfElementLocated(By.xpath("//h3[contains(text(),'Website Testing')]")));
driver.findElement(By.xpath("//h3[contains(text(),'Website Testing')]")).click();
Expected Condition
- Lớp
ExpectedConditions
cung cấp một bộ trợ giúp tuyệt vời để giải quyết các tình huống trong đó chúng ta phải xác định điều kiện xảy ra trước khi thực thi các step test thực tế.
- Lớp
ExpectedConditions
đi kèm với một loạt các điều kiện mong đợi có thể được truy cập với sự trợ giúp của biến tham chiếuWebDriverWait
và phương thứcuntil()
.
Một số Expected Conditions điển hình:
#1) elementToBeClickable() – Điều kiện mong đợi là chờ một phần tử có thể click được, tức là phần tử đó phải hiện diện / được hiển thị trên màn hình và phải enabled (có thể click).
wait.until(ExpectedConditions.elementToBeClickable(By.xpath("//button[text()='Login'")));
#2) textToBePresentInElement() – Điều kiện mong đợi là chờ một phần tử chứa đoạn text được chỉ định.
wait.until(ExpectedConditions.textToBePresentInElement(By.xpath("//div[@id= 'forgotPass'"), "text to be found"));
#3) alertIsPresent() – Điều kiện mong đợi là chờ Alert xuất hiện.
wait.until(ExpectedConditions.alertIsPresent()) !=null);
#4) titleIs() – Điều kiện mong đợi là chờ một trang có tiêu đề cụ thể.
wait.until(ExpectedConditions.titleIs("Automation Testing"));
#5) frameToBeAvailableAndSwitchToIt() – Điều kiện mong đợi là chờ một khung có sẵn (available) và ngay sau khi có khung, điều khiển sẽ tự động chuyển sang nó.
wait.until(ExpectedConditions.frameToBeAvailableAndSwitchToIt(By.id("newframe")));
#6) visibilityOfElementLocated() – được sử dụng để kiểm tra xem một phần tử có trên DOM của một trang và hiển thị hay không. Có nghĩa là nó sử dụng đối tượng By thay vì đối tượng WebElement với chức năng có thể gọi để tìm phần tử đó trước rồi kiểm tra phần tử đó có hiển thị hay không.
wait.until(ExpectedConditions.visibilityOfElementLocated(By.xpath("//h3[contains(text(),'Website Testing')]")));
driver.findElement(By.xpath("//h3[contains(text(),'Website Testing')]")).click();
#7) visibilityOf() – được sử dụng để kiểm tra xem một phần tử hiện diện trên DOM của một trang có hiển thị hay không. Có nghĩa là bạn đã tìm thấy Element đó rồi và chỉ kiểm tra nó có hiển thị hay chưa. Nên tham số nó kiểm tra là 1 đối tượng WebElement chứ không phải đối tượng By.
wait.until(ExpectedConditions.visibilityOf(driver.findElement(By.xpath("//h3[contains(text(),'Website Testing')]"))));
driver.findElement(By.xpath("//h3[contains(text(),'Website Testing')]")).click();
Ví dụ:
@Test
public void TC_02_ExplicitWait() throws InterruptedException {
driver.get("http://the-internet.herokuapp.com/login");
// Input to username & password
explicitWait.until(ExpectedConditions.visibilityOfElementLocated(By.id("username")));
driver.findElement(By.id("username")).sendKeys("tomsmith");
driver.findElement(By.id("password")).sendKeys("SuperSecretPassword!");
// Click login button
driver.findElement(By.xpath("//button[@type='submit']")).click();
// Get welcome message
explicitWait.until(ExpectedConditions.visibilityOfElementLocated(By.xpath("//h4")));
String welcomeMessage = driver.findElement(By.xpath("//h4")).getText();
Assert.assertEquals(welcomeMessage, "Welcome to the Secure Area. When you are done click logout below.");
}
Hiện tại Selenium có rất nhiều các condition khác nhau, tùy theo nhu cầu thực test mà các bạn lựa chọn sử dụng cho phù hợp nhé.
3. Fluent Wait
Mục tiêu của Fluent Wait là cung cấp 1 cơ chế Wait chung, có thể ứng dụng được nhiều chỗ, không chỉ ứng dụng cho mỗi WebDriver, và nó chính là cha của Explicit Wait phía trên. Nói chính xác hơn thì:
public class WebDriverWait extends FluentWait<WebDriver>;
Với Fluent Wait, mình có thể config con số interval và sẽ ignore Exception nào. Điểm này rất hữu dụng vì WebDriverWait chỉ ignore mỗi NotFoundException, trong khi đó mình có thể gặp các Exception khác mà mình cũng muốn ignore như StaleElementReferenceException.
Wait<WebDriver> wait = new FluentWait<WebDriver>(driver)
.withTimeout(Duration.ofSeconds(30))
.pollingEvery(Duration.ofSeconds(5))
.ignoring(NoSuchElementException.class, StaleElementReferenceException.class);
// Chờ 30 giây để một phần tử hiện diện trên trang
// Và sẽ thực hiện lặp lại mỗi 5 giây nếu chưa tìm thấy phần tử đó
Sau đó, bạn vẫn sử dụng như Wait của Explicit Wait thôi
wait.until(ExpectedConditions.elementToBeClickable(linkToClick));
4. Lời kết
Như vậy chúng ta đã tìm hiểu qua cách sử dụng các loại Wait với Selenium. Cảm ơn các bạn đã theo dõi bài viết của mình. Chúc các bạn thành công. Hẹn gặp lại các bạn ở những chủ đề tiếp theo.
Nguồn:
https://giangtester.com/phan-biet-va-su-dung-implicit-wait-explicit-wait-va-fluent-wait/
https://anhtester.com/blog/selenium-java/selenium-java-bai-15-cach-dung-wait-trong-selenium-java