0

I am using Ionic and I'd like to do some unit test on my httpClient

describe('send', function() {
    var $httpBackend, userManager, apiClient;

    beforeEach(inject(function($injector) {
        $httpBackend = $injector.get('$httpBackend');
        apiClient = new APIClient($httpBackend, userManager);
    }));

    it ('Should check if send() exists', function() {
        expect(apiClient.send).toBeDefined();
    });

    it ('Should send GET request', function(done) {
        var url = '/';

        $httpBackend.expect('GET', url, {}, {'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'}).respond({});
        apiClient.send({
            url: url,
            success: function(data, status) {
                console.log(data);
                console.log(status);
                done();
            },
            error: function(data, status) {
                console.log(data);
                console.log(status);
                done();
            }
        });
    });
});

But I have all time this error

Error: Unexpected request: [object Object] undefined
Expected GET /

I add a console.log just before the throw in angular-mock and I have

LOG: Object{method: 'GET', url: '/', headers: Object{Content-Type: 'application/x-www-form-urlencoded; charset=UTF-8'}, data: Object{}}

I also try with only $httpBackend.expect('GET', url) and I have the dame error

I tried with $httpBackend.when('GET', url) and I have

Error: Unexpected request: [object Object] undefined
No more request expected

Here's the complete code of APIClient:

/**
 * Util
 *
 * @constructor
 */
var APIClient = function($http, UserManager)
{
    this.userManager = UserManager;

    this.tokenUrl = AppSettings.baseApiUrl + '/oauth/v2/token';
    this.clientId = AppSettings.clientId;
    this.clientSecret = AppSettings.clientSecret;

    this.accessTokenKey = 'access_token';
    this.refreshTokenKey = 'refresh_token';
    this.expireTokenKey = 'expires_in';

    var that = this;

    /**
     *
     * @param {{method:{string}, url:{string}, headers:{}, data:{}, success:function({}, int), error:function({}, int), oauth:{boolean}}} customerData
     */
    this.send = function(customerData)
    {
        var data = {
            method: 'GET',
            url: null,
            headers: {
                'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
            },
            data: {},
            file: null,
            success: function(){},
            error: function(){},
            oauth: false
        };

        for (var attrName in customerData) {
            if (customerData.hasOwnProperty(attrName)) {
                data[attrName] = customerData[attrName];
            }
        }

        var successCallback = data.success;
        var errorCallback = data.error;

        var oAuthStatus = 1;

        if (data.oauth) {
            oAuthStatus = 0;
            this.getToken(function(success, message){
                if (success) {
                    data.url = that.setGetParameter(
                        data.url,
                        that.accessTokenKey,
                        message
                    );
                    oAuthStatus = 1;
                } else {
                    errorCallback(message);
                    oAuthStatus = 2;
                }
            });
        }

        var intvl = setInterval(function() {
            if (oAuthStatus != 0) {
                clearInterval(intvl);

                if (oAuthStatus == 1) {
                    if (data.file !== null) {
                        sendFile(data, successCallback, errorCallback);
                    } else {

                        var tmpData = '';
                        for (var key in data.data) {
                            if (data.data.hasOwnProperty(key)) {
                                data.url = that.setGetParameter(data.url, key, data.data[key]);
                            }
                        }

                        if (data.method !== 'GET') {
                            data.data = tmpData.substring(1);
                        } else {
                            data.data = {};
                        }

                        sendRequest(data, successCallback, errorCallback);
                    }
                }
            }
        }, 100);
    };

    /**
     *
     * @param {function(boolean, {})} callback
     */
    this.getToken = function(callback)
    {
        if (!this.isToken()) {
            this.loadToken(function(success, data){
                if (success) {
                    callback(true, that.getAccessToken());
                } else {
                    callback(false, data);
                }
            });
        }else if (this.isTokenExpired()) {
            this.refreshToken(function(success, data){
                if (success) {
                    callback(true, this.getAccessToken());
                } else {
                    callback(false, data);
                }
            });
        } else {
            callback(true, this.getAccessToken());
        }
    };

    /**
     *
     * @param {function(boolean, data)} callback
     */
    this.loadToken = function(callback)
    {
        if (!this.userManager.isCurrent()) {
            throw {
                key: 'api_client_user_not_found',
                message: 'User not found'
            }
        }

        var user = this.userManager.getCurrent();

        this.send({
            method: 'GET',
            url: this.tokenUrl,
            data: {
                client_id: this.clientId,
                client_secret: this.clientSecret,
                username: user.getUsername(),
                password: user.getPassword(),
                grant_type: 'password'
            },
            success: function (data) {
                that.updateToken(data);
                callback(true, data);
            },
            error: function (data) {
                callback(false, data)
            }
        });
    };

    /**
     *
     * @param {function(boolean, {})} callback
     */
    this.refreshToken = function(callback)
    {
        if (!this.userManager.isCurrent()) {
            throw {
                key: 'api_client_user_not_found',
                message: 'User not found'
            }
        }

        this.send({
            method: 'GET',
            url: this.tokenUrl,
            data: {
                client_id: this.clientId,
                client_secret: this.clientSecret,
                refresh_token: this.getRefreshToken(),
                grant_type: 'refresh_token'
            },
            success: function (data) {
                that.updateToken(data);
                callback(true, data)
            },
            error: function (data) {
                callback(false, data)
            }
        });
    };

    /**
     *
     * @param {{access_token:{string}, refresh_token:{string}, expires_in:{string}}} data
     */
    this.updateToken = function(data)
    {
        window.localStorage.setItem(this.accessTokenKey, data[this.accessTokenKey]);
        window.localStorage.setItem(this.refreshTokenKey, data[this.refreshTokenKey]);

        var t = new Date();
        t.setSeconds(t.getSeconds() + data[this.expireTokenKey]);

        window.localStorage.setItem(this.expireTokenKey, t.getTime());
    };

    /**
     * Clear api tokens
     */
    this.clearToken = function()
    {
        window.localStorage.removeItem(this.accessTokenKey);
        window.localStorage.removeItem(this.refreshTokenKey);
        window.localStorage.removeItem(this.expireTokenKey);
    };

    /**
     *
     * @returns string
     */
    this.getAccessToken = function()
    {
        return window.localStorage.getItem(this.accessTokenKey);
    };

    /**
     *
     * @returns string
     */
    this.getRefreshToken = function()
    {
        return window.localStorage.getItem(this.refreshToken);
    };

    /**
     *
     * @returns string
     */
    this.getTokenExpiration = function()
    {
        return window.localStorage.getItem(this.expireTokenKey);
    };

    /**
     *
     * @returns {boolean}
     */
    this.isToken = function()
    {
        return null !== this.getAccessToken();
    };

    /**
     *
     * @returns {boolean}
     */
    this.isTokenExpired = function()
    {
        var t = new Date;

        return t.getTime() > this.getTokenExpiration()
    };

    /**
     *
     * @param {string} url
     * @param {string} paramName
     * @param {string} paramValue
     * @returns {string}
     */
    this.setGetParameter = function(url, paramName, paramValue)
    {
        if (url.indexOf(paramName + "=") >= 0)
        {
            var prefix = url.substring(0, url.indexOf(paramName));
            var suffix = url.substring(url.indexOf(paramName));
            suffix = suffix.substring(suffix.indexOf("=") + 1);
            suffix = (suffix.indexOf("&") >= 0) ? suffix.substring(suffix.indexOf("&")) : "";
            url = prefix + paramName + "=" + paramValue + suffix;
        }
        else
        {
            if (url.indexOf("?") < 0)
                url += "?" + paramName + "=" + paramValue;
            else
                url += "&" + paramName + "=" + paramValue;
        }
        return url;
    };

    function sendRequest(data, successCallback, errorCallback) {
        $http({
            method: data.method,
            url: data.url,
            headers: data.headers,
            data: data.data
        }).success(function(data, status){
            successCallback(data, status);
        }).error(function(data, status){
            errorCallback(data, status);
        });
    }

    function sendFile(data, successCallback, errorCallback) {

        var options = new FileUploadOptions();
        options.fileKey="file";
        options.fileName="file";
        options.params = data.data;

        var ft = new FileTransfer();
        ft.upload(data.file, data.url, uploadSuccess, uploadError, options);
        function uploadSuccess(r) {
            result = JSON.parse(r.response);
            successCallback(result, true);
        }
        function uploadError(error) {
            errorCallback(error, true)
        }
    }

};

