ซีลีเนียมรอจนกว่าเอกสารจะพร้อม


133

ใครช่วยบอกทีว่าฉันจะทำซีลีเนียมรอจนกว่าหน้าจะโหลดเสร็จได้อย่างไร? ฉันต้องการบางอย่างทั่วไปฉันรู้ว่าฉันสามารถกำหนดค่า WebDriverWait และเรียกบางสิ่งเช่น 'find' เพื่อให้รอ แต่ฉันไม่ไปไกลขนาดนั้น ฉันแค่ต้องทดสอบว่าหน้าเว็บโหลดสำเร็จและไปที่หน้าถัดไปเพื่อทดสอบ

เจอบางอย่างใน. net แต่ไม่สามารถใช้งานใน java ได้ ...

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"));

มีใครคิดบ้างไหม?


ทำไมคุณถึงไม่ต้องการใช้การรอ?
Amey

7
คุณหมายถึงการรออย่างชัดเจน? ใช้เวลานานมากฉันกำลังทดสอบหน้าเว็บ 10k
Girish

2
ฉันหมายความว่าการเพิ่มการรอแก้ไขอาจไม่ใช่ความคิดที่ดีหากฉันกำลังทดสอบลิงก์จำนวนมากใช่ไหม
Girish

10
การรอจำนวนวินาทีคงที่ก็ไม่มีประโยชน์ นั่นคือการคาดเดา
Anders Lindén

เนื่องจากจาวาสคริปต์ของหน้าสามารถเรียกใช้โค้ดทั่วไปได้การเขียนโปรแกรมเพื่อรอให้เสร็จสมบูรณ์จึงเป็นไปไม่ได้ เป็นรูปแบบหนึ่งของ Halting Problem ( en.wikipedia.org/wiki/Halting_problem ) การแก้ปัญหาใด ๆ ในที่นี้จะต้องทำการประนีประนอมหรือขึ้นอยู่กับสมมติฐานของหน้าเว็บ
เครื่องบินเร็ว

คำตอบ:


83

ลองใช้รหัสนี้:

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

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

นี่เป็นการรอโดยปริยาย หากคุณตั้งค่านี้ครั้งเดียวมันจะมีขอบเขตจนกว่าอินสแตนซ์ Web Driver จะทำลาย

ดูเอกสารสำหรับWebDriver.Timeoutsข้อมูลเพิ่มเติม


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

ไม่ถ้าหน้าของคุณโหลดก่อน 10 วินาทีหมายความว่าจะยุติเงื่อนไขการรอและดำเนินการตามบรรทัดก่อนหน้า
Manigandan

3
ใช้เมื่อคุณคาดว่าการโหลดหน้าเว็บจะใช้เวลานานเกินไปในการหมดเวลาและเกิดข้อยกเว้นโดยจะไม่รอให้โหลดหน้าเว็บทันทีหรือกำหนดนโยบายการโหลดที่ดีขึ้น ค่าเริ่มต้นเป็นเวลาที่ไม่มีที่สิ้นสุดดังนั้นการโหลดหน้าเว็บของคุณจะไม่มีข้อยกเว้นและซีลีเนียมจะพยายามรอให้โหลดจนหมด
Petr Janeček

19
ปัญหาของวิธีนี้คือเป็นไปได้ว่า DOM ไม่สามารถเข้าถึงได้ทั้งหมดแม้ว่าการรอโดยปริยายก่อนหน้านี้จะส่งคืนอ็อบเจ็กต์ WebElement ได้สำเร็จ จากนั้นหากคุณพยายามคลิกองค์ประกอบคุณจะได้รับข้อยกเว้นองค์ประกอบเก่า ดังนั้นคำตอบนี้ไม่ปลอดภัยอย่างสิ้นเชิง
djangofan

3
การหมดเวลานี้เกี่ยวข้องกับการรอให้เอกสารโหลดอย่างไร
Anders Lindén

90

