Selenium WebDriver: รอให้หน้าที่ซับซ้อนที่มี JavaScript โหลด


103

ฉันมีเว็บแอปพลิเคชันที่จะทดสอบกับซีลีเนียม มี JavaScript จำนวนมากที่ทำงานบนการโหลดหน้าเว็บ
โค้ด JavaScript นี้เขียนไม่ค่อยดี แต่ไม่สามารถเปลี่ยนแปลงอะไรได้ ดังนั้นการรอให้องค์ประกอบปรากฏใน DOM ด้วยfindElement()วิธีการจึงไม่ใช่ทางเลือก
ฉันต้องการสร้างฟังก์ชันทั่วไปใน Java เพื่อรอให้เพจโหลดวิธีแก้ปัญหาที่เป็นไปได้คือ:

  • เรียกใช้ WebDriver รูปแบบ JavaScript สคริปต์และเก็บผลของในตัวแปรสตริงdocument.body.innerHTMLbody
  • เปรียบเทียบbodyตัวแปรกับเวอร์ชันก่อนหน้าของbody. ถ้าพวกเขาจะเหมือนกันจากนั้นตั้งค่าเพิ่มเคาน์เตอร์notChangedCountกำหนดมิฉะนั้นnotChangedCountจะเป็นศูนย์
  • รอสักครู่ (ตัวอย่างเช่น 50 ms)
  • หากเพจไม่มีการเปลี่ยนแปลงในบางครั้ง (เช่น 500 มิลลิวินาที) ดังนั้นให้notChangedCount >= 10ออกจากลูปมิฉะนั้นวนซ้ำไปที่ขั้นตอนแรก

คุณคิดว่าเป็นวิธีแก้ปัญหาที่ถูกต้องหรือไม่?


findElement () ไม่รอ - คุณหมายถึงอะไร?
Rostislav Matl

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

ฉันลืมไปแล้ว - ฉันเคยใช้ WebDriverWait และ expectedCondition มันมีความยืดหยุ่นมากกว่า
Rostislav Matl

คำตอบ:


73

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

มีหลายสิ่งที่คุณสามารถทำได้ แต่ทุกสิ่งมีปัญหา:

  1. ดังที่ Ashwin Prabhu กล่าวไว้หากคุณรู้จักสคริปต์ดีคุณสามารถสังเกตพฤติกรรมและติดตามตัวแปรบางอย่างบนwindowหรือdocumentอื่น ๆ ได้อย่างไรก็ตามโซลูชันนี้ไม่ได้มีไว้สำหรับทุกคนและสามารถใช้ได้โดยคุณเท่านั้นและในชุดที่ จำกัด เท่านั้น หน้า

  2. วิธีแก้ปัญหาของคุณโดยสังเกตโค้ด HTML และไม่ว่าจะมีการเปลี่ยนแปลงหรือไม่ในบางครั้งก็ไม่เลว (นอกจากนี้ยังมีวิธีรับ HTML ต้นฉบับและไม่ได้แก้ไขโดยตรงโดยWebDriver) แต่:

    • ใช้เวลานานในการยืนยันหน้าเว็บจริงและอาจยืดเวลาการทดสอบได้มาก
    • คุณไม่มีทางรู้ว่าช่วงเวลาที่เหมาะสมคืออะไร สคริปต์อาจกำลังดาวน์โหลดสิ่งที่ยิ่งใหญ่ซึ่งใช้เวลามากกว่า 500 มิลลิวินาที มีสคริปต์หลายตัวในหน้าภายในของ บริษัท ซึ่งใช้เวลาหลายวินาทีใน IE คอมพิวเตอร์ของคุณอาจขาดแคลนทรัพยากรชั่วคราว - กล่าวว่าโปรแกรมป้องกันไวรัสจะทำให้ CPU ของคุณทำงานได้เต็มที่จากนั้น 500 มิลลิวินาทีอาจสั้นเกินไปสำหรับสคริปต์ที่ไม่ซับซ้อน
    • บางสคริปต์ไม่เคยทำ พวกเขาเรียกตัวเองว่ามีความล่าช้า ( setTimeout()) และทำงานซ้ำแล้วซ้ำอีกและอาจเปลี่ยน HTML ทุกครั้งที่เรียกใช้ อย่างจริงจังทุกหน้า "Web 2.0" ทำ แม้แต่ Stack Overflow คุณสามารถเขียนทับวิธีการทั่วไปที่ใช้และพิจารณาสคริปต์ที่ใช้ว่าเสร็จสมบูรณ์ แต่ ... คุณไม่แน่ใจ
    • จะเกิดอะไรขึ้นถ้าสคริปต์ทำอย่างอื่นนอกเหนือจากการเปลี่ยน HTML? มันสามารถทำได้หลายพันสิ่งไม่ใช่แค่innerHTMLความสนุก
  3. มีเครื่องมือที่จะช่วยคุณในเรื่องนี้ ได้แก่Progress Listenersร่วมกับnsIWebProgressListenerและอื่น ๆ อย่างไรก็ตามการรองรับเบราว์เซอร์สำหรับสิ่งนี้นั้นแย่มาก Firefox เริ่มพยายามสนับสนุนตั้งแต่ FF4 เป็นต้นไป (ยังคงพัฒนาอยู่) IE มีการสนับสนุนพื้นฐานใน IE9

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


