如何让 behat 等待一个元素显示在屏幕上再填充它?
How to make behat wait for an element to be displayed on the screen before filling it?
当我单击一个按钮时,会打开一个新页面,其中包含一个表单,我需要在该页面上填写一个字段。
但是,一旦页面开始加载,behat 就会尝试填充尚未加载的字段。
我想隐式等待以等待显示该字段,然后再尝试填充它。
/**
* @Given que preencho corretamente os campos da tela
*/
public function quePreenchoCorretamenteOsCamposDaTela()
{
$faker = Faker\Factory::create();
$this->getPage()->findField('voucher_subject')->setValue($faker->text);
$this->getPage()->findField('voucher_nameRecipient')->setValue($faker->name);
}
有人能帮帮我吗?
如果您使用的驱动程序只模拟浏览器(如 BrowserKit 或 Goutte),只有当 DOM 正确组合并准备就绪时,behat 才会收回控制权(当然没有 js 可以解释或执行)。如果您使用类似 Selenium2 的东西并且该字段是从异步调用构建的(如果我理解正确,这就是您的情况),则由您来确保页面被完整加载。那是因为请求有响应,控制权传回Behat进程。
此问题的一种可能解决方案是在每个 ajax/async 调用之前将 class 附加到主体,并在每次调用完成后立即将其删除。然后,在你的 behat 上下文中创建一个 "spinner" 函数来检查 class 是否消失。
您可以使用旋转功能:
trait FeatureContextHelper
{
public function spin (callable $lambda, $wait = 5)
{
$lastErrorMessage = '';
for ($i = 0; $i < $wait; $i++) {
try {
if ($lambda($this)) {
return true;
}
} catch (Exception $e) {
// do nothing
$lastErrorMessage = $e->getMessage();
}
sleep(1);
}
throw new ElementNotVisible('The element is not visible ' . $lastErrorMessage);
}
}
那么在你的上下文中:
class FeatureContext extends MinkContext
{
use FeatureContextHelper;
/**
* @Given que preencho corretamente os campos da tela
*/
public function quePreenchoCorretamenteOsCamposDaTela()
{
$this->spin(function ($context) {
$faker = Faker\Factory::create();
$context->getSession()->getPage()->findField('voucher_subject')->setValue($faker->text);
$context->getSession()->getPage()->findField('voucher_nameRecipient')->setValue($faker->name);
return true;
}
}
}
它将尝试在 5 秒内找到元素,如果找不到则超时。它非常适合我们使用 Selenium2 和 Goutte。
从我的角度来看,现在可以做得更优雅:
$page = $this->getSession()->getPage();
$page->waitFor(5000,
function () use ($page) {
return $page->findField('voucher_subject')->isVisible();
}
);
您也可以将其包装在一些 private
函数中。
当我单击一个按钮时,会打开一个新页面,其中包含一个表单,我需要在该页面上填写一个字段。
但是,一旦页面开始加载,behat 就会尝试填充尚未加载的字段。
我想隐式等待以等待显示该字段,然后再尝试填充它。
/**
* @Given que preencho corretamente os campos da tela
*/
public function quePreenchoCorretamenteOsCamposDaTela()
{
$faker = Faker\Factory::create();
$this->getPage()->findField('voucher_subject')->setValue($faker->text);
$this->getPage()->findField('voucher_nameRecipient')->setValue($faker->name);
}
有人能帮帮我吗?
如果您使用的驱动程序只模拟浏览器(如 BrowserKit 或 Goutte),只有当 DOM 正确组合并准备就绪时,behat 才会收回控制权(当然没有 js 可以解释或执行)。如果您使用类似 Selenium2 的东西并且该字段是从异步调用构建的(如果我理解正确,这就是您的情况),则由您来确保页面被完整加载。那是因为请求有响应,控制权传回Behat进程。
此问题的一种可能解决方案是在每个 ajax/async 调用之前将 class 附加到主体,并在每次调用完成后立即将其删除。然后,在你的 behat 上下文中创建一个 "spinner" 函数来检查 class 是否消失。
您可以使用旋转功能:
trait FeatureContextHelper
{
public function spin (callable $lambda, $wait = 5)
{
$lastErrorMessage = '';
for ($i = 0; $i < $wait; $i++) {
try {
if ($lambda($this)) {
return true;
}
} catch (Exception $e) {
// do nothing
$lastErrorMessage = $e->getMessage();
}
sleep(1);
}
throw new ElementNotVisible('The element is not visible ' . $lastErrorMessage);
}
}
那么在你的上下文中:
class FeatureContext extends MinkContext
{
use FeatureContextHelper;
/**
* @Given que preencho corretamente os campos da tela
*/
public function quePreenchoCorretamenteOsCamposDaTela()
{
$this->spin(function ($context) {
$faker = Faker\Factory::create();
$context->getSession()->getPage()->findField('voucher_subject')->setValue($faker->text);
$context->getSession()->getPage()->findField('voucher_nameRecipient')->setValue($faker->name);
return true;
}
}
}
它将尝试在 5 秒内找到元素,如果找不到则超时。它非常适合我们使用 Selenium2 和 Goutte。
从我的角度来看,现在可以做得更优雅:
$page = $this->getSession()->getPage();
$page->waitFor(5000,
function () use ($page) {
return $page->findField('voucher_subject')->isVisible();
}
);
您也可以将其包装在一些 private
函数中。