Преминаване към JavascriptExecutor, когато Selenium2 findElement се провали?

Имам тази идея за отказ на JavascriptExecutor, ако Selenium2 не успее да извлече обект WebElement след запитване за ограничен период от време. Както можете да видите, методът има ограничението да се нуждае от предварително дефиниране на Javascript фрагмента за „отказ“ при извикване на getElementByLocator. Не можах да измисля никакъв начин да направя това динамично. Ако някой може да ми помогне да подобря това, ще наградя отговора на най-доброто предложение, колкото и малко да е то.

// failover example1: "document.getElementById('gbqfb')"
// failover example2: "document.querySelector("div#gbqfb")"
public static WebElement getElementByLocator(final By locator, String failover) {
  Wait<WebDriver> wait = new FluentWait<WebDriver>(driver)
    .withTimeout(30, TimeUnit.SECONDS)
    .pollingEvery(5, TimeUnit.SECONDS);
    .ignoring(NoSuchElementException.class,StaleElementReferenceException.class);
  WebElement we = wait.until( ExpectedConditions
      .presenceOfElementLocated( locator ) );
  if ( we.isNull() ) {
    JavascriptExecutor js = (JavascriptExecutor) driver;
    if ( !failover.isEmpty() ) {
      we = (WebElement)js.executeScript( failover );
      if ( we.isNull() ) LOG.info("Still couldn't get element.");
    } else {
      LOG.info("No failover String available.  Cannot try with " +
        "a JavascriptExecutor.");
    }    
  }
  return we;
}

person djangofan    schedule 10.10.2013    source източник


Отговори (1)


Всъщност отговорих на подобен въпрос тук

Не бих препоръчал делегиране на нищо на javascript по този начин.. Използвайте това, което ви дава Selenium.. това е много достатъчно.

Нещо, което поставям във всяка една рамка, която някога съм създавал, което е МНОГО ефективно.. Ето извадка от рамката, намерена тук.

Внедрявам нещо като метод от тип псевдо-изчакване, преди да извърша каквито и да е действия върху обекти. Опитайте сами. Много е ефективен.

Това са методи от AutomationTest клас

/**
 * Checks if the element is present or not.<br>
 * @param by
 * @return <i>this method is not meant to be used fluently.</i><br><br.
 * Returns <code>true</code> if the element is present. and <code>false</code> if it's not.
 */
public boolean isPresent(By by) {
    if (driver.findElements(by).size() > 0) return true;
    return false;
}

/**
 * Private method that acts as an arbiter of implicit timeouts of sorts.. sort of like a Wait For Ajax method.
 */
private WebElement waitForElement(By by) {
    int attempts = 0;
    int size = driver.findElements(by).size();

    while (size == 0) {
        size = driver.findElements(by).size();
        if (attempts == MAX_ATTEMPTS) fail(String.format("Could not find %s after %d seconds",
                                                         by.toString(),
                                                         MAX_ATTEMPTS));
        attempts++;
        try {
            Thread.sleep(1000); // sleep for 1 second.
        } catch (Exception x) {
            fail("Failed due to an exception during Thread.sleep!");
            x.printStackTrace();
        }
    }

    if (size > 0) System.err.println("WARN: There are more than 1 " + by.toString() + " 's!");

    return driver.findElement(by);
}

Това, което правя, е всеки път, когато изпълнявам нещо, като

getText(By.cssSelector("input#someId"))

ако не го намери от първия път, ще изчака 1 секунда. ако го намери тогава, продължава. прави това впоследствие 5 пъти, така че общо 5 секунди изчакване.. което е напълно добре, защото ако НЕ намерите елемента, от който се нуждаете, тогава вашият тест трябва ефективно да се провали в този момент.

Освен това от опит мога да ви кажа, че използването на driver.findElements() е по-ефективно от тези WebDriverWait.

Това не означава, че не ги използвам.. просто не за това. За съжаление, не бях добавил тази функционалност към началната работа със селеновата рамка, така че просто ще ви кажа кога използвах Webdriverwait's.

Така че моят тест ще изглежда така -

@Config(url="http://systemunder.test", browser=CHROME)
public class MyClass extends AutomationTest {

    @Test
    public void testSomething() {
        setText(By.id("blah")) // if <* id="blah" /> doesn't exist, waits 1+ seconds for it to appear before interacting.
        .click(By.id("Blah2")) // ^ same thing here.
        .waitForPresent(By.cssSelector("ajaxy")); // this method right here would circumvent the hard waits, with webdriverwait's.
    }
}

не помня точно защо не работеше за мен преди, но използването на webdriverwaits в нещо подобно е безупречно.

person ddavison    schedule 10.10.2013
comment
Оценявам дългия отговор и много подробната информация. Целта на въпроса ми е да уловя редките крайни случаи, които според моя опит се случват понякога след надграждане от една версия на Selenium2 към друга, където понякога елемент вече не може да бъде извлечен от обикновения скрипт и аз се опитвам да избегна малки редакции на код в тези случаи, които изискват JavascriptExecutor за достъп до него. Следователно, опитвайки се да измисля работещ метод за преодоляване при срив. Както виждате от моя код, в 99% от случаите той не извиква JavascriptExecutor. Сривът е само за крайния случай. - person djangofan; 10.10.2013
comment
Никога в моите дни като тестов инженер не съм се сблъсквал с такъв тип проблем, който да не е бил отстранен с помощта на това, което предоставих по-горе. Казвате, че елементът вече не може да се извлече от обикновения скрипт.. какво означава това? предоставяте селектор за избор на обекта и сте готови. - person ddavison; 10.10.2013
comment
Е, казвам, че обичайният ми код работи повече от 99% от времето и използвам методи, подобни на вашите, но може би малко по-модерни (тъй като използвам неща като FluentWait, ExpectedConditions, LoadableComponent и т.н.), но също така казвам, че според моя опит .findElement() доста често не е 100% напълно надежден. Искам да измисля нещо, което мога да кажа, че е стабилно. Когато пишете рамка, това е целта за потребителите на вашата рамка. Освен това няма причина да мислим, че .findElement ще бъде 100%, защото зареждането на DOM не е 100%, нито е моментално... - person djangofan; 10.10.2013
comment
Е, предполагам, че изглежда сме стигнали до задънена улица :) Никога не съм преживявал момент, в който findElement() не е работил и когато тези методи не са работили, дори с ajax, който отнема няколко секунди за зареждане. - person ddavison; 10.10.2013
comment
Добре, чувам те. Следващият път, когато видя проблема, ще тествам теорията ви. - person djangofan; 10.10.2013