ฉันจะขอให้ Selenium-WebDriver รอสองสามวินาทีใน Java ได้อย่างไร


101

ฉันกำลังทำงานกับ Java Selenium-WebDriver ฉันเพิ่ม

driver.manage().timeouts().implicitlyWait(2, TimeUnit.SECONDS);

และ

WebElement textbox = driver.findElement(By.id("textbox"));

เนื่องจากแอปพลิเคชันของฉันใช้เวลาไม่กี่วินาทีในการโหลดส่วนติดต่อผู้ใช้ ผมจึงตั้งเวลา 2 วินาทีโดยนัย แต่ฉันไม่พบกล่องข้อความองค์ประกอบ

จากนั้นฉันก็เพิ่ม Thread.sleep(2000);

ตอนนี้ใช้งานได้ดี วิธีไหนดีกว่ากัน


คำตอบ:


123

การรอมีสองประเภท: การรออย่างชัดเจนและโดยปริยาย แนวคิดของการรออย่างชัดเจนคือ

WebDriverWait.until(condition-that-finds-the-element);

แนวคิดของการรอโดยปริยายคือ

driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);

คุณจะได้รับความแตกต่างในรายละเอียดที่นี่

ในสถานการณ์เช่นนี้ฉันต้องการใช้การรออย่างชัดเจน ( fluentWaitโดยเฉพาะ):

public WebElement fluentWait(final By locator) {
    Wait<WebDriver> wait = new FluentWait<WebDriver>(driver)
            .withTimeout(30, TimeUnit.SECONDS)
            .pollingEvery(5, TimeUnit.SECONDS)
            .ignoring(NoSuchElementException.class);

    WebElement foo = wait.until(new Function<WebDriver, WebElement>() {
        public WebElement apply(WebDriver driver) {
            return driver.findElement(locator);
        }
    });

    return  foo;
};

fluentWaitฟังก์ชันส่งคืนองค์ประกอบเว็บที่คุณพบ จากเอกสารเกี่ยวกับfluentWait: การใช้อินเทอร์เฟซ Wait ที่อาจมีการกำหนดระยะหมดเวลาและช่วงการสำรวจความคิดเห็นได้ทันที แต่ละอินสแตนซ์ FluentWait กำหนดระยะเวลาสูงสุดในการรอเงื่อนไขตลอดจนความถี่ในการตรวจสอบเงื่อนไข นอกจากนี้ผู้ใช้อาจกำหนดค่าการรอเพื่อละเว้นข้อยกเว้นบางประเภทในขณะที่รอเช่น NoSuchElementExceptions เมื่อค้นหาองค์ประกอบบนเพจ ดูรายละเอียดได้ที่นี่

การใช้งานfluentWaitในกรณีของคุณมีดังต่อไปนี้:

WebElement textbox = fluentWait(By.id("textbox"));

วิธีนี้ดีกว่า IMHO เนื่องจากคุณไม่ทราบว่าต้องรอนานเท่าใดและในช่วงการสำรวจคุณสามารถกำหนดค่าเวลาที่กำหนดได้เองว่าจะมีการตรวจสอบองค์ประกอบใดบ้าง ความนับถือ.


3
นั่นimport com.google.common.base.Function;ไม่ใช่import java.util.function.Function;
ตรวจสอบ

ยังไม่ได้ตรวจสอบโดยใช้ intelij IDEA ในการพัฒนาซึ่งช่วยในการนำเข้าอัตโนมัติ (เมื่อทำงานในโครงการที่ใช้ maven)
eugene.polschikov

1
ฉันแค่โทรหาคนอื่นที่อาจสงสัยว่าFunctionกำลังใช้ตัวไหนอยู่ มันไม่ชัดเจนสำหรับฉันในตอนแรก ขอบคุณสำหรับคำตอบ.
ตรวจสอบ

1
หรือคุณสามารถใช้นิพจน์แลมบ์ดา: driver -> driver.findElement(locator). เมื่อใช้สิ่งนี้คุณไม่จำเป็นต้องมีใบแจ้งยอดการนำเข้าเลย
Thibstars

2
ตอนนี้เป็น: .withTimeout(Duration.ofSeconds(30)).pollingEvery(Duration.ofSeconds(5))แทน: .withTimeout(30, TimeUnit.SECONDS).pollingEvery(5, TimeUnit.SECONDS)
SuperRetro

16