โซลูชันที่คุณแนะนำจะรอให้DOMreadyStateส่งสัญญาณcompleteเท่านั้น แต่โดยค่าเริ่มต้นซีลีเนียมจะพยายามรอให้สิ่งเหล่านั้น (และอื่น ๆ อีกเล็กน้อย) บนหน้าโหลดผ่านทางdriver.get()และelement.click()วิธีการ พวกเขากำลังบล็อกอยู่แล้วพวกเขารอให้หน้าโหลดจนเสร็จและสิ่งเหล่านั้นควรจะใช้งานได้

เห็นได้ชัดว่าปัญหาคือการเปลี่ยนเส้นทางผ่านคำขอ AJAX และการเรียกใช้สคริปต์ซึ่งซีลีเนียมไม่สามารถจับได้จึงไม่รอให้พวกเขาเสร็จสิ้น นอกจากนี้คุณไม่สามารถจับได้อย่างน่าเชื่อถือโดยreadyStateรอสักครู่ซึ่งอาจมีประโยชน์ แต่จะส่งสัญญาณcompleteนานก่อนที่เนื้อหา AJAX ทั้งหมดจะถูกดาวน์โหลด

ไม่มีวิธีแก้ปัญหาทั่วไปที่ใช้ได้ทุกที่และสำหรับทุกคนนั่นเป็นเหตุผลว่าทำไมจึงยากและทุกคนก็ใช้สิ่งที่แตกต่างกันเล็กน้อย

กฎทั่วไปคือการพึ่งพา WebDriver ในการดำเนินการในส่วนของเขาจากนั้นใช้การรอโดยนัยจากนั้นใช้การรออย่างชัดเจนสำหรับองค์ประกอบที่คุณต้องการยืนยันบนหน้า แต่มีเทคนิคอื่น ๆ อีกมากมายที่สามารถทำได้ คุณควรเลือกอย่างใดอย่างหนึ่ง (หรือหลาย ๆ อย่างรวมกัน) ที่เหมาะกับกรณีของคุณในหน้าทดสอบของคุณ

ดูคำตอบสองข้อของฉันเกี่ยวกับเรื่องนี้สำหรับข้อมูลเพิ่มเติม:


20
ไม่ถูกต้อง Selenium ไม่รอหรือปิดกั้นการelement.click()โทร
hwjp

3
@hwjp สนใจที่จะอธิบายเพิ่มเติม? JavaDocs กล่าวเป็นอย่างอื่น : "หากสิ่งนี้ทำให้หน้าใหม่โหลดวิธีนี้จะพยายามบล็อกจนกว่าหน้าจะโหลด"
Petr Janeček

5
เทียบกับการสนทนาบางอย่างที่ฉันเคยพบในรายชื่ออีเมลดูเหมือนว่าจะไม่ถูกต้อง ซีลีเนียมอาจปิดกั้นเมื่อ. รับสายที่คุณขอ URL อย่างชัดเจน แต่จะไม่มีอะไรพิเศษในการคลิกการโทรเนื่องจากไม่สามารถบอกได้ว่าคุณได้คลิกไฮเปอร์ลิงก์ "จริง" หรือที่จาวาสคริปต์จะดักฟัง ..
hwjp

4
ฉันเชื่อมโยงไปยังจุดบกพร่องที่จุดเริ่มต้นของการอภิปรายรายชื่ออีเมล แม้แต่เอกสารก็เทียบเคียง: "ถ้าคลิก () [... ] ทำโดยการส่งเหตุการณ์เนทีฟเมธอดจะ * ไม่ * รอ"
hwjp

4
ดังนั้นทุกอย่างจะเปิดขึ้นว่าเบราว์เซอร์กำลังใช้ "เหตุการณ์ดั้งเดิม" หรือไม่ และดูเหมือนว่าส่วนใหญ่จะโดยค่าเริ่มต้น: code.google.com/p/selenium/wiki/… (ดังนั้นฉันขอบอกว่าเอกสารเหล่านั้นทำให้เข้าใจผิดได้ดีที่สุดจะ ping รายชื่ออีเมล)
hwjp

61

นี่คือตัวอย่างเวอร์ชัน Java ที่ใช้งานได้ที่คุณให้ไว้:

void waitForLoad(WebDriver driver) {
    new WebDriverWait(driver, 30).until((ExpectedCondition<Boolean>) wd ->
            ((JavascriptExecutor) wd).executeScript("return document.readyState").equals("complete"));
}

