【问题标题】:How does Selenium WebDriver's isDisplayed() method workSelenium WebDriver 的 isDisplayed() 方法是如何工作的
【发布时间】:2013-08-06 09:48:25
【问题描述】:

我目前有很多情况需要验证页面(及其所有元素)是否正确显示。 WebElement 的isDisplayed() 方法似乎是执行此操作的合乎逻辑的方法,但是我想准确了解此方法在确定是否“显示”元素时所做的工作。 javadoc 没有说明该方法的内部工作原理,并且网络上的其他信息充其量似乎是稀疏的。

如果有人能详细说明此方法的工作原理,我将不胜感激。

【问题讨论】:

标签: selenium webdriver selenium-webdriver


【解决方案1】:

WebDriver 有自己的W3C specification

关于determining visibility 的部分是你所追求的。

我会警告说,“显示”是一个如此广泛的术语,因此它有很多场景。因此,很可能存在 WebDriver 不考虑的情况。

因此,重要的是,事实上,至关重要,要记住“显示”或“可见”的东西有许多含义。 (同理一个页面被完全加载,也有很多含义。)

还要记住 Selenium 是 entirely open source. 没有什么可以阻止您重新签出存储库并在本地检查它。

【讨论】:

  • 因此,例如,依靠 isDisplayed() 方法来告诉我表格的行是否正在显示不是一个理想的测试方法?抓取表格并循环浏览行并检查值是否符合预期会更好吗?
  • Depends -> 您是否要验证它们是否显示而不管内容如何?验证内容可能是更好的解决方法。我并不是说使用isDisplayed 是一件坏事,只是有很多关于“这个元素对用户可见”的定义。到目前为止,它对我很有帮助,但我看到它绊倒了几个人。
  • 我将尝试确保所有重要元素都显示在不同的浏览器中。所以目前我并不担心内容——当我开始自动化功能测试时就会出现。
【解决方案2】:

我相信 Selenium 可以确定一个元素是否显示。如果它不起作用,您可以提出错误和/或修复您看到的任何问题并提供补丁。

这就是方法的作用(取自当前的Selenium source code):

/**
 * Determines whether an element is what a user would call "shown". This means
 * that the element is shown in the viewport of the browser, and only has
 * height and width greater than 0px, and that its visibility is not "hidden"
 * and its display property is not "none".
 * Options and Optgroup elements are treated as special cases: they are
 * considered shown iff they have a enclosing select element that is shown.
 *
 * @param {!Element} elem The element to consider.
 * @param {boolean=} opt_ignoreOpacity Whether to ignore the element's opacity
 *     when determining whether it is shown; defaults to false.
 * @return {boolean} Whether or not the element is visible.
 */