31

ขอบคุณ Ashwin!

ในกรณีของฉันฉันควรรอให้การดำเนินการปลั๊กอิน jquery ในบางองค์ประกอบ .. โดยเฉพาะ "qtip"

ตามคำใบ้ของคุณมันทำงานได้ดีสำหรับฉัน:

wait.until( new Predicate<WebDriver>() {
            public boolean apply(WebDriver driver) {
                return ((JavascriptExecutor)driver).executeScript("return document.readyState").equals("complete");
            }
        }
    );

หมายเหตุ: ฉันใช้ Webdriver 2


2
มันได้ผลดีสำหรับฉันด้วย ในกรณีของฉันองค์ประกอบถูกแก้ไขโดย Javascript หลังจากที่โหลดหน้าเว็บเสร็จแล้วและซีลีเนียมไม่ได้รอสิ่งนั้น
Noxxys

2
Predicate มาจากไหน? นำเข้าตัวไหน ??
Amado Saladino

@AmadoSaladino "นำเข้า com.google.common.base.Predicate;" จากลิงค์ google lib guava-15.0: mvnrepository.com/artifact/com.google.guava/guava/15.0มีเวอร์ชันใหม่กว่า 27.0 ให้คุณลอง!
Eduardo Fabricio

26

คุณต้องรอให้ Javascript และ jQuery โหลดจนเสร็จ ดำเนินการ Javascript เพื่อตรวจสอบว่าjQuery.activeเป็น0และdocument.readyStateเป็นcompleteหรือไม่ซึ่งหมายความว่าการโหลด JS และ jQuery เสร็จสมบูรณ์

