Pregunta

Parece que promete no resuelva en pruebas de Angular/Jasmine a menos que fuerce un $scope.$digest().Esto es una tontería en mi opinión, pero está bien, lo tengo funcionando cuando corresponde (controladores).

La situación en la que me encuentro ahora es que tengo un servicio al que no le importan los alcances de la aplicación, todo lo que hace es devolver algunos datos del servidor, pero la promesa no parece resolverse.

app.service('myService', function($q) {
  return {
    getSomething: function() {
      var deferred = $q.defer();
      deferred.resolve('test');
      return deferred.promise;
    }
  }
});

describe('Method: getSomething', function() {
  // In this case the expect()s are never executed
  it('should get something', function(done) {
    var promise = myService.getSomething();

    promise.then(function(resp) {
      expect(resp).toBe('test');      
      expect(1).toEqual(2);
    });

    done();
  });

  // This throws an error because done() is never called.
  // Error: Timeout - Async callback was not invoked within timeout specified by jasmine.DEFAULT_TIMEOUT_INTERVAL.
  it('should get something', function(done) {
    var promise = myService.getSomething();

    promise.then(function(resp) {
      expect(resp).toBe('test');      
      expect(1).toEqual(2);
      done();
    });
  });
});

¿Cuál es la forma correcta de probar esta funcionalidad?

Editar:Solución como referencia.Aparentemente estás obligado a inyectar y digerir $rootScope incluso si el servicio no lo está utilizando.

  it('should get something', function($rootScope, done) {
    var promise = myService.getSomething();

    promise.then(function(resp) {
      expect(resp).toBe('test');      
    });

    $rootScope.$digest();
    done();
  }); 
¿Fue útil?

Solución

Necesitas inyectar $rootScope en tu prueba y disparador $digest en eso.

Otros consejos

siempre existe el $rootScope, úsalo

inject(function($rootScope){
myRootScope=$rootScope;
})
....

myRootScope.$digest();

Así que he estado luchando con esto toda la tarde.Después de leer esta publicación, yo también sentí que había algo mal en la respuesta; resulta que sí.Ninguna de las respuestas anteriores da una explicación clara de dónde y por qué utilizar $rootScope.$digest.Entonces, esto es lo que se me ocurrió.

En primer lugar ¿por qué?Necesitas usar $rootScope.$digest siempre que responda desde un evento no angular o una devolución de llamada.Esto incluiría eventos DOM puros, eventos jQuery y otras bibliotecas Promise de terceros distintas a $q que es parte de angular.

En segundo lugar ¿dónde?En su código, NO en su prueba.No es necesario inyectar $rootScope en su prueba, solo es necesario en su servicio angular real.Ahí es donde todo lo anterior no logra dejar claro cuál es la respuesta, muestran $rootScope.$digest como si fuera llamado de la prueba.

Espero que esto ayude a la próxima persona que venga hace mucho tiempo y tenga el mismo problema.

Actualizar


Eliminé esta publicación ayer cuando fue rechazada.Hoy seguí teniendo este problema al intentar utilizar las respuestas proporcionadas anteriormente.Entonces, dejo en espera mi respuesta a costa de puntos de reputación y, como tal, la voy a recuperar.

Esto es lo que necesita en los controladores de eventos que no son angulares y está usando $q e intentando realizar pruebas con Jasmine.

something.on('ready', function(err) {
    $rootScope.$apply(function(){deferred.resolve()});              
});

Tenga en cuenta que es posible que deba incluirse en un $timeout en algún caso.

something.on('ready', function(err) {
    $timeout(function(){
      $rootScope.$apply(function(){deferred.resolve()});    
    });     
});

Una nota más.En los ejemplos de problemas originales que estás llamando done En el momento equivocado.necesitas llamar done dentro de la then método (o el catch o finally), de la promesa, después de que se resuelva.Lo está llamando antes de que se resuelva la promesa, lo que está provocando que it cláusula de rescisión.

De la documentación angular.

https://docs.angularjs.org/api/ng/service/$ q

it('should simulate promise', inject(function($q, $rootScope) {
  var deferred = $q.defer();
  var promise = deferred.promise;
  var resolvedValue;

  promise.then(function(value) { resolvedValue = value; });
  expect(resolvedValue).toBeUndefined();

  // Simulate resolving of promise
  deferred.resolve(123);
  // Note that the 'then' function does not get called synchronously.
  // This is because we want the promise API to always be async, whether or not
  // it got called synchronously or asynchronously.
  expect(resolvedValue).toBeUndefined();

  // Propagate promise resolution to 'then' functions using $apply().
  $rootScope.$apply();
  expect(resolvedValue).toEqual(123);
}));
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top