ตัวอย่างสำหรับ c #:

public static void WaitForLoad(IWebDriver driver, int timeoutSec = 15)
{
  IJavaScriptExecutor js = (IJavaScriptExecutor)driver;
  WebDriverWait wait = new WebDriverWait(driver, new TimeSpan(0, 0, timeoutSec));
  wait.Until(wd => js.ExecuteScript("return document.readyState").ToString() == "complete");
}

1
เพื่อนฉันกำลังคัดลอก / วางสิ่งนี้ ตัวอย่างนี้ยอดเยี่ยมมาก ทำไมฉันไม่คิดเรื่องนี้ ความจริงที่ว่าลูกตามากกว่าหนึ่งคู่นำไปสู่ทางออกที่ดีเสมอ ขอบคุณ
luis.espinal

2
คุณสามารถใส่สิ่งนี้ในเวอร์ชัน java 1.7 ที่เข้ากันได้หรือไม่เนื่องจากนิพจน์แลมบ์ดาไม่รองรับ
vkrams

3
เวอร์ชัน Java 1.7: wait.until (Predicate <WebDriver> () {public boolean apply (ไดรเวอร์ WebDriver) {return (((JavascriptExecutor) driver) .executeScript ("return document.readyState"). equals ("complete");} });
luQ

1
หากมีคนต้องการใช้วิธีแก้ปัญหาโดย @IuQ Predicate ได้นำเข้าimport com.google.common.base.Predicate
Knu8

ฉันลองใช้แนวคิดนี้ในแอปทดสอบ VB ใช้งานได้เกือบตลอดเวลา บางครั้งฉันได้รับข้อผิดพลาดนี้: System.InvalidOperationException: ข้อผิดพลาด JavaScript (Un ไม่คาดคิดJavaScriptError) ที่ OpenQA.Selenium.Remote.RemoteWebDriver.UnpackAndThrowOnError (Response errorResponse) ทดสอบแอปคลิกที่ลิงค์เมนูระดับ 2 จากนั้นเรียก WaitObj.Until (Function (D) DirectCast ( D, InternetExplorerDriver) .ExecuteScript ("return document.readyState") = "complete") ฉันคิดว่าเกิดข้อผิดพลาดเนื่องจากเบราว์เซอร์ยกเลิกการโหลดหน้าปัจจุบันและไม่ใช่วัตถุเอกสาร อาจจะรอ 1/2 วินาทีก่อนที่จะทำ "return document.readystate? Ideas?
CoolBreeze

12

นี่คือความพยายามของฉันในการแก้ปัญหาทั่วไปใน 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__))

จากนั้นการแก้ปัญหาจะขึ้นอยู่กับข้อเท็จจริงที่ว่าซีลีเนียมบันทึกหมายเลขรหัส (ภายใน) สำหรับองค์ประกอบทั้งหมดในเพจรวมถึง<html>องค์ประกอบระดับบนสุด เมื่อเพจรีเฟรชหรือโหลดหน้าจะได้รับองค์ประกอบ html ใหม่พร้อม ID ใหม่

ดังนั้นสมมติว่าคุณต้องการคลิกลิงก์ที่มีข้อความ "my link" เช่น:

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()

ฉันคิดว่ามันกันกระสุนได้! คุณคิดอย่างไร?

ข้อมูลเพิ่มเติมในบล็อกโพสต์เกี่ยวกับเรื่องนี้ที่นี่


แนวทางที่น่าสนใจมาก ความท้าทายอย่างหนึ่งคือสามารถใช้งานได้กับการโหลดหน้าเว็บครั้งแรกหรือไม่หลังจากเปิดตัวเบราว์เซอร์ครั้งแรก ไม่มีการรับประกันว่าสถานะเริ่มต้นของเบราว์เซอร์มีการโหลดหน้าใด ๆ นอกจากนี้ใน Java ฉันไม่เห็นว่าเรามี 'id' บนวัตถุ - ฉันสมมติว่าคุณไม่ได้หมายความว่าซีลีเนียมแทรกแอตทริบิวต์ html id ฉันจะเพิ่มคำตอบนี้ให้มากขึ้นเมื่อฉันได้สำรวจตัวเลือกนี้มากขึ้น ขอบคุณสำหรับโพสต์!
Lukus

