Выполнение обещаний в Protractor and Cucumber с помощью Chai as Promised

В последнее время у нас с коллегой возникли некоторые разногласия по поводу «правильного» способа реализации определений шагов Cucumber с использованием Protractor и Chai as Promised. Наше утверждение проистекает из взаимного непонимания того, что именно происходит с разрешением обещаний в контексте Cucumber.

Мы тестируем приложение AngularJS, поэтому выполнение обещаний и асинхронного поведения - неизбежное зло. Самая большая проблема, с которой мы столкнулись, - это заставить Cucumber ждать выполнения обещаний между определениями шагов. В некоторых случаях мы наблюдали такие ситуации, что Cucumber, кажется, просматривает определения шагов прямо до того, как Webdriver даже выполнит их. Наши решения этой проблемы различаются ...

Рассмотрим гипотетический сценарий:

Scenario: When a user logs in, they should see search form
  Given a user exists in the system
  When the user logs into the application
  Then the search form should be displayed

Большая часть путаницы возникает на шаге Then. В этом примере определение должно утверждать, что все поля для формы поиска существуют на странице, что означает несколько проверок isPresent ().

Из документации и примеров, которые мне удалось найти, я почувствовал, что утверждение должно выглядеть примерно так:

this.Then(/the search form should be displayed/, function(next) {
    expect(element(by.model('searchTerms')).isPresent()).to.eventually.be.true;
    expect(element(by.model('optionsBox')).isPresent()).to.eventually.be.true;
    expect(element(by.button('Run Search')).isPresent()).to.eventually.be.true.and.notify(next);
});

Однако мой коллега утверждает, что для выполнения обещания вам нужно связать свои ожидания с then () следующим образом:

this.Then(/the search form should be displayed/, function(next) {
    element(by.model('searchTerms')).isPresent().then(function(result) {
        expect(result).to.be.true;

    }).then(function() {
        element(by.model('optionsBox')).isPresent().then(function(result) {
            expect(result).to.be.true;

        }).then(function() {
            element(by.button('Run Search')).isPresent().then(function(result) {
                expect(result).to.be.true;
                next;
            });
        });
    });
});

Последнее мне кажется неправильным, но я тоже не знаю, правильно ли первое. Насколько я понимаю, функция finally () заключается в том, что она работает аналогично then () в том смысле, что она ожидает разрешения обещания, прежде чем двигаться дальше. Я ожидал, что предыдущий пример будет ждать каждого вызова expect () по порядку, а затем вызывать next () через notify () в последнем expect (), чтобы сигнализировать огурцу о переходе к следующему шагу.

Чтобы добавить еще больше путаницы, я наблюдал, как другие коллеги пишут свои ожидания следующим образом:

expect(some_element).to.eventually.be.true.then(function() {
    expect(some_other_element).to.eventually.be.true.then(function() {
        expect(third_element).to.eventually.be.true.then(function() {
            next();
        });
    });
});

Я имею в виду следующие вопросы:

  • Правильно ли что-либо из вышеперечисленного вроде?
  • Что в конечном итоге () действительно делает? Принуждает ли он к синхронному поведению, как then ()?
  • Что на самом деле делает and.notify (next)? Отличается ли он от вызова next () внутри then ()?
  • Есть ли руководство по передовой практике, которое мы еще не нашли, чтобы прояснить что-либо из этого?

Спасибо заранее.


person Andrew Yochum    schedule 13.07.2015    source источник


Ответы (2)


  • Ваше мнение было правильным, ваш коллега ошибался (хотя это была разумная ошибка!). Protractor автоматически ожидает выполнения одной команды WebDriver перед запуском второй. Таким образом, во втором блоке кода element(by.button('Run Search')).isPresent() не разрешится, пока не будут выполнены и element(by.model('optionsBox')).isPresent(), и element(by.model('searchTerms')).isPresent().
  • eventually выполняет обещания. Объяснение здесь: https://stackoverflow.com/a/30790425/1432449
  • Я не верю, что это отличается от помещения next() в then()
  • Я не верю, что существует руководство по передовой практике. Огурец не является основным направлением работы команды Protractor, и его поддержка в значительной степени обеспечивается сообществом на github. Если вы или кто-то из ваших знакомых хотели бы написать руководство по передовой практике, мы (команда транспортиров) приветствуем PR!
person sjelin    schedule 13.07.2015
comment
Отлично, спасибо за разъяснения! Я согласен, основываясь на примерах и описаниях, объединение их в цепочку в приведенном выше примере кажется логичным. Мы новички в тестировании в Protractor, так что это новая территория для нас. Возможно, в будущем мы рассмотрим возможность написания руководства по передовой практике. :) - person Andrew Yochum; 14.07.2015

Что мне подходит, так это то, что приведенная ниже функция ищет что-то, что всегда будет равно true - в случае существования тега html. Я вызываю эту функцию в конце каждого теста, передавая обратный вызов

function callbackWhenDone(callback) {
    browser.wait(EC.presenceOf(element(by.css('html'))))
        .then(function () {callback();})
}

Это использование в простом тесте:

this.Given(/^I go on "([^"]*)"$/, function (arg1, callback) {
    browser.get('/' + arg1);
    callbackWhenDone(callback);
});

Я знаю, что это что-то вроде хака, но он выполняет свою работу и выглядит довольно чистым при использовании повсюду.

person Ryan Knell    schedule 16.08.2016