เธรดนี้เก่ากว่าเล็กน้อย แต่คิดว่าฉันจะโพสต์สิ่งที่ฉันทำอยู่ (กำลังดำเนินการอยู่)

แม้ว่าฉันจะยังคงโดนสถานการณ์ที่ระบบมีภาระงานหนักและเมื่อฉันคลิกปุ่มส่ง (เช่น login.jsp) เงื่อนไขทั้งสาม (ดูด้านล่าง) จะกลับมาtrueแต่หน้าถัดไป (เช่น home.jsp) ไม่มี ' ยังไม่เริ่มโหลดเลย

นี่เป็นวิธีการรอทั่วไปที่ใช้รายการที่คาดหวังเงื่อนไข

public boolean waitForPageLoad(int waitTimeInSec, ExpectedCondition<Boolean>... conditions) {
    boolean isLoaded = false;
    Wait<WebDriver> wait = new FluentWait<>(driver)
            .withTimeout(waitTimeInSec, TimeUnit.SECONDS)
            .ignoring(StaleElementReferenceException.class)
            .pollingEvery(2, TimeUnit.SECONDS);
    for (ExpectedCondition<Boolean> condition : conditions) {
        isLoaded = wait.until(condition);
        if (isLoaded == false) {
            //Stop checking on first condition returning false.
            break;
        }
    }
    return isLoaded;
}

ฉันได้กำหนดเงื่อนไขที่คาดว่าจะใช้ซ้ำได้หลายแบบ (สามข้ออยู่ด้านล่าง) ในตัวอย่างนี้เงื่อนไขที่คาดหวังสามประการ ได้แก่ document.readyState = 'complete', ไม่มี "wait_dialog" อยู่และไม่มี 'spinners' (องค์ประกอบที่ระบุว่ามีการร้องขอข้อมูล async)

เฉพาะหน้าแรกเท่านั้นที่สามารถใช้กับหน้าเว็บทั้งหมดได้

/**
 * Returns 'true' if the value of the 'window.document.readyState' via
 * JavaScript is 'complete'
 */
public static final ExpectedCondition<Boolean> EXPECT_DOC_READY_STATE = new ExpectedCondition<Boolean>() {
    @Override
    public Boolean apply(WebDriver driver) {
        String script = "if (typeof window != 'undefined' && window.document) { return window.document.readyState; } else { return 'notready'; }";
        Boolean result;
        try {
            result = ((JavascriptExecutor) driver).executeScript(script).equals("complete");
        } catch (Exception ex) {
            result = Boolean.FALSE;
        }
        return result;
    }
};
/**
 * Returns 'true' if there is no 'wait_dialog' element present on the page.
 */
public static final ExpectedCondition<Boolean> EXPECT_NOT_WAITING = new ExpectedCondition<Boolean>() {
    @Override
    public Boolean apply(WebDriver driver) {
        Boolean loaded = true;
        try {
            WebElement wait = driver.findElement(By.id("F"));
            if (wait.isDisplayed()) {
                loaded = false;
            }
        } catch (StaleElementReferenceException serex) {
            loaded = false;
        } catch (NoSuchElementException nseex) {
            loaded = true;
        } catch (Exception ex) {
            loaded = false;
            System.out.println("EXPECTED_NOT_WAITING: UNEXPECTED EXCEPTION: " + ex.getMessage());
        }
        return loaded;
    }
};
/**
 * Returns true if there are no elements with the 'spinner' class name.
 */
public static final ExpectedCondition<Boolean> EXPECT_NO_SPINNERS = new ExpectedCondition<Boolean>() {
    @Override
    public Boolean apply(WebDriver driver) {
        Boolean loaded = true;
        try {
        List<WebElement> spinners = driver.findElements(By.className("spinner"));
        for (WebElement spinner : spinners) {
            if (spinner.isDisplayed()) {
                loaded = false;
                break;
            }
        }
        }catch (Exception ex) {
            loaded = false;
        }
        return loaded;
    }
};

ขึ้นอยู่กับหน้านั้นฉันอาจใช้หนึ่งหรือทั้งหมด:

waitForPageLoad(timeoutInSec,
            EXPECT_DOC_READY_STATE,
            EXPECT_NOT_WAITING,
            EXPECT_NO_SPINNERS
    );

นอกจากนี้ยังมีคาดหวังที่กำหนดไว้ล่วงหน้าในคลาสต่อไปนี้: org.openqa.selenium.support.ui.ExpectedConditions


