[java] سيلديري WebDriver: انتظر صفحة معقدة مع جافا سكريبت (JS) لتحميل


Answers

شكرا اشوين!

في حالتي يجب أن أكون في انتظار تنفيذ تنفيذ ملحق jquery في بعض العناصر .. على وجه التحديد "qtip"

على أساس التلميح الخاص بك ، فقد عملت بشكل مثالي بالنسبة لي:

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

ملاحظة: أستخدم Webdriver 2

Question

لدي تطبيق على شبكة الإنترنت لاختبار مع السيلينيوم. هناك الكثير من جافا سكريبت قيد التشغيل عند تحميل الصفحة.
شفرة جافا سكريبت ليست مكتوبة بشكل جيد ولكن لا يمكنني تغيير أي شيء. لذا فإن انتظار ظهور عنصر ما في DOM باستخدام طريقة findElement() ليس خيارًا.
أريد إنشاء وظيفة عامة في جافا للانتظار حتى يتم تحميل صفحة ، يكون الحل المحتمل:

  • قم بتشغيل نموذج سكريبت JavaScript WebDriver وتخزين نتيجة document.body.innerHTML في نص متغير السلسلة.
  • مقارنة متغير body مع الإصدار السابق من body . إذا كانت هي نفسها ثم قم بتعيين زيادة عداد notChangedCount غير ذلك تعيين notChangedCount إلى صفر.
  • انتظر وقت litte (50 مللي ثانية على سبيل المثال).
  • إذا لم تتغير الصفحة لبعض الوقت (500 مللي ثانية على سبيل المثال) لذلك notChangedCount > = 10 ثم الخروج من حلقة أخرى حلقة إلى الخطوة الأولى.

هل تعتقد أنه حل صحيح؟




هل تقوم مكتبة JS بتعريف / تهيئة أي متغير معروف على النافذة؟

إذا كان الأمر كذلك ، فيمكنك الانتظار حتى يظهر المتغير. يمكنك استخدام

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

لاختبار هذا الشرط (شيء مثل: window.SomeClass && window.SomeClass.variable != null ) وإرجاع منطقية true / false .

التفاف هذا في WebDriverWait وانتظر حتى يعود البرنامج النصي true .




كان لدي نفس المشكلة. يعمل هذا الحل بالنسبة لي من 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




للقيام بذلك بشكل صحيح ، تحتاج إلى التعامل مع الاستثناءات.

هنا كيف أفعل الانتظار ل 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") ) );
    }
....

ملاحظة: يمكنك رؤية مثال عملي بالكامل هنا .




هنا من رمز بلدي:
وينفذ Window.setTimeout فقط عندما يكون المتصفح في وضع الخمول.
لذلك ، فإن استدعاء الوظيفة بشكل متكرر (42 مرة) سيأخذ 100 مللي ثانية إذا لم يكن هناك أي نشاط في المستعرض وأكثر من ذلك بكثير إذا كان المتصفح مشغولًا بعمل شيء آخر.

    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 calls أو إذا تم تشغيل أي رسوم متحركة 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");
        }
    };
}



بالنسبة 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);
});



Links