Test Bootstrap Modal Open - setTimeout - async

I have a controller that has an action that triggers opening a bootstrap modal. I want to write a unit test that ensures that the modal has indeed opened upon triggering the action by checking if the modal’s html has the “in” class. That class is not added until after the css transition has completed. How do I handle the async nature of this test? I’ve looked through ember-cli testing docs, qunit docs(don’t work, none of the functions are available), and stack overflow.

test('loginClick() opens modal', function(){
	var controller = this.subject();
	controller.send('loginClick', 'anything');

	setTimeout(function(){
		equal($('#login-modal').hasClass('in'), true, "has the 'in' class");
	}, 500);
});

Questions like these belong on stack overflow.

See “Async Example” at GitHub - rwjblue/ember-qunit: QUnit test helpers for Ember - you need to create and return a promise, and resolve or reject the promise in your setTimeout.

Emberjs discussion forum seems like a great place to discuss emberjs issues. Thanks for the link though it still didn’t help.

Well, as stated in the sticky at the top http://discuss.emberjs.com/t/welcome-to-the-ember-js-discussion-forum/185:

Practical, answerable questions should be posted on StackOverflow and tagged with ember.js. This venue is for discussion about topics that might not have a clear answer.

This forum is more for discussion of the higher level concepts such as design and best practices, whereas your question has a pretty clear answer - SO is full of such questions and answers.

Can you please post your latest attempt at solving it on SO?

Although @Leeft is right, this specific question is better for SO, I’m presenting a guide to handling CSS transitions in tests that I think other users of this forum will find helpful.

You can handle this one of two ways:

  1. Account for asynchrony of CSS transitions in your tests. First understand that the andThen async helper is only useful when ember is aware of the asynchronous event. By default, it waits on router transitions, AJAX requests, and any timers created through Ember.run.*, you can see this here. Ember handles these async operations out of the box because they are super common and straightforward to implement. CSS transitions are neither of these things. To make the Ember testing helpers aware of your CSS transitions, you have a few options:

  2. Use a setTimeout like @Leeft suggested, with the transition delay hard coded. You’ll want to use Ember.run.later however, since test helpers are already aware of timers and will block if one has not finished.

  3. Create an async test helper (e.g. openModal) that returns a promise that is resolved by using either the transitionEnd event or a native setTimeout. See RSVP.Promise for more info on creating promises.

  4. Register a custom waiter that blocks all async test helpers passively. This typically entails some kind of global (closure) lock that is flipped when the async event has completed, in your case when the transitionEnd event is fired. This approach is a bit more complicated, but allows you to completely ignore the transition when writing tests.

  5. Disable CSS transitions completely when running tests. You can do this with bootstrap easily: $.support.transition = false;, see here.

The first option may seem like the ‘purer’ approach, since it’s testing exactly what the user will see, but in practice it’s rare you’ll want to do this, since every test that opens a modal takes at least the full amount of time the transition takes. You could conceivably adjust bootstrap’s transition duration timeouts when testing, but in my opinion it’s not worth it. I used to use bootstrap’s modal in a large app, and I disabled transitions completely in tests.

2 Likes

Point well taken. I suppose this has a best practices answer.

I’ve still had no luck with solutions. Here is the stack overflow I created for it:

AsyncHelper has not worked to me with Em 1.10, I need to use registerWaiter instead. Could anybody confirm that asyncHelpers are supported for this purpose?

@ccarterc another possible solution `waitUntil` async helper feedback