Lỗi này xảy ra khi nào?
- Lúc đầu bạn tương tác vào DOM của trang web, selenium lưu lại reference đến element đó. Ví dụ:
x --> WebElement A
, x ở đây là reference. - Khi trang web của bị refresh thì DOM được tạo lại, dẫn đến tình trạng, reference bị stale (hỏng, ôi thiu, từ stale này hay dùng cho đồ ăn), có nghĩa là reference
x
này không trỏ đếnWebElement A
mới mà đang trỏ vào cáiWebElement A
cũ. - Khi bạn dùng
x
như click() hoặc getText() thì có nghĩa bạn đang trỏ vào thằngWebElement A
cũ –> bị Stale Element Reference Exception.
Các cách để fix lỗi này:
Nội dung bài viết
I. Thêm wait time
- Hãy đợi 1 khoảng thời gian, ví dụ:
Thread.sleep(3000)
–> đợi 3s - Rồi get lại Element mà mình muốn tương tác:
var name = driver.getElement(username).getText();
Cách này có điểm dở là:
- Có khi thời gian đợi không đủ, có khi 2s, có khi là 5s. Khi nó chỉ cần 2s mà mình đợi 3s thì đợi thừa mất 1s, còn khi nó cần đến 5s mà mình chỉ đợi 3s sẽ vẫn bị Stale Element Reference Exception
II. Kết thúc hành động ở trạng thái ready
- Khi 1 hành động tương tác với DOM, hãy đợi đến khi trang web refresh xong, hoàn thành việc render.
Ví dụ:
- Click button A –> refresh 1 phần của trang web –> hãy đợi đến khi 1 Element nào đó thay đổi trạng thái, đừng wait chính cái element mà đang bị Stale Element Reference Exception. Giả sử bạn đang muốn lấy
Item Two
đừng kiểm tra chínhItem Two
mà hãy dùngText X
@Test void checkItemTwo(){ clickA(); wait.util(ExpectedConditions.invisibilityOfElementLocated(TextX)); getItemTwo(); }
Vì mục tiêu là để web ở trạng thái ready sau khi 1 hành động được diễn ra, nên wait kia nên đặt vào trong method clickA()
.
@Test void checkItemTwo(){ clickA(); getItemTwo(); } void clickA(){ ... wait.util(ExpectedConditions.invisibilityOfElementLocated(TextX)); }
III. Retry đến khi tương tác được thì thôi.
Flow có thể như sau:
- Get
Item Two
, nếu bị StaleElementReferenceException thì tiếp tục get lại thêm 1 lần nữa, giữa 2 lần tương tác sẽ đợi tầm 500ms. Hết n lần retry mà không được khi throw ra RuntimeException.
public String retryGetText(By by) { int attempts = 0; while (attempts < 5) { try { return driver.findElement(by).getText(); } catch (StaleElementReferenceException e) {} attempts++; waitIn(500); } throw new RuntimeException("Cannot get text from element: " + by);; } private void waitIn(long mili){ try { Thread.sleep(mili); } catch (Exception ignored) {} }
IV. Tổng kết
Trên đây là 1 vài cách để xử lý Stale Element Reference Exception, nếu nó vẫn không work thì bạn nên kết hợp các cách này với nhau. Đây là nỗi nhức nhối của các ace tester, hi vọng bài viết có ích, chứ mình đi fix dạo lỗi này cũng thấy mệt. T__T