web-dev-qa-db-ja.com

要素がWebDriverで表示されるかどうかを確認する方法

Selenium 2.0a2のWebDriverを使用すると、要素が表示されているかどうかを確認できません。

WebDriver.findElementWebElementを返しますが、残念ながらisVisibleメソッドは提供していません。 WebElement.clearまたはWebElement.clickを使用してこれを回避できますが、どちらもElementNotVisibleExceptionをスローしますが、これは非常に汚い感じがします。

より良いアイデアはありますか?

62
ponzao

element instanceof RenderedWebElementは動作するはずです。

20
hleinone

私は質問に答えるのが少し遅れていますが:

WebElement.isDisplayed() を使用して、要素が表示されているかどうかを確認できるようになりました。

要素が不可視になる理由はたくさんあります。 Seleniumはそれらのほとんどをカバーしようとしますが、期待どおりに動作しないEdgeのケースがあります。

たとえば、isDisplayed()doesは、要素にdisplay: noneまたはopacity: 0が含まれる場合にfalseを返しますが、少なくともmyテストでは、CSSの配置のために要素が別の要素で覆われているかどうかを確実に検出しません。

131
sleske

次の2つの提案方法があります。

  1. 次のようにisDisplayed()を使用できます。

    driver.findElement(By.id("idOfElement")).isDisplayed();
    
  2. 以下に示すようにメソッドを定義して呼び出すことができます:

    public boolean isElementPresent(By by) {
      try {
        driver.findElement(by);
        return true;
      }
    catch (org.openqa.Selenium.NoSuchElementException e) {
        return false;
      }
    }
    

これで、以下のようにアサーションを実行して、要素が存在するかどうかを確認できます。

assertTrue(isElementPresent(By.id("idOfElement")));
15
Ripon Al Wasim

C#を使用している場合は、driver.Displayedになります。私自身のプロジェクトの例を次に示します。

if (!driver.FindElement(By.Name("newtagfield")).Displayed)      //if the tag options is not displayed
    driver.FindElement(By.Id("expand-folder-tags")).Click();    //make sure the folder and tags options are visible
7

短い答え:#visibilityOfElementLocatedを使用してください

isDisplayedなどを使用した答えはどれも正しくありません。彼らはdisplayプロパティがnoneではないかどうかをチェックするだけで、要素が実際に見えるかどうかはチェックしません! Seleniumには、多数の静的ユーティリティメソッドが ExpectedConditions クラスに追加されていました。この場合、そのうちの2つを使用できます。

使用法

