Ed Hinchliffe Ed Hinchliffe - 3 months ago 21
AngularJS Question

Testing the contents of a temporary element with protractor

I'm trying to test the login page on my site using protractor.

If you log in incorrectly, the site displays a "toast" message that pops up for 5 seconds, then disappears (using


I'm using the following test:

describe('[login]', ()->
it('should show a toast with an error if the password is wrong', ()->

username = element(select.model("user.username"))
password = element(select.model("user.password"))
loginButton = $('button[type=\'submit\']')
toast = $('.toaster')

# Verify that the toast isn't visible yet

# Verify that toast appears and contains an error
toastMessage = $('.toast-message')
expect(toastMessage.getText()).toBe("Invalid password")

The relevant markup (jade) is below:

.toast-message(ng-repeat="message in messages") {{message.body}}

The problem is the
test is failing (it can't find the element). It seems to be waiting for the toast to disappear and then running the test.

I've also tried putting the
test outside the
callback (I think this is pretty much redundant anyway), but I get the exact same behaviour.

My best guess is that protractor sees that there's a
running, and waits for it to finish before running the next test (ref protractor control flow). How would I get around this and make sure the test runs during the timeout?


Following the suggestion below, I used
to wait for the toast to be visible, then tried to run the test when the promise resolved. It didn't work.

console.log "clicking button"

browser.wait((()-> toast.isDisplayed()),20000, "never visible").then(()->
console.log "looking for message"
toastMessage = $('.toaster')
expect(toastMessage.getText()).toBe("Invalid password")

The console.log statements let me see what's going on. This is the series of events, the
are what I see happening in the browser.

clicking button
[toast appears]
[5 sec pass]
[toast disappears]
looking for message
[test fails]

For added clarity on what is going on with the toaster: I have a service which essentially holds an array of messages. The toast directive is always on the page (template is the jade above), and watches the messages in the toast service. If there is a new message, it runs the following code:

# set a timeout to remove it afterwards.

This pushes the message into the messages array on the scope for 5 seconds, which is what makes the toast appear (via

Why is protractor waiting for the toast's
to expire before moving on to the tests?


It turns out that this is known behaviour for protractor. I think it should be a bug, but at the moment the issue is closed.

The workaround is to use $interval instead of $timeout, setting the third argument to 1 so it only gets called once.