1
ตอบโจทย์มาก! ฉันไม่เคยเห็นใครส่งรายการที่คาดหวังเงื่อนไขผ่านตัวสร้างวิธีการ ช่างเป็นความคิดที่ยอดเยี่ยม +1
djangofan

Jeff Vincent คุณช่วยบอกฉันได้ไหมว่าหน้านี้จะใช้งานได้หรือไม่เพื่อรอ 5 นาทีถ้าใช่โปรดแนะนำว่าพารามิเตอร์ตำแหน่งใดที่ต้องส่ง
khanam

นี่คือคำตอบที่ยอดเยี่ยม ฉันมีฟังก์ชั่นที่คล้ายกันเช่นนี้อย่างไรก็ตามฉันต้องเรียกมันในทุกฟังก์ชันเพื่อให้สคริปต์ของฉันรอจนกว่าจะโหลดหน้า (สปินเนอร์) มีวิธีใดบ้างที่ฉันสามารถเชื่อมต่อฟังก์ชัน waitForSpinner แบบเงียบ ๆ เข้ากับ ImplicitWait เพื่อที่ฉันจะได้ไม่ต้องเรียกมันว่า everytime ในฟังก์ชันของฉัน เช่นเดียวกับกำหนดฟังก์ชั่นให้เชื่อมต่อกับไดรเวอร์หนึ่งครั้งและบูม
Bhuvanesh Mani

13

หากใช้ webdriverJs (node.js)

driver.findElement(webdriver.By.name('btnCalculate')).click().then(function() {
    driver.sleep(5000);
});

โค้ดด้านบนทำให้เบราว์เซอร์รอ 5 วินาทีหลังจากคลิกปุ่ม


18
ทำไมคุณถึงโพสต์สิ่งนี้ในเมื่อคำถามเกี่ยวกับ Java โดยเฉพาะไม่ใช่ node / JavaScript มันนอกประเด็นพอ ๆ กับการตอบวิธีทำในทับทิม
Thor84no

1
คำแนะนำให้ใช้การนอนหลับไม่ใช่ทางออกที่ดีอย่างแน่นอน
Kiril S.

1
@ Thor84no ส่วนใหญ่เนื่องจากพวกเราบางคนค้นหาโซลูชันเว็บพบคำตอบนี้
Kitanga Nday

10

การใช้Thread.sleep(2000);เป็นการรออย่างไม่มีเงื่อนไข หากการทดสอบของคุณโหลดเร็วขึ้นคุณจะยังคงต้องรอ ดังนั้นโดยหลักการแล้วการใช้implicitlyWaitคือทางออกที่ดีกว่า

อย่างไรก็ตามฉันไม่เห็นว่าเหตุใดจึงimplicitlyWaitไม่ได้ผลในกรณีของคุณ คุณวัดว่าfindElementใช้เวลาสองวินาทีจริงหรือไม่ก่อนโยนข้อยกเว้น ถ้าเป็นเช่นนั้นคุณสามารถลองใช้การรอแบบมีเงื่อนไขของ WebDriver ตามที่อธิบายไว้ในคำตอบนี้ได้หรือไม่


3

ฉันชอบใช้เงื่อนไขที่กำหนดเอง นี่คือรหัสบางส่วนใน Python:

def conditions(driver):
    flag = True
    ticker = driver.find_elements_by_id("textbox")
    if not ticker:
        flag = False
    return flag

... click something to load ...
self.wait = WebDriverWait(driver, timeout)
self.wait.until(conditions)

เมื่อใดก็ตามที่คุณต้องรอคุณสามารถทำได้อย่างชัดเจนโดยตรวจสอบการมีอยู่ขององค์ประกอบบางอย่าง (องค์ประกอบดังกล่าวอาจแตกต่างกันไปในแต่ละหน้า) find_elements_by_idรายการส่งคืน - ว่างเปล่าหรือไม่คุณต้องตรวจสอบ


2

คลิกดูเหมือนจะบล็อก? - นี่เป็นอีกวิธีหนึ่งในการรอหากคุณใช้ WebDriverJS:

driver.findElement(webdriver.By.name('mybutton')).click().then(function(){
  driver.getPageSource().then(function(source) {
    console.log(source);
  });
});

โค้ดด้านบนจะรอหลังจากคลิกปุ่มเพื่อโหลดหน้าถัดไปจากนั้นจึงคว้าแหล่งที่มาของหน้าถัดไป


1
อะไรทำให้โค้ดรอโหลดหน้าถัดไป เป็นเพียงการโทรครั้งแรกในการโทรกลับคือ getPageSource?
Isochronous