angular.module('api.client', []).factory('APIClient', ['$http', 'UserManager', function($http, UserManager)
{
    var client = new APIClient($http, UserManager);

    return {
        send: function(data)
        {
            return client.send(data);
        },
        clearToken: function()
        {
            client.clearToken();
        }
    }

}]);
9
  • You're testing the APIClient, and it fails, but we have no idea of what APIClient does. Post its code. And never use $httpBackend anywhere, except in tests. Production code should use $http. Commented Jun 30, 2015 at 10:25
  • I add it in the edit, there is something like that $http({method:'GET', url:'/', ...}) Commented Jun 30, 2015 at 10:29
  • We don't need to know that there is "something like that". We want to know the exact code of APIClient. Commented Jun 30, 2015 at 10:30
  • 1
    Well, the APIClient function expects the $http service as argument, and you're passing it the $httpBackend service instead. Commented Jun 30, 2015 at 10:52
  • 1
    No. The $httpBackend defined in angular-mocks is a mock for the real $httpBackend service defined in angular. $http uses $httpBackend. See docs.angularjs.org/api/ng/service/$httpBackend Commented Jun 30, 2015 at 11:09

1 Answer 1

2
+50

Your error occurs because you are expecting a query $http('GET','/') that never occurs !

I'm not sure how to manage your case where you pass a parameter the $http dependency. $httpBackend manages alone the replacement of $http calls, and is therefore expecting an $http in your code.

To keep your code AS IS, I'd inject $http into your beforeEach, but I never tested that.

 beforeEach(inject(function($injector) {
        $httpBackend = $injector.get('$httpBackend');
        var $http = $injector.get('$http');
        apiClient = new APIClient($http, userManager);
    }));

I'd rather modify my APIClient to not take a $http parameter so the standard mechanic of angularJS $httpBackend would apply

Moreover do not forget to use : $httpBackend.flush() to flushes all pending requests using the trained responses.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.