public boolean waitForJStoLoad() {

    WebDriverWait wait = new WebDriverWait(driver, 30);

    // wait for jQuery to load
    ExpectedCondition<Boolean> jQueryLoad = new ExpectedCondition<Boolean>() {
      @Override
      public Boolean apply(WebDriver driver) {
        try {
          return ((Long)executeJavaScript("return jQuery.active") == 0);
        }
        catch (Exception e) {
          return true;
        }
      }
    };

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

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

2
ไม่แน่ใจว่าจะใช้ได้ในทุกสถานการณ์หรือไม่ แต่ใช้ได้ผลกับกรณีการใช้งานของฉัน
DaveH

1
มันก็ใช้ได้สำหรับฉันเช่นกัน แต่มีส่วนที่ยุ่งยาก: สมมติว่าเพจของคุณโหลดแล้ว หากคุณโต้ตอบกับองค์ประกอบ [เช่นส่ง. คลิก () หรือ. ส่งคีย์ไปที่มัน] จากนั้นคุณต้องการตรวจสอบเมื่อเพจของคุณประมวลผลเสร็จแล้วคุณต้องเพิ่มการหน่วงเวลา: เช่น click (), sleep (0.5 วินาที ) รอจนกว่า (readyState = 'complete' & jQuery.active == 0) หากคุณไม่เพิ่มการนอนหลับ iQuery จะไม่ทำงานในเวลาทดสอบ! (ฉันใช้เวลาหลายชั่วโมงในการค้นหาฉันจึงคิดที่จะแบ่งปัน)
Fivos Vilanakis

document.readyState == 'complete' && jQuery.active == 0ใช้งานได้ดี แต่มีบางอย่างเช่นนั้นสำหรับ React หรือไม่? เนื่องจากการตรวจสอบเหล่านั้นไม่สามารถตรวจจับได้ยังคงโหลดข้อมูลการตอบสนอง / ส่วนประกอบ?
ฝน 9333

10

ไลบรารี JS กำหนด / เริ่มต้นตัวแปรที่รู้จักกันดีบนหน้าต่างหรือไม่

หากเป็นเช่นนั้นคุณสามารถรอให้ตัวแปรปรากฏขึ้น คุณสามารถใช้ได้

((JavascriptExecutor)driver).executeScript(String script, Object... args)

เพื่อทดสอบเงื่อนไขนี้ (บางอย่างเช่นwindow.SomeClass && window.SomeClass.variable != null:) และส่งคืนบูลีนtrue/ false.

ห่อสิ่งนี้ใน a WebDriverWaitและรอจนกว่าสคริปต์จะกลับtrueมา


8

หากสิ่งที่คุณต้องทำคือรอให้ html บนเพจเสถียรก่อนที่จะพยายามโต้ตอบกับองค์ประกอบคุณสามารถสำรวจ DOM เป็นระยะ ๆ และเปรียบเทียบผลลัพธ์หาก DOM เหมือนกันภายในเวลาสำรวจที่กำหนดคุณ สีทอง. สิ่งนี้ที่คุณผ่านในเวลารอสูงสุดและเวลาระหว่างการสำรวจหน้าก่อนที่จะเปรียบเทียบ ง่ายและมีประสิทธิภาพ

public void waitForJavascript(int maxWaitMillis, int pollDelimiter) {
    double startTime = System.currentTimeMillis();
    while (System.currentTimeMillis() < startTime + maxWaitMillis) {
        String prevState = webDriver.getPageSource();
        Thread.sleep(pollDelimiter); // <-- would need to wrap in a try catch
        if (prevState.equals(webDriver.getPageSource())) {
            return;
        }
    }
}

1
ฉันต้องการทราบที่นี่ว่าฉันบันทึกเวลาที่ใช้ในการสำรวจหน้าขนาดกลางสองครั้งจากนั้นเปรียบเทียบสตริงเหล่านั้นใน java และใช้เวลามากกว่า 20 มิลลิวินาทีเล็กน้อย
TheFreddyKilo

2
ตอนแรกฉันพบว่านี่เป็นวิธีแก้ปัญหาที่สกปรก แต่ดูเหมือนว่าจะใช้งานได้ดีและไม่เกี่ยวข้องกับการตั้งค่าตัวแปรฝั่งไคลเอ็นต์ ข้อแม้หนึ่งอาจเป็นหน้าที่จาวาสคริปต์เปลี่ยนแปลงอยู่ตลอดเวลา (เช่นนาฬิกาจาวาสคริปต์) แต่ฉันไม่มีมันจึงใช้งานได้!
Peter

7

ฉันมีปัญหาเดียวกัน วิธีนี้ใช้ได้กับฉันจาก WebDriverDoku:

WebDriverWait wait = new WebDriverWait(driver, 10);
WebElement element = wait.until(ExpectedConditions.elementToBeClickable(By.id("someid")));

http://www.seleniumhq.org/docs/04_webdriver_advanced.jsp


ขอบคุณ. รหัสที่อยู่ในลิงก์ใช้ได้กับฉัน
ecamur

4

โค้ดด้านล่างทำงานได้อย่างสมบูรณ์ในกรณีของฉัน - หน้าของฉันมีสคริปต์จาวาที่ซับซ้อน

public void checkPageIsReady() {

  JavascriptExecutor js = (JavascriptExecutor)driver;


  //Initially bellow given if condition will check ready state of page.
  if (js.executeScript("return document.readyState").toString().equals("complete")){ 
   System.out.println("Page Is loaded.");
   return; 
  } 

  //This loop will rotate for 25 times to check If page Is ready after every 1 second.
  //You can replace your value with 25 If you wants to Increase or decrease wait time.
  for (int i=0; i<25; i++){ 
   try {
    Thread.sleep(1000);
    }catch (InterruptedException e) {} 
   //To check page ready state.
   if (js.executeScript("return document.readyState").toString().equals("complete")){ 
    break; 
   }   
  }
 }

ที่มา - วิธีรอให้เพจโหลด / พร้อมใน Selenium WebDriver


2
คุณควรใช้ซีลีเนียมรอแทนลูป
cocorossello

4

สามารถใช้เงื่อนไขสองข้อเพื่อตรวจสอบว่าเพจถูกโหลดก่อนที่จะค้นหาองค์ประกอบใด ๆ บนเพจ:

WebDriverWait wait = new WebDriverWait(driver, 50);

การใช้ readyState ด้านล่างจะรอจนกว่าจะโหลดหน้า

wait.until((ExpectedCondition<Boolean>) wd ->
   ((JavascriptExecutor) wd).executeScript("return document.readyState").equals("complete"));

ด้านล่าง JQuery จะรอจนกว่าข้อมูลจะไม่ถูกโหลด

  int count =0;
            if((Boolean) executor.executeScript("return window.jQuery != undefined")){
                while(!(Boolean) executor.executeScript("return jQuery.active == 0")){
                    Thread.sleep(4000);
                    if(count>4)
                        break;
                    count++;
                }
            }

หลังจาก JavaScriptCode เหล่านี้ให้ลอง findOut webElement

WebElement we = wait.until(ExpectedConditions.presenceOfElementLocated(by));

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

2

ฉันขอให้นักพัฒนาสร้างตัวแปร JavaScript "isProcessing" ที่ฉันสามารถเข้าถึงได้ (ในออบเจ็กต์ "ae") ที่พวกเขาตั้งไว้เมื่อสิ่งต่างๆเริ่มทำงานและล้างเมื่อสิ่งต่างๆเสร็จสิ้น จากนั้นฉันเรียกใช้ในแอคคูมูเลเตอร์ที่ตรวจสอบทุกๆ 100 มิลลิวินาทีจนกว่าจะได้รับห้าติดต่อกันรวมเป็น 500 มิลลิวินาทีโดยไม่มีการเปลี่ยนแปลงใด ๆ ถ้าผ่านไป 30 วินาทีฉันจะทิ้งข้อยกเว้นเพราะน่าจะเกิดขึ้นในตอนนั้น อยู่ใน C #

public static void WaitForDocumentReady(this IWebDriver driver)
{
    Console.WriteLine("Waiting for five instances of document.readyState returning 'complete' at 100ms intervals.");
    IJavaScriptExecutor jse = (IJavaScriptExecutor)driver;
    int i = 0; // Count of (document.readyState === complete) && (ae.isProcessing === false)
    int j = 0; // Count of iterations in the while() loop.
    int k = 0; // Count of times i was reset to 0.
    bool readyState = false;
    while (i < 5)
    {
        System.Threading.Thread.Sleep(100);
        readyState = (bool)jse.ExecuteScript("return ((document.readyState === 'complete') && (ae.isProcessing === false))");
        if (readyState) { i++; }
        else
        {
            i = 0;
            k++;
        }
        j++;
        if (j > 300) { throw new TimeoutException("Timeout waiting for document.readyState to be complete."); }
    }
    j *= 100;
    Console.WriteLine("Waited " + j.ToString() + " milliseconds. There were " + k + " resets.");
}

1

ในการดำเนินการอย่างถูกต้องคุณต้องจัดการกับข้อยกเว้น

นี่คือวิธีการรอ iFrame สิ่งนี้ต้องการให้คลาสทดสอบ JUnit ของคุณส่งอินสแตนซ์ของ RemoteWebDriver ไปยังออบเจ็กต์เพจ:

public class IFrame1 extends LoadableComponent<IFrame1> {

    private RemoteWebDriver driver;

    @FindBy(id = "iFrame1TextFieldTestInputControlID" )
    public WebElement iFrame1TextFieldInput;

    @FindBy(id = "iFrame1TextFieldTestProcessButtonID" )
    public WebElement copyButton;

    public IFrame1( RemoteWebDriver drv ) {
        super();
        this.driver = drv;
        this.driver.switchTo().defaultContent();
        waitTimer(1, 1000);
        this.driver.switchTo().frame("BodyFrame1");
        LOGGER.info("IFrame1 constructor...");
    }

    @Override
    protected void isLoaded() throws Error {        
        LOGGER.info("IFrame1.isLoaded()...");
        PageFactory.initElements( driver, this );
        try {
            assertTrue( "Page visible title is not yet available.", driver
     .findElementByCssSelector("body form#webDriverUnitiFrame1TestFormID h1")
                    .getText().equals("iFrame1 Test") );
        } catch ( NoSuchElementException e) {
            LOGGER.info("No such element." );
            assertTrue("No such element.", false);
        }
    }

    @Override
    protected void load() {
        LOGGER.info("IFrame1.load()...");
        Wait<WebDriver> wait = new FluentWait<WebDriver>( driver )
                .withTimeout(30, TimeUnit.SECONDS)
                .pollingEvery(5, TimeUnit.SECONDS)
                .ignoring( NoSuchElementException.class ) 
                .ignoring( StaleElementReferenceException.class ) ;
            wait.until( ExpectedConditions.presenceOfElementLocated( 
            By.cssSelector("body form#webDriverUnitiFrame1TestFormID h1") ) );
    }
....

หมายเหตุ: คุณสามารถดูตัวอย่างการทำงานทั้งหมดของฉันที่นี่


1

สำหรับnodejsไลบรารี Selenium ฉันใช้ตัวอย่างต่อไปนี้ ในกรณีของฉันฉันถูกมองหาวัตถุทั้งสองที่มีการเพิ่มไปที่หน้าต่างซึ่งในตัวอย่างนี้<SOME PROPERTY>, 10000เป็นมิลลิวินาทีหมดเวลา<NEXT STEP HERE>คือสิ่งที่เกิดขึ้นหลังจากที่คุณสมบัติที่พบบนหน้าต่าง

driver.wait( driver => {
    return driver.executeScript( 'if(window.hasOwnProperty(<SOME PROPERTY>) && window.hasOwnProperty(<SOME PROPERTY>)) return true;' ); }, 10000).then( ()=>{
        <NEXT STEP HERE>
}).catch(err => { 
    console.log("looking for window properties", err);
});

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

นี่มาจากรหัสของฉันเอง:
Window.setTimeout ทำงานเฉพาะเมื่อเบราว์เซอร์ไม่ได้ใช้งาน
ดังนั้นการเรียกใช้ฟังก์ชันแบบวนซ้ำ (42 ครั้ง) จะใช้เวลา 100ms หากไม่มีกิจกรรมในเบราว์เซอร์และอื่น ๆ อีกมากมายหากเบราว์เซอร์ไม่ว่างทำอย่างอื่น

    ExpectedCondition<Boolean> javascriptDone = new ExpectedCondition<Boolean>() {
        public Boolean apply(WebDriver d) {
            try{//window.setTimeout executes only when browser is idle,
                //introduces needed wait time when javascript is running in browser
                return  ((Boolean) ((JavascriptExecutor) d).executeAsyncScript( 

                        " var callback =arguments[arguments.length - 1]; " +
                        " var count=42; " +
                        " setTimeout( collect, 0);" +
                        " function collect() { " +
                            " if(count-->0) { "+
                                " setTimeout( collect, 0); " +
                            " } "+
                            " else {callback(" +
                            "    true" +                            
                            " );}"+                             
                        " } "
                    ));
            }catch (Exception e) {
                return Boolean.FALSE;
            }
        }
    };
    WebDriverWait w = new WebDriverWait(driver,timeOut);  
    w.until(javascriptDone);
    w=null;

เป็นโบนัสสามารถรีเซ็ตตัวนับบน document.readyState หรือบนการโทร jQuery Ajax หรือหากแอนิเมชั่น jQuery กำลังทำงานอยู่ (เฉพาะในกรณีที่แอพของคุณใช้ jQuery สำหรับการโทร ajax ... )
...

" function collect() { " +
                            " if(!((typeof jQuery === 'undefined') || ((jQuery.active === 0) && ($(\":animated\").length === 0))) && (document.readyState === 'complete')){" +
                            "    count=42;" +
                            "    setTimeout( collect, 0); " +
                            " }" +
                            " else if(count-->0) { "+
                                " setTimeout( collect, 0); " +
                            " } "+ 

...

แก้ไข: ฉันสังเกตเห็นว่า executeAsyncScript ทำงานได้ไม่ดีหากหน้าใหม่โหลดขึ้นและการทดสอบอาจหยุดตอบสนองโดยไม่กำหนดควรใช้สิ่งนี้แทน

public static ExpectedCondition<Boolean> documentNotActive(final int counter){ 
    return new ExpectedCondition<Boolean>() {
        boolean resetCount=true;
        @Override
        public Boolean apply(WebDriver d) {

            if(resetCount){
                ((JavascriptExecutor) d).executeScript(
                        "   window.mssCount="+counter+";\r\n" + 
                        "   window.mssJSDelay=function mssJSDelay(){\r\n" + 
                        "       if((typeof jQuery != 'undefined') && (jQuery.active !== 0 || $(\":animated\").length !== 0))\r\n" + 
                        "           window.mssCount="+counter+";\r\n" + 
                        "       window.mssCount-->0 &&\r\n" + 
                        "       setTimeout(window.mssJSDelay,window.mssCount+1);\r\n" + 
                        "   }\r\n" + 
                        "   window.mssJSDelay();");
                resetCount=false;
            }

            boolean ready=false;
            try{
                ready=-1==((Long) ((JavascriptExecutor) d).executeScript(
                        "if(typeof window.mssJSDelay!=\"function\"){\r\n" + 
                        "   window.mssCount="+counter+";\r\n" + 
                        "   window.mssJSDelay=function mssJSDelay(){\r\n" + 
                        "       if((typeof jQuery != 'undefined') && (jQuery.active !== 0 || $(\":animated\").length !== 0))\r\n" + 
                        "           window.mssCount="+counter+";\r\n" + 
                        "       window.mssCount-->0 &&\r\n" + 
                        "       setTimeout(window.mssJSDelay,window.mssCount+1);\r\n" + 
                        "   }\r\n" + 
                        "   window.mssJSDelay();\r\n" + 
                        "}\r\n" + 
                        "return window.mssCount;"));
            }
            catch (NoSuchWindowException a){
                a.printStackTrace();
                return true;
            }
            catch (Exception e) {
                e.printStackTrace();
                return false;
            }
            return ready;
        }
        @Override
        public String toString() {
            return String.format("Timeout waiting for documentNotActive script");
        }
    };
}

0

ไม่รู้ว่าจะทำอย่างไร แต่ในกรณีของฉันการสิ้นสุดการโหลดหน้าและการแสดงผลตรงกับ FAVICON ที่แสดงในแท็บ Firefox

ดังนั้นหากเราสามารถรับภาพไอคอน Fav ในเว็บเบราว์เซอร์ได้แสดงว่าหน้าเว็บนั้นเต็มแล้ว

แต่วิธีนี้ ....



-1

นี่คือวิธีการ:

new WebDriverWait(driver, 20).until(
       ExpectedConditions.jsReturnsValue(
                   "return document.readyState === 'complete' ? true : false"));

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

-1

ฉันชอบแนวคิดของคุณในการสำรวจ HTML จนกว่าจะมีเสถียรภาพ ฉันอาจเพิ่มสิ่งนั้นลงในโซลูชันของฉันเอง แนวทางต่อไปนี้อยู่ใน C # และต้องใช้ jQuery

ฉันเป็นผู้พัฒนาโครงการทดสอบ SuccessFactors (SaaS) ซึ่งเราไม่มีอิทธิพลเหนือนักพัฒนาหรือลักษณะของ DOM หลังหน้าเว็บ ผลิตภัณฑ์ SaaS สามารถเปลี่ยนการออกแบบ DOM ที่เป็นพื้นฐานได้ 4 ครั้งต่อปีดังนั้นการล่าจึงดำเนินต่อไปอย่างถาวรสำหรับวิธีทดสอบที่มีประสิทธิภาพและมีประสิทธิภาพในการทดสอบกับซีลีเนียม (รวมถึงการไม่ทดสอบกับซีลีเนียมในกรณีที่เป็นไปได้!)

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

  • Driver คืออินสแตนซ์ WebDriver ที่สื่อสารกับเบราว์เซอร์
  • DefaultPageLoadTimeout คือค่าการหมดเวลาในเห็บ (100ns ต่อขีด)

public IWebDriver Driver { get; private set; }

// ...

const int GlobalPageLoadTimeOutSecs = 10;
static readonly TimeSpan DefaultPageLoadTimeout =
    new TimeSpan((long) (10_000_000 * GlobalPageLoadTimeOutSecs));
Driver = new FirefoxDriver();

ในสิ่งต่อไปนี้ให้สังเกตลำดับของการรอในวิธีการPageReady(เอกสารซีลีเนียมพร้อม Ajax ภาพเคลื่อนไหว) ซึ่งสมเหตุสมผลถ้าคุณคิดเกี่ยวกับเรื่องนี้:

  1. โหลดหน้าที่มีรหัส
  2. ใช้รหัสเพื่อโหลดข้อมูลจากที่ใดที่หนึ่งผ่าน Ajax
  3. นำเสนอข้อมูลอาจเป็นภาพเคลื่อนไหว

บางอย่างเช่นวิธีการเปรียบเทียบ DOM ของคุณสามารถใช้ระหว่าง 1 ถึง 2 เพื่อเพิ่มความแข็งแกร่งอีกชั้นหนึ่ง


public void PageReady()
{
    DocumentReady();
    AjaxReady();
    AnimationsReady();
}


private void DocumentReady()
{
    WaitForJavascript(script: "return document.readyState", result: "complete");
}

private void WaitForJavascript(string script, string result)
{
    new WebDriverWait(Driver, DefaultPageLoadTimeout).Until(
        d => ((IJavaScriptExecutor) d).ExecuteScript(script).Equals(result));
}

private void AjaxReady()
{
    WaitForJavascript(script: "return jQuery.active.toString()", result: "0");
}

private void AnimationsReady()
{
    WaitForJavascript(script: "return $(\"animated\").length.toString()", result: "0");
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.