Как заставить behat подождать, пока элемент отобразится на экране, прежде чем заполнять его?


Когда я нажимаю на кнопку, открывается новая страница с формой, и мне нужно заполнить поле на этой странице.

Однако, как только страница начинает загружаться, 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);
   }

Кто-нибудь может мне помочь?

Author: Luiza Guerra, 2017-10-13

3 answers

Вы можете использовать функцию вращения:

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 и подагрой.

 1
Author: zstate, 2017-11-01 21:03:39

С моей точки зрения, теперь это можно сделать более элегантно:

$page = $this->getSession()->getPage();

$page->waitFor(5000,
    function () use ($page) {
        return $page->findField('voucher_subject')->isVisible();
    }
);

Вы также можете обернуть это внутри некоторой функции private.

 1
Author: freeek, 2018-03-05 18:42:19

Если вы используете драйвер, который только имитирует браузер (например, BrowserKit или Goutte), behat вернет управление только тогда, когда DOM будет правильно составлен и готов (и, конечно, никакой js не может быть интерпретирован или выполнен). Если вы используете что-то вроде Selenium2, и поле построено из асинхронного вызова (если я правильно понимаю, это ваш случай), вы должны быть уверены, что страница загружена полностью. Это потому, что на запрос есть ответ, и управление передается обратно вести себя как процесс.
Одним из возможных решений этой проблемы является добавление класса в тело непосредственно перед каждым вызовом ajax/async и удаление его сразу после завершения каждого вызова. Затем создайте функцию "spinner" в контексте вашего поведения, чтобы проверить, исчез ли класс.

 0
Author: DonCallisto, 2017-10-17 07:08:20