有人可以详细描述 Selenium WebDriver isDisplayed() 方法的工作原理吗?

软件测试 网络驱动程序
2022-01-23 20:00:41

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

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

2个回答

Spice 先生,欢迎来到 SQA。该算法有点复杂,我从未见过完整的书面解释。您需要考虑元素类型;hidden, visibility,display属性;不透明度;方面; 元素是否被溢出隐藏;应用坐标变换后元素的 (x,y) 位置;并且可能是祖先元素的部分/所有这些属性。

这是 Selenium源代码的摘录

/**
 * 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 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;
  }

  function isTransformHiding(e) {
    var transform = bot.dom.getEffectiveStyle(e, '-o-transform') ||
                    bot.dom.getEffectiveStyle(e, '-webkit-transform') ||
                    bot.dom.getEffectiveStyle(e, '-ms-transform') ||
                    bot.dom.getEffectiveStyle(e, '-moz-transform') ||
                    bot.dom.getEffectiveStyle(e, 'transform');

    // Not all browsers know what a transform is so if we have a returned value
    // lets carry on checking up the tree just in case. If we ask for the
    // transform matrix and look at the details there it will return the centre
    // of the element
    if (transform && transform !== "none") {
      var locOfElement = goog.style.getClientPosition(e);
      var rect = bot.dom.getClientRect(e);
      if ((locOfElement.x + (rect.width)) >= 0 &&
          (locOfElement.y + (rect.height)) >= 0){
        return true;
      } else {
        return false;
      }
    } else {
      var parent = bot.dom.getParentElement(e);
      return !parent || isTransformHiding(parent);
    }
  }
  return isTransformHiding(elem);
};

我使用 python 绑定,但下划线的行为应该是相同的。

功能上

  • 它会检查网络元素是否隐藏
  • 它可能会检查 webelement 的坐标是否在用户浏览器的可见范围内

代码

这是我为python找到的:

is_displayed()的代码执行 Command.IS_ELEMENT_DISPLAYED,它映射到 command.Command 类中的 isElementDisplayed

进一步看这里, isElementDisplayed 被执行。但这就是我碰壁的地方-它从哪个框架执行 isElementDisplayed() ?