@hwjp ฉันใช้วิธีนี้หลายครั้งพร้อมผลลัพธ์ที่ยอดเยี่ยม แต่ดูเหมือนว่าจะไม่ได้ผลในกรณีเดียว คำอธิบายฉบับเต็มของปัญหาstackoverflow.com/q/31985739/4249707
El Ruso

7

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

javascript:

return (document.readyState == 'complete' && jQuery.active == 0)

วิธี C # แบบเต็ม:

private void WaitUntilDocumentIsReady(TimeSpan timeout)
{
    var javaScriptExecutor = WebDriver as IJavaScriptExecutor;
    var wait = new WebDriverWait(WebDriver, timeout);            

    // Check if document is ready
    Func<IWebDriver, bool> readyCondition = webDriver => javaScriptExecutor
        .ExecuteScript("return (document.readyState == 'complete' && jQuery.active == 0)");
    wait.Until(readyCondition);
}

มีสิ่งที่ต้องการdocument.readyState == 'complete' && jQuery.active == 0สำหรับ React หรือไม่?
ฝน 9333


4

สำหรับ C # NUnit คุณต้องแปลง WebDriver เป็น JSExecuter จากนั้นเรียกใช้สคริปต์เพื่อตรวจสอบว่า document.ready state เสร็จสมบูรณ์หรือไม่ ตรวจสอบโค้ดด้านล่างเพื่ออ้างอิง:

 public static void WaitForLoad(IWebDriver driver)
    {
        IJavaScriptExecutor js = (IJavaScriptExecutor)driver;
        int timeoutSec = 15;
        WebDriverWait wait = new WebDriverWait(driver, new TimeSpan(0, 0, timeoutSec));
        wait.Until(wd => js.ExecuteScript("return document.readyState").ToString() == "complete");
    }

การดำเนินการนี้จะรอจนกว่าเงื่อนไขจะเป็นที่พอใจหรือหมดเวลา


3

สำหรับการโหลดหน้าครั้งแรกฉันสังเกตเห็นว่า "การขยายใหญ่สุด" หน้าต่างเบราว์เซอร์รอจนกว่าการโหลดหน้าเว็บจะเสร็จสมบูรณ์ (รวมถึงแหล่งที่มา)

แทนที่:

AppDriver.Navigate().GoToUrl(url);

ด้วย:

public void OpenURL(IWebDriver AppDriver, string Url)
            {
                try
                {
                    AppDriver.Navigate().GoToUrl(Url);
                    AppDriver.Manage().Window.Maximize();
                    AppDriver.SwitchTo().ActiveElement();
                }
                catch (Exception e)
                {
                    Console.WriteLine("ERR: {0}; {1}", e.TargetSite, e.Message);
                    throw;
                }
            }

กว่าใช้:

OpenURL(myDriver, myUrl);

การดำเนินการนี้จะโหลดหน้านี้รอจนกว่าจะเสร็จสมบูรณ์ขยายใหญ่สุดและโฟกัสไปที่หน้านั้น ฉันไม่รู้ว่าทำไมมันถึงเป็นแบบนี้ แต่มันได้ผล

หากคุณต้องการรอให้โหลดหน้าหลังจากคลิกที่ถัดไปหรือทริกเกอร์การนำทางหน้าอื่น ๆ จากนั้น "Navigate ()" คำตอบของ Ben Dyer (ในหัวข้อนี้) จะทำงาน


1

ดูที่tapestry web-framework คุณสามารถดาวน์โหลดซอร์สโค้ดได้ที่นั่น

แนวคิดคือการส่งสัญญาณว่าเพจพร้อมแล้วโดยแอตทริบิวต์ html of body คุณสามารถใช้แนวคิดนี้ละเว้นคดีฟ้องร้องที่ซับซ้อน

<html>
<head>
</head>
<body data-page-initialized="false">
    <p>Write you page here</p>

    <script>
    $(document).ready(function () {
        $(document.body).attr('data-page-initialized', 'true');
    });
    </script>  
