คุณจะทำให้Selenium 2.0 รอหน้าโหลดได้อย่างไร
คุณจะทำให้Selenium 2.0 รอหน้าโหลดได้อย่างไร
คำตอบ:
คุณสามารถตรวจสอบเจดีย์ด้วยรหัสต่อไปนี้
IWait<IWebDriver> wait = new OpenQA.Selenium.Support.UI.WebDriverWait(driver, TimeSpan.FromSeconds(30.00));
wait.Until(driver1 => ((IJavaScriptExecutor)driver).ExecuteScript("return document.readyState").Equals("complete"));
ใช้คลาสWebDriverWait
คุณสามารถคาดหวังให้แสดงองค์ประกอบบางอย่าง บางอย่างใน C #:
WebDriver _driver = new WebDriver();
WebDriverWait _wait = new WebDriverWait(_driver, new TimeSpan(0, 1, 0));
_wait.Until(d => d.FindElement(By.Id("Id_Your_UIElement"));
หากคุณตั้งค่าการรอโดยนัยของไดรเวอร์ให้เรียกใช้findElement
เมธอดบนองค์ประกอบที่คุณคาดว่าจะอยู่ในหน้าที่โหลด WebDriver จะสำรวจความคิดเห็นขององค์ประกอบนั้นจนกว่าจะพบองค์ประกอบหรือถึงค่าการหมดเวลา
driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
แหล่งที่มา: implicit-waits
โดยทั่วไปด้วย Selenium 2.0 เว็บไดรเวอร์ควรกลับการควบคุมไปยังรหัสการโทรเฉพาะเมื่อมีการกำหนดว่าหน้าโหลดแล้ว หากไม่เป็นเช่นนั้นคุณสามารถโทรหาwaitforelemement
ได้ซึ่งจะวนรอบการโทรfindelement
จนกว่าจะพบหรือหมดเวลา (สามารถตั้งค่าการหมดเวลา)
If click() causes a new page to be loaded via an event or is done by sending a native event (which is a common case on Firefox, IE on Windows) then the method will not wait for it to be loaded and the caller should verify that a new page has been loaded.
JavascriptExecutor
กำลังรอเอกสารอยู่แล้วสถานะเป็น "สมบูรณ์" เนื่องจากการเดินทางไปกลับจากซีลีเนียมไปยังเบราว์เซอร์สภาพการแข่งขันลดลงฉันเดาและนี่ "เสมอ" ใช้งานได้สำหรับฉัน หลังจาก "คลิก ()" เมื่อฉันคาดว่าหน้าจะโหลดฉันรออย่างชัดเจน (ใช้ WebDriverWait) สำหรับผู้อ่าน ]
การใช้ทับทิม:
wait = Selenium::WebDriver::Wait.new(:timeout => 10)
wait.until {
@driver.execute_script("return document.readyState;") == "complete"
}
คุณอาจลบSystem.out
บรรทัด มันถูกเพิ่มเพื่อวัตถุประสงค์ในการแก้ไขปัญหา
WebDriver driver_;
public void waitForPageLoad() {
Wait<WebDriver> wait = new WebDriverWait(driver_, 30);
wait.until(new Function<WebDriver, Boolean>() {
public Boolean apply(WebDriver driver) {
System.out.println("Current Window State : "
+ String.valueOf(((JavascriptExecutor) driver).executeScript("return document.readyState")));
return String
.valueOf(((JavascriptExecutor) driver).executeScript("return document.readyState"))
.equals("complete");
}
});
}
วิธีแก้ปัญหาทั้งหมดนี้ใช้ได้ในบางกรณี แต่ปัญหาเหล่านั้นอาจเกิดจากปัญหาอย่างน้อยหนึ่งในสองข้อ:
พวกเขาไม่กว้างพอ - พวกเขาต้องการให้คุณรู้ล่วงหน้าว่าเงื่อนไขเฉพาะบางอย่างจะเป็นจริงของหน้าเว็บที่คุณกำลังจะไป (เช่นองค์ประกอบบางอย่างจะปรากฏขึ้น)
พวกเขาจะเปิดให้เงื่อนไขการแข่งขันที่คุณใช้องค์ประกอบที่มีอยู่จริงในหน้าเก่าเช่นเดียวกับหน้าใหม่
นี่คือความพยายามของฉันในการแก้ปัญหาทั่วไปที่หลีกเลี่ยงปัญหานี้ (ใน Python):
ก่อนอื่นฟังก์ชั่นทั่วไป "รอ" (ใช้ WebDriverWait หากคุณต้องการฉันพบว่ามันน่าเกลียด):
def wait_for(condition_function):
start_time = time.time()
while time.time() < start_time + 3:
if condition_function():
return True
else:
time.sleep(0.1)
raise Exception('Timeout waiting for {}'.format(condition_function.__name__))
ถัดไปการแก้ปัญหาขึ้นอยู่กับข้อเท็จจริงที่ว่าซีลีเนียมบันทึกหมายเลข id (ภายใน) สำหรับองค์ประกอบทั้งหมดในหน้ารวมถึง<html>
องค์ประกอบระดับบนสุด เมื่อหน้ารีเฟรชหรือโหลดมันจะได้รับองค์ประกอบ html ใหม่พร้อมรหัสใหม่
ดังนั้นสมมติว่าคุณต้องการคลิกลิงก์ที่มีข้อความ "ลิงค์ของฉัน" ตัวอย่างเช่น:
old_page = browser.find_element_by_tag_name('html')
browser.find_element_by_link_text('my link').click()
def page_has_loaded():
new_page = browser.find_element_by_tag_name('html')
return new_page.id != old_page.id
wait_for(page_has_loaded)
สำหรับผู้ช่วยทั่วไปแบบ Pythonic ที่สามารถใช้ซ้ำได้และใช้ซ้ำได้คุณสามารถสร้างตัวจัดการบริบท:
from contextlib import contextmanager
@contextmanager
def wait_for_page_load(browser):
old_page = browser.find_element_by_tag_name('html')
yield
def page_has_loaded():
new_page = browser.find_element_by_tag_name('html')
return new_page.id != old_page.id
wait_for(page_has_loaded)
และจากนั้นคุณสามารถใช้มันในการโต้ตอบซีลีเนียมใด ๆ :
with wait_for_page_load(browser):
browser.find_element_by_link_text('my link').click()
ฉันคิดว่ามันเป็นกระสุน! คุณคิดอย่างไร?
ข้อมูลเพิ่มเติมในบล็อกโพสต์เกี่ยวกับที่นี่
นอกจากนี้คุณยังสามารถใช้คลาส: ExpectedConditions
เพื่อรอให้องค์ประกอบปรากฏในหน้าเว็บก่อนที่คุณจะสามารถดำเนินการใด ๆ เพิ่มเติมได้
คุณสามารถใช้ExpectedConditions
คลาสเพื่อพิจารณาว่าองค์ประกอบนั้นสามารถมองเห็นได้หรือไม่:
WebElement element = (new WebDriverWait(getDriver(), 10)).until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("input#houseName")));
ดูExpectedConditions class Javadoc
รายการเงื่อนไขทั้งหมดที่คุณสามารถตรวจสอบได้
คำตอบของ Imran rehashed สำหรับ Java 7:
WebDriverWait wait = new WebDriverWait(driver, 30);
wait.until(new ExpectedCondition<Boolean>() {
public Boolean apply(WebDriver wdriver) {
return ((JavascriptExecutor) driver).executeScript(
"return document.readyState"
).equals("complete");
}
});
นี่เป็นข้อ จำกัด ที่ร้ายแรงของ WebDriver เห็นได้ชัดว่าการรอองค์ประกอบจะไม่บ่งบอกถึงหน้าที่กำลังโหลดโดยเฉพาะอย่างยิ่ง DOM สามารถสร้างได้อย่างสมบูรณ์ (สถานะ onready) โดยที่ JS ยังคงดำเนินการอยู่และ CSS และรูปภาพยังคงโหลดอยู่
ฉันเชื่อว่าทางออกที่ง่ายที่สุดคือการตั้งค่าตัวแปร JS ตามเหตุการณ์ onload หลังจากทุกอย่างเริ่มต้นแล้วตรวจสอบและรอตัวแปร JS นี้ใน Selenium
หากคุณต้องการรอให้องค์ประกอบที่เฉพาะเจาะจงในการโหลดคุณสามารถใช้isDisplayed()
วิธีการในRenderedWebElement
:
// Sleep until the div we want is visible or 5 seconds is over
long end = System.currentTimeMillis() + 5000;
while (System.currentTimeMillis() < end) {
// Browsers which render content (such as Firefox and IE) return "RenderedWebElements"
RenderedWebElement resultsDiv = (RenderedWebElement) driver.findElement(By.className("gac_m"));
// If results have been returned, the results are displayed in a drop down.
if (resultsDiv.isDisplayed()) {
break;
}
}
(ตัวอย่างจากคู่มือการเริ่มต้น 5 นาที )
RenderedWebElement
ใน API อย่างไรก็ตามวิธีการนี้สามารถใช้ได้โดยตรงบนisDisplayed()
WebElement
รออย่างชัดเจนหรือรอตามเงื่อนไขในการรอนี้จนกว่าจะได้รับเงื่อนไขนี้
WebDriverWait wait = new WebDriverWait(wb, 60);
wait.until(ExpectedConditions.elementToBeClickable(By.name("value")));
สิ่งนี้จะรอทุกๆองค์ประกอบของเว็บเป็นเวลา 60 วินาที
ใช้การรอโดยปริยายสำหรับทุกองค์ประกอบในหน้าจนกว่าจะถึงเวลาที่กำหนด
driver.manage().timeouts().implicitlyWait(60, TimeUnit.SECONDS);
สิ่งนี้จะรอทุกๆองค์ประกอบของเว็บเป็นเวลา 60 วินาที
ใช้การรอโดยปริยายสำหรับทุกองค์ประกอบในหน้าจนกว่าจะถึงเวลาที่กำหนด
driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
การรอนี้สำหรับทุกองค์ประกอบในหน้าเป็นเวลา 30 วินาที
การรออื่นคือการรออย่างชัดแจ้งหรือการรอตามเงื่อนไขในการรอนี้จนกว่าจะได้รับเงื่อนไข
WebDriverWait wait = new WebDriverWait(driver, 40);
WebElement element = wait.until(ExpectedConditions.elementToBeClickable(By.id("someid")));
ใน id ให้องค์ประกอบองค์ประกอบคงที่ซึ่งจะปรากฏบนหน้าเว็บทันทีที่โหลดหน้า
ฉันประหลาดใจที่เพรดิเคตไม่ใช่ตัวเลือกแรกเนื่องจากคุณมักจะรู้ว่าองค์ประกอบใดที่คุณจะโต้ตอบในหน้าถัดไปที่คุณรอโหลด แนวทางของฉันคือการสร้างเพรดิเคต / ฟังก์ชั่นเช่นwaitForElementByID(String id)
และwaitForElemetVisibleByClass(String className)
อื่น ๆ จากนั้นใช้และนำกลับมาใช้ใหม่ได้ทุกที่ที่ต้องการไม่ว่าจะเป็นการโหลดหน้าหรือเปลี่ยนเนื้อหาของหน้า
ตัวอย่างเช่น,
ในชั้นทดสอบของฉัน:
driverWait.until(textIsPresent("expectedText");
ในระดับผู้ปกครองของฉันทดสอบ:
protected Predicate<WebDriver> textIsPresent(String text){
final String t = text;
return new Predicate<WebDriver>(){
public boolean apply(WebDriver driver){
return isTextPresent(t);
}
};
}
protected boolean isTextPresent(String text){
return driver.getPageSource().contains(text);
}
แม้ว่าสิ่งนี้จะดูเหมือนมาก แต่ก็ดูแลการตรวจสอบซ้ำ ๆ สำหรับคุณและช่วงเวลาในการตรวจสอบความถี่ที่สามารถตั้งค่าได้พร้อมกับเวลารอคอยขั้นสุดท้ายก่อนที่จะหมดเวลา นอกจากนี้คุณจะใช้วิธีการดังกล่าวอีกครั้ง
ในตัวอย่างนี้ผู้ปกครองชั้นเรียนที่กำหนดไว้และริเริ่มและWebDriver driver
WebDriverWait driverWait
ฉันหวังว่านี่จะช่วยได้.
วิธีที่ดีที่สุดในการรอให้โหลดหน้าเว็บเมื่อใช้การเชื่อม Java สำหรับ WebDriver คือการใช้รูปแบบการออกแบบ Page Object กับ PageFactory สิ่งนี้ช่วยให้คุณใช้ประโยชน์จากสิ่งAjaxElementLocatorFactory
ที่ทำให้มันเป็นเพียงการรอคอยระดับโลกสำหรับองค์ประกอบทั้งหมดของคุณ มันมีข้อ จำกัด เกี่ยวกับองค์ประกอบต่าง ๆ เช่นดรอปบ็อกซ์หรือการเปลี่ยนจาวาสคริปต์ที่ซับซ้อน แต่มันจะลดจำนวนโค้ดที่จำเป็นลงอย่างมากและเพิ่มความเร็วในการทดสอบ ตัวอย่างที่ดีสามารถพบได้ในบล็อกนี้ ทำความเข้าใจพื้นฐานของ Core Java
http://startingwithseleniumwebdriver.blogspot.ro/2015/02/wait-in-page-factory.html
โซลูชัน NodeJS:
ในNodejsคุณสามารถรับมันผ่านทางสัญญา ...
หากคุณเขียนรหัสนี้คุณสามารถมั่นใจได้ว่าหน้าเว็บจะโหลดเต็มเมื่อคุณไปที่ ...
driver.get('www.sidanmor.com').then(()=> {
// here the page is fully loaded!!!
// do your stuff...
}).catch(console.log.bind(console));
หากคุณเขียนรหัสนี้คุณจะนำทางและซีลีเนียมจะรอ 3 วินาที ...
driver.get('www.sidanmor.com');
driver.sleep(3000);
// you can't be sure that the page is fully loaded!!!
// do your stuff... hope it will be OK...
จากเอกสารซีลีเนียม:
this.get (url) →หลังจากนั้น
กำหนดเวลาคำสั่งเพื่อนำทางไปยัง URL ที่กำหนด
ผลตอบแทนที่ได้สัญญาที่จะได้รับการแก้ไขเมื่อเอกสารมีการโหลดเสร็จแล้ว
นี่เป็นเวอร์ชั่น Java 8 ของคำตอบที่ถูกโหวตมากที่สุดในปัจจุบัน:
WebDriverWait wait = new WebDriverWait(myDriver, 15);
wait.until(webDriver -> ((JavascriptExecutor) myDriver).executeScript("return document.readyState").toString().equals("complete"));
ในกรณีที่myDriver
เป็นWebDriver
วัตถุ (ประกาศก่อนหน้า)
หมายเหตุ : โปรดทราบว่าวิธีนี้ ( document.readyState
) ตรวจสอบ DOM เท่านั้น
โทรด้านล่างฟังก์ชั่นในสคริปต์ของคุณนี้จะรอจนกว่าหน้าจะไม่โหลดโดยใช้จาวาสคริปต์
public static boolean isloadComplete(WebDriver driver)
{
return ((JavascriptExecutor) driver).executeScript("return document.readyState").equals("loaded")
|| ((JavascriptExecutor) driver).executeScript("return document.readyState").equals("complete");
}
/**
* Call this method before an event that will change the page.
*/
private void beforePageLoad() {
JavascriptExecutor js = (JavascriptExecutor) driver;
js.executeScript("document.mpPageReloaded='notYet';");
}
/**
* Call this method after an event that will change the page.
*
* @see #beforePageLoad
*
* Waits for the previous page to disappear.
*/
private void afterPageLoad() throws Exception {
(new WebDriverWait(driver, 10)).until(new Predicate<WebDriver>() {
@Override
public boolean apply(WebDriver driver) {
JavascriptExecutor js = (JavascriptExecutor) driver;
Object obj = js.executeScript("return document.mpPageReloaded;");
if (obj == null) {
return true;
}
String str = (String) obj;
if (!str.equals("notYet")) {
return true;
}
return false;
}
});
}
คุณสามารถเปลี่ยนจากเอกสารเป็นองค์ประกอบในกรณีที่มีการเปลี่ยนแปลงเฉพาะบางส่วนของเอกสาร
เทคนิคนี้ได้รับแรงบันดาลใจจากคำตอบของตั้งแต่พื้นฐาน
SeleniumWaiter :
import com.google.common.base.Function;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.ui.WebDriverWait;
public class SeleniumWaiter {
private WebDriver driver;
public SeleniumWaiter(WebDriver driver) {
this.driver = driver;
}
public WebElement waitForMe(By locatorname, int timeout){
WebDriverWait wait = new WebDriverWait(driver, timeout);
return wait.until(SeleniumWaiter.presenceOfElementLocated(locatorname));
}
public static Function<WebDriver, WebElement> presenceOfElementLocated(final By locator) {
// TODO Auto-generated method stub
return new Function<WebDriver, WebElement>() {
@Override
public WebElement apply(WebDriver driver) {
return driver.findElement(locator);
}
};
}
}
และคุณใช้มัน :
_waiter = new SeleniumWaiter(_driver);
try {
_waiter.waitForMe(By.xpath("//..."), 10);
}
catch (Exception e) {
// Error
}
คุณสามารถใช้วิธีที่มีอยู่ด้านล่างเพื่อตั้งเวลาสำหรับ pageeLoadTimeout ในตัวอย่างด้านล่างหากหน้านั้นใช้เวลาในการโหลดมากกว่า 20 วินาทีจากนั้นมันจะส่งข้อยกเว้นการโหลดหน้าซ้ำ
WebDriver driver = new FirefoxDriver();
driver.manage().timeouts().pageLoadTimeout(20, TimeUnit.SECONDS)
คุณสามารถรอให้องค์ประกอบปรากฏบนหน้าเว็บก่อนที่คุณจะสามารถดำเนินการใด ๆ (เช่นองค์ประกอบ. คลิก ())
driver.get("http://somedomain/url_that_delays_loading");
WebElement myDynamicElement = (new WebDriverWait(driver, 10))
.until(new ExpectedCondition<WebElement>(){
@Override
public WebElement apply(WebDriver d) {
return d.findElement(By.id("myDynamicElement"));
}});
นี่คือสิ่งที่ฉันใช้สำหรับสถานการณ์ที่คล้ายกันและทำงานได้ดี
วิธีง่ายๆของฉัน:
long timeOut = 5000;
long end = System.currentTimeMillis() + timeOut;
while (System.currentTimeMillis() < end) {
if (String.valueOf(
((JavascriptExecutor) driver)
.executeScript("return document.readyState"))
.equals("complete")) {
break;
}
}
วิธีที่ดีที่สุดที่ฉันเคยเห็นคือใช้stalenessOf
ExpectedCondition เพื่อรอหน้าเก่าให้เก่า
ตัวอย่าง:
WebDriver driver = new FirefoxDriver();
WebDriverWait wait = new WebDriverWait(driver, 10);
WebElement oldHtml = driver.findElement(By.tagName("html"));
wait.until(ExpectedConditions.stalenessOf(oldHtml));
มันจะรอสิบวินาทีเพื่อให้แท็ก HTML เก่ากลายเป็นค้างแล้วจากนั้นก็ยกเว้นหากไม่เกิดขึ้น
ฉันใช้ node + selenium-webdriver (เวอร์ชันใดเป็น 3.5.0 ตอนนี้) สิ่งที่ฉันทำเพื่อสิ่งนี้คือ:
var webdriver = require('selenium-webdriver'),
driver = new webdriver.Builder().forBrowser('chrome').build();
;
driver.wait(driver.executeScript("return document.readyState").then(state => {
return state === 'complete';
}))
คุณสามารถใช้รอ โดยทั่วไปจะมีซีลีเนียมรออยู่ 2 ชนิด
- การรอโดยนัย
ง่ายมากโปรดดูไวยากรณ์ด้านล่าง:
driver.manage().timeouts().implicitlyWait(20, TimeUnit.SECONDS);
- รออย่างชัดเจน
รออย่างชัดเจนหรือรอตามเงื่อนไขในการรอนี้จนกว่าจะเกิดเงื่อนไขที่กำหนด
WebDriverWait wait = new WebDriverWait(driver, 40);
WebElement element = wait.until(ExpectedConditions.elementToBeClickable(By.id("someid")));
คุณสามารถใช้คุณสมบัติอื่น ๆ เช่นvisblityOf()
,visblityOfElement()
หากมีคนใช้ selenide:
public static final Long SHORT_WAIT = 5000L; // 5 seconds
$("some_css_selector").waitUntil(Condition.appear, SHORT_WAIT);
เงื่อนไขเพิ่มเติมสามารถพบได้ที่นี่: http://selenide.org/javadoc/3.0/com/codeborne/selenide/Condition.html
ในกรณีของฉันฉันใช้สิ่งต่อไปนี้เพื่อทราบสถานะการโหลดหน้า ในแอปพลิเคชันของเรากำลังโหลด gif (s) และฉันฟังพวกเขาดังต่อไปนี้เพื่อกำจัดเวลารอที่ไม่พึงประสงค์ในสคริปต์
public static void processing(){
WebDriverWait wait = new WebDriverWait(driver, 30);
wait.until(ExpectedConditions.visibilityOfElementLocated(By.xpath("//div[@id='Msgpanel']/div/div/img")));
wait.until(ExpectedConditions.invisibilityOfElementLocated(By.xpath("//div[@id='Msgpanel']/div/div/img")));
}
ตำแหน่งที่ xpath หา gif ใน HTML DOM หลังจากนี้คุณอาจใช้วิธีการกระทำของคุณคลิก
public static void click(WebElement elementToBeClicked){
WebDriverWait wait = new WebDriverWait(driver, 45);
wait.until(ExpectedConditions.visibilityOf(element));
wait.until(ExpectedConditions.elementToBeClickable(element));
wait.ignoring(NoSuchElementException.class).ignoring(StaleElementReferenceException.class); elementToBeClicked.click();
}
คำตอบทั้งหมดเหล่านี้ต้องใช้รหัสมากเกินไป นี่ควรเป็นสิ่งที่เรียบง่ายเหมือนกัน
ทำไมไม่เพียงแค่ฉีดจาวาสคริปต์ง่ายๆด้วย webdriver และตรวจสอบ นี่คือวิธีที่ฉันใช้ในชั้นเรียนของฉัน จาวาสคริปต์นั้นค่อนข้างธรรมดาแม้ว่าคุณจะไม่รู้จัก js
def js_get_page_state(self):
"""
Javascript for getting document.readyState
:return: Pages state.
More Info: https://developer.mozilla.org/en-US/docs/Web/API/Document/readyState
"""
ready_state = self.driver.execute_script('return document.readyState')
if ready_state == 'loading':
self.logger.info("Loading Page...")
elif ready_state == 'interactive':
self.logger.info("Page is interactive")
elif ready_state == 'complete':
self.logger.info("The page is fully loaded!")
return ready_state
วิธีให้ซีลีเนียมรอให้โหลดหน้าเว็บหลังจากคลิกให้วิธีที่น่าสนใจดังต่อไปนี้:
WebElement
จากหน้าเก่าWebElement
ไปจนกว่าStaleElementReferenceException
จะถูกโยนทิ้งรหัสตัวอย่าง:
WebElement link = ...;
link.click();
new WebDriverWait(webDriver, timeout).until((org.openqa.selenium.WebDriver input) ->
{
try
{
link.isDisplayed();
return false;
}
catch (StaleElementReferenceException unused)
{
return true;
}
});
new WebDriverWait(driver, 10).until(ExpectedConditions.stalenessOf(element))
คุณสามารถแทนที่รหัสของคุณข้างต้นด้วย