Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Protractor: Am I overusing promise.then()

I'm working on an end-to-end test using Protractor. The part of the application I'm working on first uses ng-switch statements to show/hide questions in the registration process, one at a time. There's an animation between questions that gave me the hardest time. For example, attempting to load the page->go to next question->assert that an element exists was tough, among other things. The script would load the page, click the next button, then make the assert before the next slide was on screen.

What's worse is that for about half of a second between questions, both the old question and the new one existed on the DOM. The best non-sleep wait mechanism I could come up with was to do a browser.wait() that first waited for there to be two questions on the DOM, then chain another browser.wait() that waited for there to be only one question on the DOM again and then proceed from there. (this entire operation is wrapped into registerPage.waitForTransition() in the code)

The browser.wait()s were not always blocking long enough, so I ended up writing code that looks like this:

it('moves to previous question after clicking previous link', function() {
    var title;

    // Get the current slide title, then click previous, wait for transition,
    // then check the title again to make sure it changed

    registerPage.slideTitle.getText()
        .then(function(text) {
            title = text;
        })
        .then(registerPage.prevLink.click())
        .then(registerPage.waitForTransition())
        .then(function() {
            expect(registerPage.slideTitle.getText()).not.toBe(title);
        });
});

in order to ensure that each wait was properly completed before executing the next command. Now this works perfectly. What was happening before was that the tests would succeed 95% of the time, but would occasionally fire off the asserts or the next click action, etc. before the transition was actually 100% complete. That doesn't happen anymore, but I feel like this is almost OVERusing .then() on promises. But at the same time, it makes sense to force everything to occur sequentially since that's how interacting with a site actually works. Load the page, then wait for the next button to slide in, then make a selection, then click the next button, then wait for the next slide, etc.

Am I doing this in a completely bad-practice style or is this acceptable use of promises when using Protractor on an app with heavy animations?

like image 286
Richard Pressler Avatar asked Oct 18 '22 14:10

Richard Pressler


1 Answers

I like these kind of code-review-like questions, so thanks for posting.

I do think some of your .thens are unnecessary. The .click() and expect shouldn't need them, as they should be added to the controlFlow for you. The expect should also handle the promise for your getText().

The problem you're having would seem to be within your waitForTransition() method, operating outside the controlFlow. Depending on how you're handling the waits within this method, you may need to add it to the controlFlow yourself. Eg. are you calling non-webdriver commands? I've also had good luck with using Expected Conditions isClickable() in cases like these.

Additionally, I would also offload much of this code to your page object, especially when waiting is required. For example, if you add something like this to your page object:

registerPage:

this.getSlideTitleText = function() {
    return this.slideTitle.getText().then(function(text) {
        return text;
    });
};

this.clickPrevLink = function() {
    this.prevLink.click();
    return this.waitForTransition(); // fix this and the rest should work
};

then your test could be...

it('moves to previous question after clicking previous link', function() {
    var title = registerPage.getSlideTitleText();
    registerPage.clickPrevLink();

    expect(registerPage.getSlideTitleText()).not.toBe(title);
});
like image 159
Brine Avatar answered Oct 21 '22 06:10

Brine