1

โดยปริยายรอและ Thread.sleep ทั้งสองใช้สำหรับการซิงโครไนซ์เท่านั้น. แต่ความแตกต่างคือเราสามารถใช้ Implicitly wait สำหรับโปรแกรมทั้งหมด แต่ Thread.sleep จะใช้งานได้กับรหัสเดียวนั้นเท่านั้น. ที่นี่คำแนะนำของฉันคือใช้โดยปริยายรอหนึ่งครั้งในโปรแกรม ทุกครั้งที่หน้าเว็บของคุณจะได้รับการรีเฟรชหมายถึงใช้ Thread.sleep ในเวลานั้น .. จะดีกว่ามาก :)

นี่คือรหัสของฉัน:

package beckyOwnProjects;

import java.util.concurrent.TimeUnit;

import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.interactions.Actions;

public class Flip {

    public static void main(String[] args) throws InterruptedException {
        WebDriver driver=new FirefoxDriver();
        driver.manage().window().maximize();
        driver.manage().timeouts().implicitlyWait(2, TimeUnit.MINUTES);
        driver.get("https://www.flipkart.com");
    WebElement ele=driver.findElement(By.cssSelector(".menu-text.fk-inline-block"));
    Actions act=new Actions(driver);
    Thread.sleep(5000);
    act.moveToElement(ele).perform();
    }

}

0

บางครั้งการรอโดยปริยายดูเหมือนจะถูกลบล้างและเวลาในการรอจะสั้นลง [@ eugene.polschikov] มีเอกสารที่ดีเกี่ยวกับเหตุผล ฉันพบในการทดสอบและการเข้ารหัสด้วย Selenium 2 ว่าการรอโดยปริยายนั้นดี แต่บางครั้งคุณต้องรออย่างชัดเจน

เป็นการดีกว่าที่จะหลีกเลี่ยงการเรียกให้ด้ายเข้านอนโดยตรง แต่บางครั้งก็ไม่มีวิธีที่ดี อย่างไรก็ตามมีซีลีเนียมอื่น ๆ ที่ให้ตัวเลือกการรอคอยที่ช่วยได้ waitForPageToLoadและwaitForFrameToLoadได้พิสูจน์แล้วว่ามีประโยชน์อย่างยิ่ง


0

การรอโดยนัย: ระหว่างการรอโดยนัยหาก Web Driver ไม่พบในทันทีเนื่องจากความพร้อมใช้งาน WebDriver จะรอเวลาที่กล่าวถึงและจะไม่พยายามค้นหาองค์ประกอบอีกในช่วงเวลาที่กำหนด เมื่อเวลาที่กำหนดสิ้นสุดลงมันจะพยายามค้นหาองค์ประกอบอีกครั้งในครั้งสุดท้ายก่อนที่จะโยนข้อยกเว้น ค่าเริ่มต้นคือศูนย์ เมื่อเรากำหนดเวลา Web Driver จะรอช่วงเวลาของอินสแตนซ์วัตถุ WebDriver

Explicit Wait: อาจมีอินสแตนซ์เมื่อองค์ประกอบหนึ่ง ๆ ใช้เวลาโหลดนานกว่าหนึ่งนาที ในกรณีนี้คุณไม่ต้องการกำหนดเวลาให้กับ Implicit wait เป็นจำนวนมากราวกับว่าคุณทำเช่นนี้เบราว์เซอร์ของคุณจะรอเวลาเดียวกันสำหรับทุกองค์ประกอบ เพื่อหลีกเลี่ยงสถานการณ์นั้นคุณสามารถแยกเวลาเฉพาะสำหรับองค์ประกอบที่ต้องการเท่านั้น การทำตามขั้นตอนนี้เบราว์เซอร์ของคุณจะใช้เวลารอโดยปริยายสำหรับทุกองค์ประกอบและจะมีขนาดใหญ่สำหรับองค์ประกอบเฉพาะ


0

บางครั้งการรอโดยปริยายล้มเหลวโดยบอกว่ามีองค์ประกอบอยู่ แต่ไม่มีอยู่จริง

วิธีแก้ไขคือหลีกเลี่ยงการใช้ driver.findElement และแทนที่ด้วยวิธีการแบบกำหนดเองที่ใช้ Explicit Wait โดยปริยาย ตัวอย่างเช่น:

import org.openqa.selenium.NoSuchElementException;