@Test
// visibilityOfElementLocated has been statically imported
public demo(){
    By searchButtonSelector = By.className("search_button");
    WebDriverWait wait = new WebDriverWait(driver, 10);
    driver.get(homeUrl);

    WebElement searchButton = wait.until(                
            visibilityOfElementLocated
            (searchButtonSelector)); 

    //clicks the search button 
    searchButton.click();

クライアントで実行されているカスタムの可視性チェック

ExpectedConditionsのユーティリティメソッドについて知る前に、これが私の答えでした。私はそれが上記の方法よりも多くのことを行うと思うので、それはまだ関連しているかもしれません。要素は高さと幅を持っていることだけをチェックします。

本質的に、これはJavaおよびfindElementBy*メソッドとWebElement#isDisplayedだけでは答えることができません。これらは要素が存在するかどうかしかわからないためです、実際に可視である場合ではありません。 OPはvisibleの意味を定義していませんが、通常は

  • opacity> 0があります
  • displayプロパティがnone以外に設定されている
  • visibility propはvisibleに設定されます
  • それを隠す他の要素はありません(最上位の要素です)

ほとんどの人は、それが実際にビューポート内にあるという要件も含みます(したがって、人はそれを見ることができます)。

何らかの理由で、この非常に通常の必要性は純粋なJava AP​​Iで満たされていませんが、その上に構築されるSeleniumのフロントエンドはしばしばisVisibleのバリエーションを実装します。そして、NodeフレームワークWebDriver.IOのソースを参照した後、 ソースisVisibleが見つかりました。 5.0ベータでのisVisibleInViewportのより適切な名前。

基本的に、クライアントで実行されるjavascriptに委任する呼び出しとしてカスタムコマンドを実装し、実際の作業を行います!これは「サーバー」ビットです。

export default function isDisplayedInViewport () {
    return getBrowserObject(this).execute(isDisplayedInViewportScript, {
        [ELEMENT_KEY]: this.elementId, // w3c compatible
        ELEMENT: this.elementId // jsonwp compatible
    })
}

興味深いのは、クライアントで実行するために送信されるJavaScriptです。

/**
 * check if element is visible and within the viewport
 * @param  {HTMLElement} elem  element to check
 * @return {Boolean}           true if element is within viewport
 */
export default function isDisplayedInViewport (elem) {
    const dde = document.documentElement

    let isWithinViewport = true
    while (elem.parentNode && elem.parentNode.getBoundingClientRect) {
        const elemDimension = elem.getBoundingClientRect()
        const elemComputedStyle = window.getComputedStyle(elem)
        const viewportDimension = {
            width: dde.clientWidth,
            height: dde.clientHeight
        }

        isWithinViewport = isWithinViewport &&
                           (elemComputedStyle.display !== 'none' &&
                            elemComputedStyle.visibility === 'visible' &&
                            parseFloat(elemComputedStyle.opacity, 10) > 0 &&
                            elemDimension.bottom > 0 &&
                            elemDimension.right > 0 &&
                            elemDimension.top < viewportDimension.height &&
                            elemDimension.left < viewportDimension.width)

        elem = elem.parentNode
    }

    return isWithinViewport
}

このJSの部分は、実際に(ほとんど)そのままの形で独自のコードベースにコピーできます(export defaultを削除し、非常緑ブラウザの場合はconstvarに置き換えます)。それを使用するには、Fileからクライアントで実行するためにSeleniumが送信できるStringに読み取ります。

検討する価値があるもう1つの興味深い関連スクリプトは、 selectByVisibleText です。

Seleniumを使用してJSを実行したことがない場合は、 これを少し覗いてみてください または JavaScriptExecutor API を参照できます。

通常、常に非ブロッキング非同期スクリプト( #executeAsyncScript を意味する)を使用するようにしてください。ただし、既に同期のブロッキングスクリプトがあるため、通常の同期呼び出しを使用することもできます。返されるオブジェクトは、多くのタイプのオブジェクトになる可能性があるため、適切にキャストしてください。これはそれを行う1つの方法です。

/** 
 * Demo of a Java version of webdriverio's isDisplayedInViewport
 * https://github.com/webdriverio/webdriverio/blob/v5.0.0-beta.2/packages/webdriverio/src/commands/element/isDisplayedInViewport.js
 * The super class GuiTest just deals with setup of the driver and such
 */
class VisibleDemoTest extends GuiTest {
    public static String readScript(String name) {
        try {
            File f = new File("Selenium-scripts/" + name + ".js");
            BufferedReader reader = new BufferedReader( new FileReader( file ) );
            return reader.lines().collect(Collectors.joining(System.lineSeparator()));
        } catch(IOError e){
            throw new RuntimeError("No such Selenium script: " + f.getAbsolutePath()); 
        }
    }

    public static Boolean isVisibleInViewport(RemoteElement e){
        // according to the Webdriver spec a string that identifies an element
        // should be deserialized into the corresponding web element,
        // meaning the 'isDisplayedInViewport' function should receive the element, 
        // not just the string we passed to it originally - how this is done is not our concern
        //
        // This is probably when ELEMENT and ELEMENT_KEY refers to in the wd.io implementation
        //
        // Ref https://w3c.github.io/webdriver/#dfn-json-deserialize
        return js.executeScript(readScript("isDisplayedInViewport"), e.getId());
    }

    public static Boolean isVisibleInViewport(String xPath){
        driver().findElementByXPath("//button[@id='should_be_visible']");
    }

    @Test
    public demo_isVisibleInViewport(){
        // you can build all kinds of abstractions on top of the base method
        // to make it more Selenium-ish using retries with timeouts, etc
        assertTrue(isVisibleInViewport("//button[@id='should_be_visible']"));
        assertFalse(isVisibleInViewport("//button[@id='should_be_hidden']"));
    }
}
4
oligofren

Driver.FindElementはHTMLソースのみをチェックするため、要素が表示されているかどうかを確認することが重要です。ただし、ポップアップコードはページhtmlにあり、表示されない可能性があります。したがって、Driver.FindElement関数はfalse positiveを返します(テストは失敗します)

2
Jason

Eleが表示されていることを確認します。

public static boolean isElementVisible(final By by)
    throws InterruptedException {
        boolean value = false;

        if (driver.findElements(by).size() > 0) {
            value = true;
        }
        return value;
    }
1
Adnan Ghaffar