bot.dom.isShown = function(elem, opt_ignoreOpacity) {
  if (!bot.dom.isElement(elem)) {
    throw new Error('Argument to isShown must be of type Element');
  }

  // Option or optgroup is shown iff enclosing select is shown (ignoring the
  // select's opacity).
  if (bot.dom.isElement(elem, goog.dom.TagName.OPTION) ||
      bot.dom.isElement(elem, goog.dom.TagName.OPTGROUP)) {
    var select = /**@type {Element}*/ (goog.dom.getAncestor(elem, function(e) {
      return bot.dom.isElement(e, goog.dom.TagName.SELECT);
    }));
    return !!select && bot.dom.isShown(select, /*ignoreOpacity=*/true);
  }

  // Image map elements are shown if image that uses it is shown, and
  // the area of the element is positive.
  var imageMap = bot.dom.maybeFindImageMap_(elem);
  if (imageMap) {
    return !!imageMap.image &&
           imageMap.rect.width > 0 && imageMap.rect.height > 0 &&
           bot.dom.isShown(imageMap.image, opt_ignoreOpacity);
  }

  // Any hidden input is not shown.
  if (bot.dom.isElement(elem, goog.dom.TagName.INPUT) &&
      elem.type.toLowerCase() == 'hidden') {
    return false;
  }

  // Any NOSCRIPT element is not shown.
  if (bot.dom.isElement(elem, goog.dom.TagName.NOSCRIPT)) {
    return false;
  }

  // Any element with hidden visibility is not shown.
  if (bot.dom.getEffectiveStyle(elem, 'visibility') == 'hidden') {
    return false;
  }

  // Any element with a display style equal to 'none' or that has an ancestor
  // with display style equal to 'none' is not shown.
  function displayed(e) {
    if (bot.dom.getEffectiveStyle(e, 'display') == 'none') {
      return false;
    }
    var parent = bot.dom.getParentElement(e);
    return !parent || displayed(parent);
  }
  if (!displayed(elem)) {
    return false;
  }

  // Any transparent element is not shown.
  if (!opt_ignoreOpacity && bot.dom.getOpacity(elem) == 0) {
    return false;
  }

  // Any element with the hidden attribute or has an ancestor with the hidden
  // attribute is not shown
  function isHidden(e) {
    //IE does not support hidden attribute yet
    if (goog.userAgent.IE) {
      return true;
    }
    if (e.hasAttribute) {
      if (e.hasAttribute('hidden')){
        return false;
      }
    } else {
      return true;
    }
    var parent = bot.dom.getParentElement(e);
    return !parent || isHidden(parent);
  }

  if (!isHidden(elem)) {
    return false;
  }

  // Any element without positive size dimensions is not shown.
  function positiveSize(e) {
    var rect = bot.dom.getClientRect(e);
    if (rect.height > 0 && rect.width > 0) {
      return true;
    }
    // A vertical or horizontal SVG Path element will report zero width or
    // height but is "shown" if it has a positive stroke-width.
    if (bot.dom.isElement(e, 'PATH') && (rect.height > 0 || rect.width > 0)) {
      var strokeWidth = bot.dom.getEffectiveStyle(e, 'stroke-width');
      return !!strokeWidth && (parseInt(strokeWidth, 10) > 0);
    }
    // Zero-sized elements should still be considered to have positive size
    // if they have a child element or text node with positive size, unless
    // the element has an 'overflow' style of 'hidden'.
    return bot.dom.getEffectiveStyle(e, 'overflow') != 'hidden' &&
        goog.array.some(e.childNodes, function(n) {
          return n.nodeType == goog.dom.NodeType.TEXT ||
                 (bot.dom.isElement(n) && positiveSize(n));
        });
  }
  if (!positiveSize(elem)) {
    return false;
  }

  // Elements that are hidden by overflow are not shown.
  if (bot.dom.getOverflowState(elem) == bot.dom.OverflowState.HIDDEN) {
    return false;
  }

不确定它是否真的需要更多解释,cmets 很清楚。如果您想添加更多信息,请告诉我。

【讨论】:

  • 那么您认为将它用于多大的规模是明智的?例如,要确保显示表格,您是否只需检查表格 WebElement?还是遍历各个行,在每一行上调用 isDisplayed?或者只是确保包含它的
    是Displayed?
  • 这取决于您正在测试的页面是如何实现的。一般来说,我不希望表格中的特定单元格或行消失,所以我只会检查表格是否可见。但是,如果您希望表格隐藏特定的行/单元格,我可能会检查每一个。了解您正在测试的应用程序将告诉您哪种方法是正确的。
【解决方案3】:

根据documentationisDisplayed()方法判断WebElement是否显示并返回一个boolean元素是否显示。这种方法避免了必须解析元素的style 属性的问题。

此实现符合 WebDriver Level 2 W3C Working Draft 中的规范,其中提到:

虽然 WebDriver 没有定义一个原语来确定 的可见性 elementviewport, 我们承认它对许多用户来说是一项重要功能。在这里,我们 包括一个推荐的方法,这将简化 元素可见性的近似值,但请注意它 仅依赖于树遍历,并且仅涵盖可见性的子集 检查。

元素的可见性取决于感知可见的内容 到人眼。在这种情况下,元素的显示性并不 涉及到 visibilitydisplay风格 属性。

建议实现者确定元素的方法 可见性最初是由 Selenium 项目开发的,并且是 基于对元素性质的粗略近似和 树中的关系。通常要考虑一个元素 如果它的任何部分在边界内的画布上绘制,则可见 视口。

元素显示算法是一个布尔状态,其中true 表示该元素已显示,false 表示该元素 元素不显示。要计算元素的状态,请调用 Call(bot.dom.isShown, null, element)。如果这样做不会产生 错误,返回此函数调用的返回值。否则 返回错误代码未知错误。

这个函数通常暴露给GET请求,其URI模板为:

/session/{session id}/element/{element id}/displayed

【讨论】:

    猜你喜欢
    相关资源
    最近更新 更多
    热门标签