首页 > 解决方案 > 如何在 Behat/Mink 中处理比赛条件

问题描述

因此,我在 Behat/Mink 中进行了以下非常简单的测试。按下按钮时,会显示一个元素,然后我会用一些文本填充该元素。有时此测试有效,有时则无效。这是基本结构:

file.blade.php

<button id="show-inputs">Show</button>
<div id="inputs" class="hidden">
  <span>Input</span>
  <input type="text" id="test-input"/>
</div>

script.js

jQuery(function($){
  $('#show-inputs').on('click', function() {
    $('#inputs').removeClass('hidden');
  });
});

TestingFeature.feature

@javascript
Scenario: Testing Input Show/Fill
  Given I am on "/"
  Then I press "show-inputs"
  And I wait for javascript to finish loading
  Then I fill in "test-input" with "This is a Test"
  ...

FeatureContext.php

public function iWaitForJavascriptToFinishLoading() {
  $this->getSession()->wait(10000, '$.active === 0');
}

如您所见,这是一个简单的测试;导航到后/,触发点击#show-inputs,等待JS完成(即给时间显示#inputsdiv),然后填写#test-input一个简单的测试。

运行这些测试,有时它可以工作,有时它不会。这是输出behat

...
Then I press "show-inputs"                        # FeatureContext::pressButton()
And I wait for javascript to finish loading       # FeatureContext::iWaitForJavascriptToFinishLoading()
Then I fill in "test-input" with "This is a Test" # FeatureContext::fillField()
  Element is not visible and can not be focused

该错误Element is not visible and can not be focused有时只出现,表明 Show Element > Fill Element 上的竞争条件,以不正确的顺序发生。我认为And I wait for javascript to finish loading, 等待直到$.activeis0会处理这个问题,但显然它没有。我想知道它是否与使用类hidden( display:none) 与简单有关$('{$selector}').show(),但我不确定。

我可以添加一个新的检查,类似于And I wait for "inputs" to be "visible",它一直等到$('{$selector}').is(':visible') === true,但这感觉不对。

有没有人遇到过这个问题?

标签: javascriptphprace-conditionbehatmink

解决方案


我最终采用了我认为我必须使用的方式,使用And I wait for "test-input" to be "visible"自定义定义FeatureContext.php

/**
 * @Then I wait for :elementId to be :visibility
 */
public function iWaitForElementToBe($elementId, $visibility) {
  if ($visibility != 'visible' && $visibility != 'hidden') {
    throw new Exception("Invalid visibility pseudo `{$visibility}` supplied: Must be one of `visible`, `hidden`");
  }
  $this->getSession()->wait(1000, "\$('#{$elementId}').is(':{$visibility}') === true");
}

然后在TestingFeature.feature:

@javascript
Scenario: Testing Input Show/Fill
  Given I am on "/"
  Then I press "show-inputs"
  And I wait for "test-input" to be "visible"
  Then I fill in "test-input" with "This is a Test"

唯一需要注意的是,如果同时显示多个元素,则And I wait for ... to be ...需要对每个元素重复,即使它们在同一行代码中切换为可见/隐藏(例如$('#id, #id2').removeClass('hidden'))。


推荐阅读