samedi 17 septembre 2016

Timeout on angular service test using $q and angular-extended-promises

I'm testing an angular service using angular extended promises as one of its dependencies. It looks like this:

angular.module('main')
    .service('MyService', ['_', '$q', 'DatabaseService', 
    function(_, $q, DatabaseService) {

      function loadResources(resources) {
          var resources = _.mapValues(resources, function(config, type) {
           return DatabaseService.getByType(type)
              .then(function(data) {
                  return index(type, data);
              });
          });
          return $q.props(resources);
      });

      var service = {
            loadResources: loadResources
      };

      return service;
    }
  ])
;

I want to make a test for the loadResources function and for this I stub DatabaseService.getByType function. I'm using mocha, chai, sinon running on karma. My test looks like this:

describe('[Service] MyService', function() {
    var MyService, DatabaseService, $q;
    var databaseBrand = [...]; // My fixtures

    beforeEach(function() {
        module('myApp');

        inject(function($injector) {
            MyService = $injector.get('MyService');
            DatabaseService = $injector.get('DatabaseService');
            $q = $injector.get('$q');

            sinon.stub(DatabaseService, 'getByType', function(type) {
                var typeResources = databaseBrand.filter(function(resource) {
                    return resource.type === type;
                });
                return $q.resolve(typeResources);
            });
        });
    });

    afterEach(function() {
        DatabaseService.getByType.restore();
    });

    it('loadResources method', function() {
        var configTest = { resources: [...] }; // input test data

        var promise = MyService.loadResources(configTest);
        return promise.should.be.fulfilled
            .then(function(brandResources) {
                console.log('PROMISE RESOLVED');
                expect(brandResources).to.be.an('object');
                // Other expects
            })
        ;
    });
});

When I run the test I have this timeout:

PhantomJS 2.1.1 (Mac OS X 0.0.0) [Service] MyService loadResources method FAILED
    timeout of 2000ms exceeded. Ensure the done() callback is being called in this test.

I have already seen some post when people suggest to use the .$apply() or $digest() of the rootScope to "force" the promise to be resolved. But the thing is that I'm a testing a service and I want to isolated it to test without any other wired behavior.

I have made modifications to recover the $rootScope during the beforeEach and to force the $digest within the afterEach and the log that I added in my test is shown (what is cool) but then I have some errors, attemping to request some resources that are not included in my scenario...

PhantomJS 2.1.1 (Mac OS X 0.0.0) [Service] MyService "after each" hook for "loadResources method" FAILED Unexpected request: GET /api/config No more request expected $httpBackend@bower_components/angular-mocks/angular-mocks.js:1211:90 sendReq@bower_components/angular/angular.js:10333:21 serverRequest@bower_components/angular/angular.js:10045:23 [native code] processQueue@bower_components/angular/angular.js:14567:30 bower_components/angular/angular.js:14583:39 $eval@bower_components/angular/angular.js:15846:28 $digest@bower_components/angular/angular.js:15657:36 $apply@bower_components/angular/angular.js:15951:31

Is there any way to avoid to use this $digest or $apply ? Why do I have to do this to allow $q.prop to resolve the promise if I'm within a service and not a controller ?

Thanks

Aucun commentaire:

Enregistrer un commentaire