Có thể nói WebDriver thường có API chặn. Bởi vì nó là một thư viện ngoài quy trình hướng dẫn trình duyệt phải làm gì và vì nền tảng web có bản chất không đồng bộ nội tại, nên WebDriver không theo dõi trạng thái hoạt động, thời gian thực của DOM. Điều này đi kèm với một số thách thức mà chúng ta sẽ thảo luận ở đây
Theo kinh nghiệm, hầu hết các sự cố không liên tục phát sinh từ việc sử dụng Selenium và WebDriver đều liên quan đến các điều kiện tương tranh xảy ra giữa trình duyệt và hướng dẫn của người dùng. Một ví dụ có thể là người dùng hướng dẫn trình duyệt điều hướng đến một trang, sau đó gặp lỗi không có phần tử như vậy khi cố gắng tìm một phần tử
Xem xét tài liệu sau
Race Condition Example
Các hướng dẫn WebDriver có thể trông đủ ngây thơ
driver.get["file:///race_condition.html"];
WebElement element = driver.findElement[By.tagName["p"]];
assertEquals[element.getText[], "Hello from JavaScript!"];
driver.navigate["file:///race_condition.html"]
el = driver.find_element[By.TAG_NAME, "p"]
assert el.text == "Hello from JavaScript!"
driver.Navigate[].GoToUrl["file:///race_condition.html"];
IWebElement element = driver.FindElement[By.TagName["p"]];
assertEquals[element.Text, "Hello from JavaScript!"];
require 'selenium-webdriver'
driver = Selenium::WebDriver.for :firefox
begin
# Navigate to URL
driver.get 'file:///race_condition.html'
# Get and store Paragraph Text
search_form = driver.find_element[:css,'p'].text
"Hello from JavaScript!".eql? search_form
ensure
driver.quit
end
await driver.get['file:///race_condition.html'];
const element = driver.findElement[By.css['p']];
assert.strictEqual[await element.getText[], 'Hello from JavaScript!'];
driver.get["file:///race_condition.html"]
val element = driver.findElement[By.tagName["p"]]
assert[element.text == "Hello from JavaScript!"]
Vấn đề ở đây là mặc định được sử dụng trong WebDriver lắng nghe
driver.Navigate[].GoToUrl["file:///race_condition.html"];
IWebElement element = driver.FindElement[By.TagName["p"]];
assertEquals[element.Text, "Hello from JavaScript!"];
7 để thay đổi thành driver.Navigate[].GoToUrl["file:///race_condition.html"];
IWebElement element = driver.FindElement[By.TagName["p"]];
assertEquals[element.Text, "Hello from JavaScript!"];
8 trước khi quay lại cuộc gọi để điều hướng. Vì phần tử driver.Navigate[].GoToUrl["file:///race_condition.html"];
IWebElement element = driver.FindElement[By.TagName["p"]];
assertEquals[element.Text, "Hello from JavaScript!"];
9 được thêm vào sau khi tải xong tài liệu, tập lệnh WebDriver này có thể bị gián đoạn. Nó “có thể” không liên tục vì không thể đảm bảo về các yếu tố hoặc sự kiện kích hoạt không đồng bộ mà không cần chờ—hoặc chặn—đối với các sự kiện đó một cách rõ ràngMay mắn thay, tập lệnh thông thường có sẵn trên giao diện WebElement—chẳng hạn như WebElement. nhấp chuột và WebElement. sendKeys—được đảm bảo là đồng bộ, trong đó lệnh gọi hàm sẽ không trả về [hoặc lệnh gọi lại sẽ không kích hoạt trong các ngôn ngữ kiểu gọi lại] cho đến khi lệnh được hoàn thành trong trình duyệt. Các API tương tác người dùng nâng cao, Bàn phím và Chuột, là những ngoại lệ vì chúng được dự định rõ ràng là các lệnh không đồng bộ “hãy làm những gì tôi nói”
Chờ đợi là việc thực thi tác vụ tự động trôi qua trong một khoảng thời gian nhất định trước khi tiếp tục với bước tiếp theo
Để khắc phục vấn đề về điều kiện tương tranh giữa trình duyệt và tập lệnh WebDriver của bạn, hầu hết các ứng dụng khách Selenium đều gửi gói chờ. Khi sử dụng một sự chờ đợi, bạn đang sử dụng những gì thường được gọi là một
chờ đợi rõ ràng
Chờ đợi rõ ràng có sẵn cho khách hàng Selenium cho các ngôn ngữ thủ tục, mệnh lệnh. Chúng cho phép mã của bạn tạm dừng thực thi chương trình hoặc đóng băng chuỗi cho đến khi điều kiện bạn vượt qua nó được giải quyết. Điều kiện được gọi với tần suất nhất định cho đến khi hết thời gian chờ. Điều này có nghĩa là miễn là điều kiện trả về giá trị sai, nó sẽ tiếp tục cố gắng và chờ đợi
Vì các khoảng chờ rõ ràng cho phép bạn đợi một điều kiện xảy ra nên chúng rất phù hợp để đồng bộ hóa trạng thái giữa trình duyệt và DOM của nó và tập lệnh WebDriver của bạn
Để khắc phục tập lệnh lỗi của chúng tôi từ trước đó, chúng tôi có thể sử dụng thời gian chờ để lệnh gọi findElement đợi cho đến khi phần tử được thêm động từ tập lệnh đã được thêm vào DOM
WebDriver driver = new ChromeDriver[];
driver.get["//google.com/ncr"];
driver.findElement[By.name["q"]].sendKeys["cheese" + Keys.ENTER];
// Initialize and wait till element[link] became clickable - timeout in 10 seconds
WebElement firstResult = new WebDriverWait[driver, Duration.ofSeconds[10]]
.until[ExpectedConditions.elementToBeClickable[By.xpath["//a/h3"]]];
// Print the first result
System.out.println[firstResult.getText[]];
from selenium.webdriver.support.wait import WebDriverWait
def document_initialised[driver]:
return driver.execute_script["return initialised"]
driver.navigate["file:///race_condition.html"]
WebDriverWait[driver, timeout=10].until[document_initialised]
el = driver.find_element[By.TAG_NAME, "p"]
assert el.text == "Hello from JavaScript!"
driver = new ChromeDriver[];
driver.Url = "//www.google.com/ncr";
driver.FindElement[By.Name["q"]].SendKeys["cheese" + Keys.Enter];
WebDriverWait wait = new WebDriverWait[driver, TimeSpan.FromSeconds[10]];
IWebElement firstResult = wait.Until[e => e.FindElement[By.XPath["//a/h3"]]];
Console.WriteLine[firstResult.Text];
driver.get["file:///race_condition.html"];
WebElement element = driver.findElement[By.tagName["p"]];
assertEquals[element.getText[], "Hello from JavaScript!"];
0driver.get["file:///race_condition.html"];
WebElement element = driver.findElement[By.tagName["p"]];
assertEquals[element.getText[], "Hello from JavaScript!"];
1driver.get["file:///race_condition.html"];
WebElement element = driver.findElement[By.tagName["p"]];
assertEquals[element.getText[], "Hello from JavaScript!"];
2Chúng ta chuyển vào điều kiện dưới dạng tham chiếu hàm mà lệnh chờ sẽ chạy lặp lại cho đến khi giá trị trả về của nó là true. Giá trị trả về “trung thực” là bất kỳ giá trị nào có giá trị boolean true trong ngôn ngữ hiện tại, chẳng hạn như chuỗi, số, boolean, đối tượng [bao gồm WebElement] hoặc chuỗi hoặc danh sách được điền [không trống]. Điều đó có nghĩa là một danh sách trống đánh giá là sai. Khi điều kiện là đúng và chờ chặn bị hủy bỏ, giá trị trả về từ điều kiện sẽ trở thành giá trị trả về của chờ
Với kiến thức này, và bởi vì tiện ích chờ mặc định bỏ qua các lỗi phần tử như vậy, chúng ta có thể cấu trúc lại các hướng dẫn của mình để ngắn gọn hơn
driver.get["file:///race_condition.html"];
WebElement element = driver.findElement[By.tagName["p"]];
assertEquals[element.getText[], "Hello from JavaScript!"];
3driver.get["file:///race_condition.html"];
WebElement element = driver.findElement[By.tagName["p"]];
assertEquals[element.getText[], "Hello from JavaScript!"];
4driver.get["file:///race_condition.html"];
WebElement element = driver.findElement[By.tagName["p"]];
assertEquals[element.getText[], "Hello from JavaScript!"];
5driver.get["file:///race_condition.html"];
WebElement element = driver.findElement[By.tagName["p"]];
assertEquals[element.getText[], "Hello from JavaScript!"];
6driver.get["file:///race_condition.html"];
WebElement element = driver.findElement[By.tagName["p"]];
assertEquals[element.getText[], "Hello from JavaScript!"];
7driver.get["file:///race_condition.html"];
WebElement element = driver.findElement[By.tagName["p"]];
assertEquals[element.getText[], "Hello from JavaScript!"];
8Trong ví dụ đó, chúng tôi chuyển vào một hàm ẩn danh [nhưng chúng tôi cũng có thể định nghĩa nó một cách rõ ràng như chúng tôi đã làm trước đó để nó có thể được sử dụng lại]. Đối số đầu tiên và duy nhất được chuyển đến điều kiện của chúng tôi luôn là tham chiếu đến đối tượng trình điều khiển của chúng tôi, WebDriver. Trong môi trường đa luồng, bạn nên cẩn thận thao tác trên tham chiếu trình điều khiển được truyền vào điều kiện thay vì tham chiếu đến trình điều khiển ở phạm vi bên ngoài
Vì quá trình chờ sẽ không nuốt các lỗi phần tử như vậy được nêu ra khi không tìm thấy phần tử, nên điều kiện sẽ thử lại cho đến khi phần tử được tìm thấy. Sau đó, nó sẽ nhận giá trị trả về, một WebElement và chuyển nó trở lại tập lệnh của chúng ta
Nếu điều kiện thất bại, e. g. không bao giờ đạt được giá trị trả về trung thực từ điều kiện, thời gian chờ sẽ ném/tăng lỗi/ngoại lệ được gọi là lỗi hết thời gian chờ
Tùy chọn
Điều kiện chờ có thể được tùy chỉnh để phù hợp với nhu cầu của bạn. Đôi khi, không cần thiết phải chờ hết thời gian chờ mặc định, vì hình phạt nếu không đạt được điều kiện thành công có thể rất tốn kém
Sự chờ đợi cho phép bạn chuyển vào một đối số để ghi đè thời gian chờ
driver.get["file:///race_condition.html"];
WebElement element = driver.findElement[By.tagName["p"]];
assertEquals[element.getText[], "Hello from JavaScript!"];
9driver.navigate["file:///race_condition.html"]
el = driver.find_element[By.TAG_NAME, "p"]
assert el.text == "Hello from JavaScript!"
0driver.navigate["file:///race_condition.html"]
el = driver.find_element[By.TAG_NAME, "p"]
assert el.text == "Hello from JavaScript!"
1driver.navigate["file:///race_condition.html"]
el = driver.find_element[By.TAG_NAME, "p"]
assert el.text == "Hello from JavaScript!"
2driver.navigate["file:///race_condition.html"]
el = driver.find_element[By.TAG_NAME, "p"]
assert el.text == "Hello from JavaScript!"
3driver.navigate["file:///race_condition.html"]
el = driver.find_element[By.TAG_NAME, "p"]
assert el.text == "Hello from JavaScript!"
4điều kiện dự kiến
Vì việc phải đồng bộ hóa DOM và hướng dẫn của bạn là điều khá phổ biến nên hầu hết các máy khách cũng đi kèm với một tập hợp các điều kiện dự kiến được xác định trước. Như cái tên có thể rõ ràng, chúng là các điều kiện được xác định trước cho các hoạt động chờ đợi thường xuyên
Các điều kiện có sẵn trong các ràng buộc ngôn ngữ khác nhau sẽ khác nhau, nhưng đây là danh sách không đầy đủ của một số
- cảnh báo có mặt
- yếu tố tồn tại
- phần tử có thể nhìn thấy
- tiêu đề chứa
- tiêu đề là
- yếu tố ổn định
- văn bản hiển thị
Bạn có thể tham khảo tài liệu API cho từng liên kết ứng dụng khách để tìm danh sách đầy đủ các điều kiện dự kiến
chờ đợi ngầm định
Có một loại chờ đợi thứ hai khác với gọi là chờ đợi ngầm định. Bằng cách chờ đợi ngầm định, WebDriver thăm dò DOM trong một khoảng thời gian nhất định khi cố gắng tìm bất kỳ phần tử nào. Điều này có thể hữu ích khi một số thành phần nhất định trên trang web không có sẵn ngay lập tức và cần một chút thời gian để tải
Theo mặc định, tính năng chờ ngầm cho các phần tử xuất hiện bị tắt và sẽ cần được bật theo cách thủ công trên cơ sở mỗi phiên. Trộn và đợi ẩn sẽ gây ra những hậu quả không lường trước được, cụ thể là đợi ngủ trong thời gian tối đa ngay cả khi phần tử có sẵn hoặc điều kiện là đúng
Cảnh báo. Không trộn lẫn chờ đợi ngầm và rõ ràng. Làm như vậy có thể gây ra thời gian chờ đợi không thể đoán trước. Ví dụ: đặt thời gian chờ ngầm định là 10 giây và thời gian chờ rõ ràng là 15 giây có thể khiến thời gian chờ xảy ra sau 20 giây
Chờ đợi ngầm định là yêu cầu WebDriver thăm dò DOM trong một khoảng thời gian nhất định khi cố gắng tìm một phần tử hoặc các phần tử nếu chúng không có sẵn ngay lập tức. Cài đặt mặc định là 0, nghĩa là bị vô hiệu hóa. Sau khi được đặt, thời gian chờ ngầm được đặt cho vòng đời của phiên
driver.navigate["file:///race_condition.html"]
el = driver.find_element[By.TAG_NAME, "p"]
assert el.text == "Hello from JavaScript!"
5driver.navigate["file:///race_condition.html"]
el = driver.find_element[By.TAG_NAME, "p"]
assert el.text == "Hello from JavaScript!"
6driver.navigate["file:///race_condition.html"]
el = driver.find_element[By.TAG_NAME, "p"]
assert el.text == "Hello from JavaScript!"
7driver.navigate["file:///race_condition.html"]
el = driver.find_element[By.TAG_NAME, "p"]
assert el.text == "Hello from JavaScript!"
8driver.navigate["file:///race_condition.html"]
el = driver.find_element[By.TAG_NAME, "p"]
assert el.text == "Hello from JavaScript!"
9driver.Navigate[].GoToUrl["file:///race_condition.html"];
IWebElement element = driver.FindElement[By.TagName["p"]];
assertEquals[element.Text, "Hello from JavaScript!"];
0Lưu loátChờ đợi
Phiên bản FluentWait xác định lượng thời gian tối đa để chờ một điều kiện, cũng như tần suất kiểm tra điều kiện
Người dùng có thể định cấu hình chờ để bỏ qua các loại ngoại lệ cụ thể trong khi chờ, chẳng hạn như
require 'selenium-webdriver'
driver = Selenium::WebDriver.for :firefox
begin
# Navigate to URL
driver.get 'file:///race_condition.html'
# Get and store Paragraph Text
search_form = driver.find_element[:css,'p'].text
"Hello from JavaScript!".eql? search_form
ensure
driver.quit
end
0 khi tìm kiếm một phần tử trên trang