</body>
</html>

จากนั้นสร้างส่วนขยายของ Selenium webdriver (ตาม tapestry framework)

public static void WaitForPageToLoad(this IWebDriver driver, int timeout = 15000)
{
    //wait a bit for the page to start loading
    Thread.Sleep(100);

    //// In a limited number of cases, a "page" is an container error page or raw HTML content
    // that does not include the body element and data-page-initialized element. In those cases,
    // there will never be page initialization in the Tapestry sense and we return immediately.
    if (!driver.ElementIsDisplayed("/html/body[@data-page-initialized]"))
    {                
        return;
    }

    Stopwatch stopwatch = Stopwatch.StartNew();

    int sleepTime = 20;

    while(true)
    {
        if (driver.ElementIsDisplayed("/html/body[@data-page-initialized='true']"))
        {
            return;
        }

        if (stopwatch.ElapsedMilliseconds > 30000)
        {
            throw new Exception("Page did not finish initializing after 30 seconds.");
        }

        Thread.Sleep(sleepTime);
        sleepTime *= 2; // geometric row of sleep time
    }          
}

การขยายการใช้งาน ElementIsDisplayed เขียนโดย Alister สกอตต์

public static bool ElementIsDisplayed(this IWebDriver driver, string xpath)
{
    try
    {
        return driver.FindElement(By.XPath(xpath)).Displayed;
    }
    catch(NoSuchElementException)
    {
        return false;
    }
}

และสุดท้ายสร้างการทดสอบ:

driver.Url = this.GetAbsoluteUrl("/Account/Login");            
driver.WaitForPageToLoad();

1

คำตอบของ Ben Dryer ไม่ได้รวบรวมไว้ในเครื่องของฉัน ( "The method until(Predicate<WebDriver>) is ambiguous for the type WebDriverWait")

เวอร์ชัน Java 8 ที่ใช้งานได้:

Predicate<WebDriver> pageLoaded = wd -> ((JavascriptExecutor) wd).executeScript(
        "return document.readyState").equals("complete");
new FluentWait<WebDriver>(driver).until(pageLoaded);

เวอร์ชัน Java 7:

Predicate<WebDriver> pageLoaded = new Predicate<WebDriver>() {

        @Override
        public boolean apply(WebDriver input) {
            return ((JavascriptExecutor) input).executeScript("return document.readyState").equals("complete");
        }

};
new FluentWait<WebDriver>(driver).until(pageLoaded);

1

ฉันลองใช้รหัสนี้แล้วและใช้ได้กับฉัน ฉันเรียกใช้ฟังก์ชันนี้ทุกครั้งที่ย้ายไปหน้าอื่น

public static void waitForPageToBeReady() 
{
    JavascriptExecutor js = (JavascriptExecutor)driver;

    //This loop will rotate for 100 times to check If page Is ready after every 1 second.
    //You can replace your if you wants to Increase or decrease wait time.
    for (int i=0; i<400; i++)
    { 
        try 
        {
            Thread.sleep(1000);
        }catch (InterruptedException e) {} 
        //To check page ready state.

        if (js.executeScript("return document.readyState").toString().equals("complete"))
        { 
            break; 
        }   
      }
 }

1

ใน 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) → Thenable

กำหนดตารางคำสั่งเพื่อนำทางไปยัง URL ที่กำหนด

ส่งคืนคำสัญญาที่จะได้รับการแก้ไขเมื่อโหลดเอกสารเสร็จสิ้นการโหลดเสร็จแล้ว

เอกสารซีลีเนียม (Nodejs)


1

การรอเหตุการณ์ document.ready ไม่ใช่การแก้ไขปัญหานี้ทั้งหมดเนื่องจากโค้ดนี้ยังคงอยู่ในสภาพการแข่งขัน: บางครั้งโค้ดนี้จะเริ่มทำงานก่อนที่เหตุการณ์การคลิกจะถูกประมวลผลดังนั้นสิ่งนี้จะส่งกลับโดยตรงเนื่องจากเบราว์เซอร์ยังไม่เริ่มทำงาน กำลังโหลดหน้าใหม่

