0

I am trying to mock HTTP requests for AngularJS in Jest.

I have a service like this

public UserService(user) { 
    let url = this.env.getUserEndpoint("/users"); 
    let deferred = this.$q.defer<any>(); 

    this.$http.post<{ user: IUser }>(url,user).then( (result) => {
        deferred.resolve(result.data.user); 
    }, (error) => { 
        deferred.reject(this.httpErrorHandlingService.handleHttpError(error, "creating new user")); 
    }); 

    return deferred.promise;
}

Test:

beforeEach(angular.mock.module("test"));

var userService;

beforeEach(angular.mock.inject(function (UserService) {
    userService = UserService;
}));

it('should create new user', function () {
    const newUser = {
        name: "testUser",
        password: "12345"
    };

    return userService.createNewUser(newUser).then(user => expect(user.name).toEqual("testUser")
});

The error I get is Timeout - Async callback was not invoked within the 5000ms timeout specified by jest.setTimeout.Timeout

What am I doing wrong, and how can I mock AngularJS HTTP requests the easiest way?

2
  • Can you provide the relevant code in UserService please?
    – Bucket
    Commented May 7, 2020 at 17:37
  • Hello. This is the relevant code public UserService(user) { let url = this.env.getUserEndpoint("/users"); let deferred = this.$q.defer<any>(); this.$http.post<{ user: IUser }>(url,user).then( (result) => { deferred.resolve(result.data.user); }, (error) => { deferred.reject(this.httpErrorHandlingService.handleHttpError(error, "creating new user")); } ); return deferred.promise; }
    – Ilia Hanev
    Commented May 7, 2020 at 17:49

1 Answer 1

1

You don't need to create your own promise - $http.post() returns one for you. Then you can return the response data in your success and error function callbacks in your then method, and these will be handed to the promise returned by $http.post(). This should simplify your service code a bit:

public UserService(user) { 

    public createNewUser(user) {
        let url = this.env.getUserEndpoint("/users"); 

        return this.$http.post<{ user: IUser }>(url, user).then((result) => {
            return result.data.user; 
        }, (error) => { 
            this.httpErrorHandlingService.handleHttpError(error, "creating new user"); 
        });
    }
}
3
  • Is there a way to handle it with deferred.promise? I have over 400 methods returning it. Anyway I tried returning the promise and resolved value inside (like the comment) but I still get the callback error. We are using es5 if this helps.
    – Ilia Hanev
    Commented May 7, 2020 at 18:17
  • @IliaHanev you can keep it as is and it will work fine, but the extra promise is completely unnecessary, and only adds confusion to your code. Furthermore, if you're unit testing your code, making an AJAX requests is not recommended, as this is technically integration testing. For that you should mock your network calls, and unit test those separately. I also see that you don't provide the createNewUser function in UserService, so make sure it is defined; I've changed my answer above to now show the function declaration.
    – Bucket
    Commented May 8, 2020 at 13:41
  • @IliaHanev to mock your '$http.post()' call, Jest provides a decent tutorial on how to approach this: jestjs.io/docs/en/tutorial-async
    – Bucket
    Commented May 8, 2020 at 13:44

Not the answer you're looking for? Browse other questions tagged or ask your own question.