Behat Selenium - 等待滑入的元素

时间:2015-04-13 15:13:53

标签: php selenium behat mink

我在Behat等待元素“滑入”时遇到了麻烦。

在我们的管理面板菜单中,每个主要项目向下滑动以显示子菜单,如下所示:

enter image description here

为了清晰起见,我添加了红线以显示菜单,并为子菜单添加了绿色。

问题是,这个菜单“滑入”。这是一个可爱的效果,但它破坏了我的测试。 :)

我正在尝试使用spin function让Behat等到子菜单可见后再尝试点击它。

代码:

/**
 * @When I wait for :cssSelector
 * @param $cssSelector
 * @throws \Exception
 */
public function iWaitFor($cssSelector)
{
    $this->spin(function($context) use ($cssSelector) {
        /** @var $context FeatureContext */
        return !is_null($context->getSession()->getPage()->find('css', $cssSelector));
    });
}

/**
 * @When I wait for :text to appear
 * @Then I should see :text appear
 * @param $text
 * @throws \Exception
 */
public function iWaitForTextToAppear($text)
{
    $this->spin(function($context) use ($text) {
        /** @var $context FeatureContext */
        return $context->getSession()->getPage()->hasContent($text);
    });
}

/**
 * @When I wait for :text to disappear
 * @Then I should see :text disappear
 * @param $text
 * @throws \Exception
 */
public function iWaitForTextToDisappear($text)
{
    $this->spin(function($context) use ($text) {
        /** @var $context FeatureContext */
        return !$context->getSession()->getPage()->hasContent($text);
    });
}

/**
 * Based on Behat's own example
 * @see http://docs.behat.org/en/v2.5/cookbook/using_spin_functions.html#adding-a-timeout
 * @param $lambda
 * @param int $wait
 * @throws \Exception
 */
public function spin($lambda, $wait = 60)
{
    $time = time();
    $stopTime = $time + $wait;
    while (time() < $stopTime)
    {
        try {
            if ($lambda($this)) {
                return;
            }
        } catch (\Exception $e) {
            // do nothing
        }

        usleep(250000);
    }

    throw new \Exception("Spin function timed out after {$wait} seconds");
}

该功能的片段:

@javascript
Scenario Outline: Create a new piece of artwork
  Given I am logged in to the CMS as "adminUser"
  Then I should see "Artwork"
  When I follow "Artwork"
  Then I should see "Pieces" appear
  When I follow "Pieces"
  Then I should see "Manage Artwork Pieces"

然而,虽然这在我的Vagrant开发环境中运行得非常好,但是当Jenkins在确认已经出现“Pieces”后尝试follow "Pieces"时,它会中断。两者都在无头linux的XVFB中使用Firefox运行Selenium。

这些是我目前正在使用的版本:

╔═════════════╦══════════════╦════════════╗
║ Environment ║ Development  ║ Testing    ║
╠═════════════╬══════════════╬════════════╣
║ Linux       ║ Ubuntu 14.04 ║ CentOS 6.6 ║
║ PHP         ║ 5.5.9        ║ 5.4.38     ║
║ Behat       ║ 3.0.x-dev    ║ 3.0.x-dev  ║
║ Selenium    ║ 2.45.0       ║ 2.45.0     ║
║ XVFB        ║ 1.15.1       ║ 1.15.0     ║
║ Firefox     ║ 36.0.4       ║ 31.5.0     ║
╚═════════════╩══════════════╩════════════╝

我将尝试确保Firefox和Selenium都尽可能最新,以确定是否能解决问题,但这一直是一个持续存在的问题,所以我不相信。

附录

我错过了一个实际错误消息的示例:

When I follow "Carousel" # tests/Behat/Cms/Features/1.1.Carousel.feature:11
  Offset within element cannot be scrolled into view: (110, 17): http://www.###.co.uk/admin/fp/carousel
  Build info: version: '2.44.0', revision: '76d78cf', time: '2014-10-23 20:02:37'

这是在Then I should see "Carousel" appear

之后

此外,错误几乎是随机发生的。我需要一种简单的方法来确保测试不会继续,直到页面处于允许它继续的状态。我想要避免任何类似“等待”或任何依赖于JavaScript或Selenium的东西(如果我切换到另一个驱动程序)。

更新:将测试机上的Selenium更新为2.45.0,仍然遇到同样的问题。修正了Dev Environment上面的PHP版本,有5.4,实际上是5.5.9。

1 个答案:

答案 0 :(得分:3)

我相信我已经解决了这个问题,但我不能完全确定原因,所以如果我错了,请纠正我。

猜测检查页面内容将始终返回true,无论它是否可见。相反,我转而使用Mink提供的断言,这些断言是为每个驱动程序独立实现的。在这种情况下,我们要求Selenium考虑该元素是否存在。

我最初避免使用断言,因为它们会抛出异常,但是,因为异常是特定且可知的,我们可以利用它来为我们带来优势。

这是新代码。

/**
 * @When I wait for :text to appear
 * @Then I should see :text appear
 * @param $text
 * @throws \Exception
 */
public function iWaitForTextToAppear($text)
{
    $this->spin(function(FeatureContext $context) use ($text) {
        try {
            $context->assertPageContainsText($text);
            return true;
        }
        catch(ResponseTextException $e) {
            // NOOP
        }
        return false;
    });
}

/**
 * @When I wait for :text to disappear
 * @Then I should see :text disappear
 * @param $text
 * @throws \Exception
 */
public function iWaitForTextToDisappear($text)
{
    $this->spin(function(FeatureContext $context) use ($text) {
        try {
            $context->assertPageContainsText($text);
        }
        catch(ResponseTextException $e) {
            return true;
        }
        return false;
    });
}

我自从运行测试套件两次以来,每次检查的变体大约发生了100次,他们都回来了。如果有人想提交更好的答案/解释,我现在暂时保留这个问题。