3

I'm using AngularJS and ES6, So I want to write a unit test for the ES6 (not using angular.mock ...) this is how I tried to test it. but the problem is it('resolves its promise with the current data' it fails with the

Error: Timeout - Async callback was not invoked within timeout specified by jasmine.DEFAULT_TIMEOUT_INTERVAL.

I removed the done() based on this but the test always passes, doesn't matter toEqual what!. maybe the response variable doesn't set correctly.

Does someone have any idea!?

data.service.js

    export class DataService {
     'ngInject';
      constructor($log, $http) {
        this.$log = $log;
        this.$http = $http;
      }
      getData(url, name) {
        return this.$http.get(url)
          .then((response) => {
            return {data: response.data, version: response.version)};
          })
          .catch((error) => {
            this.$log.error('Failed for getData.\n' + angular.toJson(error.data, true));
            throw error.data || {};
          });
       }
    }

data.service-spec.js

import {DataService} from './data.service';

let sysUnderTest, mapSelectionServiceMock, http;

describe('http.get', () => {
  let temperaturePromise;
  let promiseHelper;
  let getDataPromise;

  beforeEach(() => {
    let fetchPromise = new Promise((resolve, reject) => {
      promiseHelper = {
        resolve: resolve,
        reject: reject
      };
    });

    // http mock
    http = {
      get: () => {}
    };
    spyOn(http, 'get').and.returnValue(fetchPromise);
    sysUnderTest = new DataService(null, http, null, null, null);
    getDataPromise = sysUnderTest.getData('sampleURL');
  });

  it('getData', () => {
    expect(http.get).toHaveBeenCalled();
    expect(getDataPromise).toEqual(jasmine.any(Promise));
  });

  describe('on successful get', function() {
    beforeEach(function() {
      let response = new Response(JSON.stringify({
        data: 78,
        version: 1
      }));
      promiseHelper.resolve(response);
    });

    it('resolves its promise with the current data', function(done) {
        getDataPromise.then(function(data) {
          expect(data).toEqual(79987);
          done();
        });
    });
  });
});
GeoCom
  • 1,290
  • 2
  • 12
  • 33
  • The idea is that you shouldn't mix Angular $q promises with ES6 promises, unless you know what you're doing very well. You can't rely on [the answer](https://stackoverflow.com/a/25273095/5134285) you've cited because of that. $q promise is synchronous. ES6 promise is not. This test tests something that never happens in real service. I've checked the code and still not sure what could go wrong here - but it could. You don't `catch` in a test, while you should. What's `Response`? If it's https://developer.mozilla.org/en-US/docs/Web/API/Response, it won't work as you expect. – Estus Flask Oct 24 '17 at 19:17
  • @estus, thanks, yeah it is kind of complicated, the question is I am not sure if it is a correct unit test. In this case what could be the correct and probably good way to test the `getData` method from the `DataService` class. How should I test the `.then` and `.catch`. `response`can be a json object. as you see `data=80` and `version=1` as an example – GeoCom Oct 24 '17 at 21:51
  • 1
    I'd suggest to not reinvent the wheel and stick to ngMock and $q promises for unit tests, they are very straightforward and efficient. You should add `catch` to `getDataPromise.then` because if the test fails, it should call `done.fail` and not result in test timeout, like it possibly is in your case. Again, the origin of `Response` is unknown, and it may cause an error. – Estus Flask Oct 24 '17 at 22:05
  • the problem is the project is already there, and not allow for refactoring and using $q. therefore I must use the es6 promises in unit test. but without changing the code and using the ngMock and $q => this is my next question for how to do it? – GeoCom Oct 24 '17 at 22:18
  • The code you've posted (data.service.js and $http) uses $q promises, so the problem appears. Obviously, it's preferable to stick to $q in tests to test $q promises, and Promise for testing native promises, because those two aren't interchangeable. Even though the test may pass at some point, it doesn't test real code - it may stay green at some point while the app stops working as expected. – Estus Flask Oct 24 '17 at 22:21
  • OK, now I got where is(could be) the problem, thanks. Is it possible for you to provide a sample test for the `data.service.js` with $q. I never use it before in test. – GeoCom Oct 24 '17 at 22:25
  • 1
    I'm out of time and can't offer workable example for now, and this one is supposed to be quite extensive here. I'd suggest to check https://docs.angularjs.org/guide/unit-testing first. I would suggest to test DataService service instead of DataService class because it will test DI as well. And $http requests are supposed to be mocked with https://docs.angularjs.org/api/ngMock/service/$httpBackend in ngMock. Check also also https://github.com/bvaughn/jasmine-promise-matchers for $q promise assertions. – Estus Flask Oct 24 '17 at 22:34

0 Answers0