Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using Ember (cli) how do I get an acceptance test to wait for a promise?

In my Ember app, I currently have a model that has a findResults function that returns a promise that is wrapping a Google Places library to fetch results for auto-completion. To use this in my UI, I setup a PromiseMixin controller. I instruct the controller to watch the searchText value, and when that changes I update the controller's promise value to be the promise returned by the findResults function, but with the new value from searchText. This works nicely when I'm playing with the app in the browser, however when I run my acceptance tests the test seems to finish before the promise is returned and therefore the tests fail. I'll include the relevant files below.

I'm not sure how to tell Ember to wait for the promise to resolve during testing.

app/services/google-autocomplete-location.js

import Ember from "ember";

var googleAutocompleteLocation = Ember.Object.extend({
  placeId: null,
  description: null
});

googleAutocompleteLocation.reopenClass({
  findResults: function(query) {
    var self = this;
    var promise = new Ember.RSVP.Promise(function(resolve, reject) {
      var autocompleteService = new google.maps.places.AutocompleteService();

      return autocompleteService.getPlacePredictions({ input: query },
        function(predictions, status) {
          if (status !== google.maps.places.PlacesServiceStatus.OK) {
            Ember.run(null, reject, status);
          }
          else {
            Ember.run(null, resolve, self._decorateGoogleResults(predictions));
          }
        });
    });

    return promise;
  },

  _decorateGoogleResults: function(predictions) {
    var locations = [];

    predictions.forEach(function(prediction) {
      locations.push(
        googleAutocompleteLocation.create({
          placeId: prediction.place_id,
          description: prediction.description
        })
      );
    });


    return locations;
   }
});

export default googleAutocompleteLocation;

app/controllers/index.js

import Ember from "ember";
import GoogleLocation from "../services/google-location";
import GoogleAutocompleteLocation from '../services/google-autocomplete-location';

export default Ember.ArrayController.extend(Ember.PromiseProxyMixin, {
  searchText: '',
  map: null,
  mapUrl: null,

  actions: {
    submit: function() {
      return this.transitionToRoute('entries.new');
    }
  },

  highlightedResult: function() {
    if (this.get('model').length) {
      return this.get('model')[0];
    } else {
      return null;
    }
  }.property('model'),

  setMap: (function() {
    if (this.get('highlightedResult') === null) {
      return this.set('map', null);
    } else {
      if (this.get('map') === null) {
        return this.set('map', GoogleLocation.create({
          mapContainer: Ember.$('.maps-info'),
          placeId: this.get('highlightedResult').placeId
        }));
      } else {
        return this.get('map').set('placeId', this.get('highlightedResult').placeId);
      }
    }
  }).observes('highlightedResult'),

  searchTextChanged: (function() {
    if (this.get('searchText').length) {
      this.set('promise',
        GoogleAutocompleteLocation.findResults(this.get('searchText')));
      console.log(this.get('promise'));
    } else {
      this.set('model', []);
    }
  }).observes('searchText')
});

tests/acceptance/create-new-entry-test.js

test('finding a location', function() {
  expect(1);
  visit('/');
  click('.location-input input');
  fillIn('.location-input input', "Los Angeles, CA");

  andThen(function() {
    var searchResult = find('.search-results ul li:first a').text();

    equal(searchResult, 'Los Angeles, CA, United States');
  });
});
like image 317
jklina Avatar asked Oct 22 '14 01:10

jklina


People also ask

How do you pause a test in Ember?

Visit http://localhost:4200/tests in your browser. When the execution of the test come upon await pauseTest() , the test will be paused, allowing you to inspect the state of your application. You can now type resumeTest() in the console of your browser to continue the test execution.

How do I run ember acceptance tests?

Ember CLI comes with acceptance test support out of the box. For creating your first test, you just need to run ember generate acceptance-test <name> . In our case, ember generate acceptance-test user-can-login-via-form . Ember CLI will create a new test file under tests/acceptance/ .


1 Answers

The best way to go about this is likely to register your own async test helper. I've prepared a JSBin with a simulation of your code and a solution here: http://jsbin.com/ziceratana/3/edit?html,js,output

The code used to create the helper is this:

Ember.Test.registerAsyncHelper('waitForControllerWithPromise', function(app, controllerName) {
  return new Ember.Test.promise(function(resolve) {

    // inform the test framework that there is an async operation in progress,
    // so it shouldn't consider the test complete
    Ember.Test.adapter.asyncStart();

    // get a handle to the promise we want to wait on
    var controller = app.__container__.lookup('controller:' + controllerName);
    var promise = controller.get('promise');

    promise.then(function(){

      // wait until the afterRender queue to resolve this promise,
      // to give any side effects of the promise resolving a chance to
      // occur and settle
      Ember.run.schedule('afterRender', null, resolve);

      // inform the test framework that this async operation is complete
      Ember.Test.adapter.asyncEnd();
    });
  });
});

And it would be used like so:

test('visiting / and searching', function() {
  expect(1);
  visit('/');
  click('.location-input input');
  fillIn('.location-input input', "Los Angeles, CA");
  waitForControllerWithPromise('index'); // <-- simple & elegant!
  andThen(function(){
    var searchResult = find('.search-results ul li:first').text();
    equal(searchResult, 'Los Angeles, CA, United States');
  });
});

In ember-testing, an async-helper will automatically wait on previous promises and subsequent async helpers will wait on it when the test is executed. For excellent background on this, see Cory Forsyth's Demystifying Async Testing

like image 110
Luke Melia Avatar answered Oct 06 '22 00:10

Luke Melia