public WebElement element(By locator){
    Integer timeoutLimitSeconds = 20;
    WebDriverWait wait = new WebDriverWait(driver, timeoutLimitSeconds);
    try {
        wait.until(ExpectedConditions.presenceOfElementLocated(locator));
    }
    catch(TimeoutException e){
        throw new NoSuchElementException(locator.toString());
    }
    WebElement element = driver.findElement(locator);
    return element;
}

มีเหตุผลเพิ่มเติมที่จะหลีกเลี่ยงการรอโดยปริยายนอกเหนือจากความล้มเหลวเป็นระยะ ๆ เป็นครั้งคราว (ดูลิงค์นี้)

คุณสามารถใช้เมธอด "element" นี้ในลักษณะเดียวกับ driver.findElement ตัวอย่างเช่น:

    driver.get("http://yoursite.html");
    element(By.cssSelector("h1.logo")).click();

หากคุณต้องการรอเพียงไม่กี่วินาทีเพื่อแก้ไขปัญหาหรือบางโอกาสที่หายากอื่น ๆ คุณสามารถสร้างวิธีการหยุดชั่วคราวที่คล้ายกับข้อเสนอของซีลีเนียม IDE:

    public void pause(Integer milliseconds){
    try {
        TimeUnit.MILLISECONDS.sleep(milliseconds);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}

0

คำตอบ : รอสักครู่ก่อนที่การมองเห็นองค์ประกอบโดยใช้ Selenium WebDriver จะดำเนินการตามวิธีการด้านล่าง

implicitlyWait () : อินสแตนซ์ WebDriver รอจนกว่าจะโหลดเต็มหน้า คุณรำพึงใช้เวลา 30 ถึง 60 วินาทีเพื่อรอการโหลดเต็มหน้า

driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);

ExplicitlyWait WebDriverWait () : อินสแตนซ์ WebDriver รอจนกว่าจะโหลดเต็มหน้า

WebDriverWait wait = new WebDriverWait(driver, 60);

wait.until(ExpectedConditions.visibilityOf(textbox));

driver.findElement(By.id("Year")).sendKeys(allKeys);

หมายเหตุ : โปรดใช้ ExplicitlyWait WebDriverWait () เพื่อจัดการกับ WebElement ใด ๆ



-1

ฉันต้องการให้รหัสต่อไปนี้รอ 2 วินาที

for(int i=0; i<2 && driver.findElements(By.id("textbox")).size()==0 ; i++){
   Thread.sleep(1000);
}

-1
Thread.sleep(1000);

ที่แย่กว่านั้นคือการรอแบบคงที่มันจะทำให้สคริปต์ทดสอบช้าลง

driver.manage().timeouts.implicitlyWait(10,TimeUnit.SECONDS);

นี่คือการรอแบบไดนามิก

  • ใช้ได้จนถึงการมีอยู่ของ webdriver หรือมีขอบเขตจนถึงอายุการใช้งานไดรเวอร์
  • เราสามารถรอโดยปริยายได้เช่นกัน

สุดท้ายสิ่งที่ผมแนะนำคือ

WebDriverWait wait = new WebDriverWait(driver,20);
wait.until(ExpectedConditions.<different canned or predefined conditions are there>);

ด้วยเงื่อนไขที่กำหนดไว้ล่วงหน้า:

isAlertPresent();
elementToBeSelected();
visibilityOfElementLocated();
visibilityOfAllElementLocatedBy();
frameToBeAvailableAndSwitchToIt();
  • นอกจากนี้ยังเป็นการรอแบบไดนามิก
  • ในนี้การรอจะเป็นเพียงไม่กี่วินาที
  • เราต้องใช้การรออย่างชัดเจนสำหรับองค์ประกอบเว็บที่เราต้องการใช้

-4
Thread.Sleep(5000);

สิ่งนี้ช่วยฉันได้ แต่ข้อยกเว้น InterruptedException ต้องได้รับการดูแล ล้อมรอบมันให้ดีขึ้นด้วยการลองจับ:

try {
    Thread.Sleep(5000);
} catch (InterruptedException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
}

หรือ

เพิ่มการประกาศการพ่น:

public class myClass {
    public static void main(String[] args) throws InterruptedException
    { ... }

ฉันต้องการอันที่สองเนื่องจากสามารถใช้ได้sleep()หลายครั้งตามที่ต้องการและหลีกเลี่ยงการทำซ้ำtryและcatchบล็อกทุกครั้งที่sleep()มีการใช้งาน

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.