javascript ember.js

javascript - Usando Ember(cli) ¿cómo obtengo una prueba de aceptación para esperar una promesa?



ember.js (4)

En mi aplicación Ember, actualmente tengo un modelo que tiene una función findResults que devuelve una promesa que está envolviendo una biblioteca de Google Places para obtener resultados para la finalización automática. Para usar esto en mi UI, configuro un controlador PromiseMixin. searchText al controlador para que mire el valor de searchText , y cuando eso cambia, actualizo el valor prometedor del controlador para que sea la promesa devuelta por la función findResults , pero con el nuevo valor de searchText . Esto funciona bien cuando juego con la aplicación en el navegador, sin embargo, cuando ejecuto mis pruebas de aceptación, la prueba parece finalizar antes de que se devuelva la promesa y, por lo tanto, las pruebas fallan. Incluiré los archivos relevantes a continuación.

No estoy seguro de cómo decirle a Ember que espere a que se cumpla la promesa durante la prueba.

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''); }); });


No puedo reproducir su problema en JSBin pero ha intentado stop() y start() . En tu caso:

test(''finding a location'', function() { expect(1); stop(); visit(''/'') .click(''.location-input input'') .fillIn(''.location-input input'', "Los Angeles, CA") .then(function() { var searchResult = find(''.search-results ul li:first a'').text(); equal(searchResult, ''Los Angeles, CA, United States''); start(); }); });


Soy nuevo en esto y he tenido dificultades similares hoy. Lo encontré andThen luego solo esperaré las promesas creadas con las promesas de prueba de Ember,

var promise = Ember.Test.promise(function (resolve, reject) {...});

y no aquellos donde la promesa es instanciada directamente, es decir,

var promise = new Ember.RSVP.Promise(function (resolve, reject) {...});

Ember.Test.promise devuelve un new Ember.RSVP.Promise , pero también realiza el paso de establecer Ember.Test.lastPromise en la instancia de promesa antes de devolverlo. Tal vez la respuesta aquí es para que establezcas Ember.Test.lastPromise en la promesa que estás esperando.

Por cierto, también tuve que usar stop() y start() en mi caso para evitar que la prueba saliera antes de que se llamara la segunda afirmación. También necesité ajustar la segunda run.next en una llamada run.next para dar a las propiedades / DOM la oportunidad de actualizar:

test(''shows content when unresolved promise resolves true'', function() { expect(2); var resolveTestPromise; var testPromise = Ember.Test.promise(function (resolve) { resolveTestPromise = resolve; }); // creates the component instance, stubbing the security service and template properties var component = this.subject({ securityService: CreateMockSecurityService(testPromise), template: Ember.Handlebars.compile(''<div id="if-may-test-div" />'') }); // appends the component to the page var $component = this.append(); // our div shouldn''t be visible yet equal($component.find(''div#if-may-test-div'').length, 0); stop(); Ember.run.later(null, function () {resolveTestPromise(true);}, 1000); andThen(function () { Ember.run.next(function () { // div should be visible now equal($component.find(''div#if-may-test-div'').length, 1); start(); }); }); });

¡Espero que ayude!


La mejor manera de hacerlo es registrar tu propio asistente de prueba asíncrono. He preparado un JSBin con una simulación de tu código y una solución aquí: http://jsbin.com/ziceratana/3/edit?html,js,output

El código usado para crear el helper es este:

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(); }); }); });

Y se usaría así:

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''); }); });

En las pruebas de ascuas, un asincrónico de ayuda esperará automáticamente en las promesas anteriores y los asistentes de sincronización posteriores lo esperarán cuando se ejecute la prueba. Para obtener excelentes antecedentes sobre esto, vea Cory Forsyth''s Demystifying Async Testing


En caso de que espere una promesa que no se resolverá pero rechazará, aquí hay un parche para detectar el error y aún pasar el andThen prueba.

Ember.Test.registerAsyncHelper(''waitForControllerWithPromise'', function(app, controllerName) { return new Ember.Test.promise(function(resolve, reject) { // 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(); }).catch(function() { // when the promise is rejected, resolve it to pass in `andThen()` Ember.run.schedule(''afterRender'', null, resolve); Ember.Test.adapter.asyncEnd(); }); }); });