หลังจากการค้นหาบางครั้งฉันพบโพสต์เกี่ยวกับObay the testing goatซึ่งมีวิธีแก้ปัญหานี้ รหัส c # สำหรับโซลูชันนั้นเป็นดังนี้:

 IWebElement page = null;
 ...
 public void WaitForPageLoad()
 {
    if (page != null)
    {
       var waitForCurrentPageToStale = new WebDriverWait(driver, TimeSpan.FromSeconds(10));
       waitForCurrentPageToStale.Until(ExpectedConditions.StalenessOf(page));
    }

    var waitForDocumentReady = new WebDriverWait(driver, TimeSpan.FromSeconds(10));
    waitForDocumentReady.Until((wdriver) => (driver as IJavaScriptExecutor).ExecuteScript("return document.readyState").Equals("complete"));

    page = driver.FindElement(By.TagName("html"));

}

`ฉันยิงวิธีนี้โดยตรงหลังจาก driver.navigate.gotourl เพื่อให้ได้รับการอ้างอิงของหน้าโดยเร็วที่สุด ขอให้สนุกกับมัน!


1

ปกติเมื่อซีลีเนียมเปิดหน้าใหม่จากการคลิกหรือส่งหรือรับวิธีการมันจะรอจนกว่าจะโหลดหน้าเว็บ แต่ปัญหาคือเมื่อหน้ามีการเรียก xhr (ajax) เขาจะไม่รอให้ xhr โหลดดังนั้น การสร้างเมธอดใหม่เพื่อตรวจสอบ xhr และรอมันจะเป็นการดี

public boolean waitForJSandJQueryToLoad() {
    WebDriverWait wait = new WebDriverWait(webDriver, 30);
    // wait for jQuery to load
    ExpectedCondition<Boolean> jQueryLoad = new ExpectedCondition<Boolean>() {
      @Override
      public Boolean apply(WebDriver driver) {
        try {
            Long r = (Long)((JavascriptExecutor)driver).executeScript("return $.active");
            return r == 0;
        } catch (Exception e) {
            LOG.info("no jquery present");
            return true;
        }
      }
    };

    // wait for Javascript to load
    ExpectedCondition<Boolean> jsLoad = new ExpectedCondition<Boolean>() {
      @Override
      public Boolean apply(WebDriver driver) {
        return ((JavascriptExecutor)driver).executeScript("return document.readyState")
        .toString().equals("complete");
      }
    };

  return wait.until(jQueryLoad) && wait.until(jsLoad);
}

if $.active == 0ดังนั้นจึงไม่มีการเรียก xhrs ที่ใช้งานอยู่ (ซึ่งใช้ได้กับ jQuery เท่านั้น) สำหรับการเรียก javascript ajax คุณต้องสร้างตัวแปรในโปรเจ็กต์ของคุณและจำลองมัน


0

คุณสามารถเขียนตรรกะเพื่อจัดการสิ่งนี้ได้ ฉันได้เขียนวิธีการที่จะคืนค่าWebElementและวิธีนี้จะเรียกว่าสามครั้งหรือคุณสามารถเพิ่มเวลาและเพิ่มการตรวจสอบค่าว่างสำหรับWebElementนี่คือตัวอย่าง

public static void main(String[] args) {
        WebDriver driver = new FirefoxDriver();
        driver.get("https://www.crowdanalytix.com/#home");
        WebElement webElement = getWebElement(driver, "homekkkkkkkkkkkk");
        int i = 1;
        while (webElement == null && i < 4) {
            webElement = getWebElement(driver, "homessssssssssss");
            System.out.println("calling");
            i++;
        }
        System.out.println(webElement.getTagName());
        System.out.println("End");
        driver.close();
    }

    public static WebElement getWebElement(WebDriver driver, String id) {
        WebElement myDynamicElement = null;
        try {
            myDynamicElement = (new WebDriverWait(driver, 10))
                    .until(ExpectedConditions.presenceOfElementLocated(By
                            .id(id)));
            return myDynamicElement;
        } catch (TimeoutException ex) {
            return null;
        }
    }

0

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

public static boolean waitUntilDOMIsReady(WebDriver driver) {
def maxSeconds = DEFAULT_WAIT_SECONDS * 10
for (count in 1..maxSeconds) {
    Thread.sleep(100)
    def ready = isDOMReady(driver);
    if (ready) {
        break;
    }
}

}

public static boolean isDOMReady(WebDriver driver){
    return driver.executeScript("return document.readyState");
}

0
public boolean waitForElement(String zoneName, String element, int index, int timeout) {
        WebDriverWait wait = new WebDriverWait(appiumDriver, timeout/1000);
        wait.until(ExpectedConditions.visibilityOfElementLocated(By.xpath(element)));
        return true;
    }

0

เช่นเดียวกับที่ Rubanov เขียนสำหรับ C # ฉันเขียนสำหรับ Java และมันคือ:

    public void waitForPageLoaded() {
    ExpectedCondition<Boolean> expectation = new
            ExpectedCondition<Boolean>() {
                public Boolean apply(WebDriver driver) {
                    return (((JavascriptExecutor) driver).executeScript("return document.readyState").toString().equals("complete")&&((Boolean)((JavascriptExecutor)driver).executeScript("return jQuery.active == 0")));
                }
            };
    try {
        Thread.sleep(100);
        WebDriverWait waitForLoad = new WebDriverWait(driver, 30);
        waitForLoad.until(expectation);
    } catch (Throwable error) {
        Assert.fail("Timeout waiting for Page Load Request to complete.");
    }
}

0

ใน Java จะเป็นดังนี้: -

  private static boolean isloadComplete(WebDriver driver)
    {
        return ((JavascriptExecutor) driver).executeScript("return document.readyState").equals("loaded")
                || ((JavascriptExecutor) driver).executeScript("return document.readyState").equals("complete");
    }

1
มันจะดีกว่าถ้ารวมคำสั่ง JS เป็นคำสั่งเดียวเพื่อที่คุณจะได้ไม่ต้องกดหน้าสองครั้งเช่นreturn document.readyState == 'loaded' || return document.readyState == 'complete'
JeffC

0

รหัสต่อไปนี้น่าจะใช้ได้:

WebDriverWait wait = new WebDriverWait(driver, 10);
wait.until(ExpectedConditions.presenceOfAllElementsLocated(By.xpath("//*")));

0

หากคุณมีเพจหรือการเชื่อมต่อเครือข่ายที่ช้าอาจเป็นไปได้ว่าสิ่งที่กล่าวมาข้างต้นจะไม่ได้ผล ฉันได้ลองทั้งหมดแล้วและสิ่งเดียวที่ได้ผลสำหรับฉันคือรอองค์ประกอบสุดท้ายที่มองเห็นได้ในหน้านั้น ยกตัวอย่างเช่นหน้าเว็บ Bing พวกเขาได้วางไอคอน CAMERA (ปุ่มค้นหาด้วยรูปภาพ) ถัดจากปุ่มค้นหาหลักซึ่งจะมองเห็นได้หลังจากโหลดเพจเสร็จแล้วเท่านั้น หากทุกคนทำเช่นนั้นสิ่งที่เราต้องทำก็คือใช้การรออย่างชัดเจนดังตัวอย่างด้านบน


-1
public void waitForPageToLoad()
  {
(new WebDriverWait(driver, DEFAULT_WAIT_TIME)).until(new ExpectedCondition<Boolean>() {
      public Boolean apply(WebDriver d) {
        return (((org.openqa.selenium.JavascriptExecutor) driver).executeScript("return document.readyState").equals("complete"));
      }
    });//Here DEFAULT_WAIT_TIME is a integer correspond to wait time in seconds

-1

นี่คือสิ่งที่คล้ายกันใน Ruby:

wait = Selenium::WebDriver::Wait.new(:timeout => 10)
wait.until { @driver.execute_script('return document.readyState').eql?('complete') }

รหัสของคุณใช้ไม่ได้สำหรับฉัน ฉันจะเปลี่ยนทำ iframe ได้อย่างไรและรอให้ onload = "javascript: pageload (); functionalPageLoad ();" เพื่อโหลดหน้าซ้ำใน Ruby? ฉันพบว่าตัวเองเปิด iframe ภายในเพจฉันสามารถเข้าถึงได้จากนั้นเพจก็โหลดซ้ำและฉันไม่สามารถเข้าถึงเฟรมได้อีกต่อไป ฉันได้อ่านคำตอบมากมายเกี่ยวกับการรอการนอนหลับเวลาเปลี่ยนไปใช้เฟรมจากนั้นเป็นผู้ปกครอง แต่ฉันไม่สามารถบรรลุเป้าหมายได้
อแมนดาคาวัลลาโร

1
ดูเหมือนว่าคำถามของคุณส่วนใหญ่เกี่ยวกับวิธีเปลี่ยนไปใช้ iFrame ไม่ใช่เกี่ยวกับการรอโหลดเอกสาร อาจจะดีกว่าถ้าคุณเริ่มคำถามใหม่หากคุณไม่พบคำตอบในคำถามเกี่ยวกับการทำงานกับ iFrames
Emery

-1

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

driver.get(homeUrl); 
Thread.sleep(5000);
driver.findElement(By.xpath("Your_Xpath_here")).sendKeys(userName);
driver.findElement(By.xpath("Your_Xpath_here")).sendKeys(passWord);
driver.findElement(By.xpath("Your_Xpath_here")).click();

ฉันพบว่า Thread.sleep (5000) มักเป็นวิธีเดียวที่ได้รับการทดสอบแม้ว่าจะมีคำแนะนำทั้งหมดที่ไม่ให้ใช้ก็ตาม ไม่มีการรวมกันของการรอให้องค์ประกอบทำงานสำหรับฉันโดยเฉพาะอย่างยิ่งเมื่อไม่สามารถระบุองค์ประกอบจำนวนมากได้จนกว่าจะพบจริง
Steve Staple

-1

ฉันตรวจสอบการโหลดหน้าเสร็จแล้วทำงานในซีลีเนียม 3.14.0

    public static void UntilPageLoadComplete(IWebDriver driver, long timeoutInSeconds)
    {
        Until(driver, (d) =>
        {
            Boolean isPageLoaded = (Boolean)((IJavaScriptExecutor)driver).ExecuteScript("return document.readyState").Equals("complete");
            if (!isPageLoaded) Console.WriteLine("Document is loading");
            return isPageLoaded;
        }, timeoutInSeconds);
    }

    public static void Until(IWebDriver driver, Func<IWebDriver, Boolean> waitCondition, long timeoutInSeconds)
    {
        WebDriverWait webDriverWait = new WebDriverWait(driver, TimeSpan.FromSeconds(timeoutInSeconds));
        webDriverWait.Timeout = TimeSpan.FromSeconds(timeoutInSeconds);
        try
        {
            webDriverWait.Until(waitCondition);
        }
        catch (Exception e)
        {
            Console.WriteLine(e);
        }
    }

-1

สำหรับผู้ที่ต้องรอให้องค์ประกอบเฉพาะปรากฏขึ้น (ใช้ c #)

public static void WaitForElement(IWebDriver driver, By element)
{
    WebDriverWait wait = new WebDriverWait(driver, TimeSpan.FromSeconds(20));
    wait.Until(ExpectedConditions.ElementIsVisible(element));
}

จากนั้นหากคุณต้องการรอตัวอย่างเช่นหาก class = "error-message" มีอยู่ใน DOM คุณก็ทำดังนี้

WaitForElement(driver, By.ClassName("error-message"));

สำหรับ id นั้นจะเป็น

WaitForElement(driver, By.Id("yourid"));


-3

คุณใช้ Angular หรือไม่? หากคุณเป็นไปได้ว่า webdriver ไม่ทราบว่าการโทรแบบ async เสร็จสิ้นแล้ว

ผมขอแนะนำให้มองหาที่พอล Hammants ngWebDriver วิธีการ waitForAngularRequestsToFinish () อาจมีประโยชน์


เขาไม่ได้ใช้ Angular เป็นอย่างมาก คำตอบนี้ถูกลดคะแนนเนื่องจากดูเหมือนว่าคุณไม่ได้อ่านคำถามเดิมอย่างละเอียด
zelusp

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