1

I am using AngularJs controller to send data from form to Google Sheet. Using Jasmine I wrote unit-test, which raises the bellow issue:

Error: Unsatisfied requests: POST http://localhost:5000/google-form
at Function.$httpBackend.verifyNoOutstandingExpectation 
(.../angular-mocks/angular-mocks.js:1474:13)

After googling and going through some questions in stackowerflow, I decided to post the question as I didn't find a solution for it.

Here is the code for your references:

Angular Controller

/* global $ */
'use strict';
angular.module('myApp')
  .controller('QuickMessageCtrl', ['$scope', function ($scope) {
    $scope.quickMessageButtonText = 'Send';
    $scope.quickMessage = {
      name: '',
      email: '',
      content: '',
    };

    function setSubmittingIndicators() {
      $scope.quickMessageButtonText = '';
      $scope.submitting = true;
    }

    $scope.postQuickMessageToGoogle = _.throttle(function() {
      setSubmittingIndicators();
      $.ajax({
        url: 'https://docs.google.com/forms/d/MyFormKey/formResponse',
        data: {
          'entry.3'  : $scope.quickMessage.name,
          'entry.1'  : $scope.quickMessage.email,
          'entry.0'  : $scope.quickMessage.content
        },
        type: 'POST',
        dataType: 'jsonp',
        statusCode: {
          200: function (){
            //show succes message;
          }
        }
      });
    }, 500);
  }]);

Unit Test Code

'use strict';

describe('Controller: QuickMessageCtrl', function() {
    var $httpBackend, $rootScope, $controller, scope, apiUrl; 

    beforeEach(module('myApp'));

    beforeEach(inject(function($injector) {
        $httpBackend = $injector.get('$httpBackend');
        apiUrl = $injector.get('apiUrl');
        $httpBackend.expect(
            'POST',
            apiUrl + 'google-form',
            {'name': 'test', 'email': '[email protected]', 'content': 'this is content'}
        ).respond(200);

        $rootScope = $injector.get('$rootScope');
        scope = $rootScope.$new();
        $controller = $injector.get('$controller');
        $controller('QuickMessageCtrl', { $scope: scope });
    }));

    afterEach(function() {
        $httpBackend.verifyNoOutstandingExpectation();
        $httpBackend.verifyNoOutstandingRequest();
    });

    describe('Successful form submit', function() {
        beforeEach(function() {
            scope.quickMessageForm = { $valid: true };
            scope.quickMessage.email = '[email protected]';
            scope.quickMessage.name = 'test';
            scope.quickMessage.content = 'this is test';
            scope.postQuickMessageToGoogle();
        });

        it('should set submitting indicators on submit', function() {
            expect(scope.quickMessageButtonText).toBe('');
        });

    });
});

2 Answers 2

2

Your tests says that the mock http backend should receive a POST at the URL

apiUrl + 'google-form'

which, given the error message, is http://localhost:5000/google-form.

But your controller never sends a POST to that URL. It sends a POST to https://docs.google.com/forms/d/MyFormKey/formResponse. And it doesn't do it using angular's $http service, but does it behind its back, using jQuery.

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

Comments

1

As @JB Nizet pointed you are using jQuery instead of angular methods. In fact you should refactor your code a bit.

Its a great practice to keep things separate, like Controller from Service. In your case you are using service inside the controller. I would rather suggest you to create a service and then import that service in your controller. So basically here how the code will look like:

Controller

/* global $ */
'use strict';
angular.module('myApp')
  .controller('QuickMessageCtrl', ['$scope', 'MyNewService', function ($scope, MyNewService) {
    $scope.quickMessageButtonText = 'Send';
    $scope.quickMessage = {
      name: '',
      email: '',
      content: '',
    };

    function resetFormData() {
      $('#name').val('');
      $('#email').val('');
      $('#content').val('');
    }

    $scope.postQuickMessageToGoogle = _.throttle(function() {
      setSubmittingIndicators();
      MyNewService.sendQuickMessage(
        $scope.quickMessage.name,
        $scope.quickMessage.email,
        $scope.quickMessage.content
      )
      .success(
        //sucess Message
        //can be as well a function that returns a status code
      )
      .error(
        //error Message
      );
    }, 500);
  }]);

Service

'use strict';
angular.module('myApp')
  .factory('MyNewService', ['$http', function ($http) {
    var myService = {};

    myService.sendQuickMessage = function(name, email, content) {
      $http({
        method: 'JSONP',
        url: 'https://docs.google.com/forms/d/MyFormKey/formResponse?'+
          'entry.3=' + name +
          '&entry.1=' + email +
          '&entry.0=' + content
      });
    };
    return myService;
  }]);

Unit-test

'use strict';

describe('Controller: QuickMessageCtrl', function() {
  var $httpBackend, $rootScope, $controller, scope, apiUrl;

  beforeEach(module('myApp'));

  beforeEach(inject(function($injector) {
    $httpBackend = $injector.get('$httpBackend');
    apiUrl = $injector.get('apiUrl');
    $httpBackend.expectJSONP(
      'https://docs.google.com/forms/d/MyFormKey/formResponse?'+
      'entry.3=test'+
      '&[email protected]'+
      '&entry.0=thisIsContent'
    ).respond(200, {});

    $rootScope = $injector.get('$rootScope');
    scope = $rootScope.$new();
    $controller = $injector.get('$controller');
    $controller('QuickMessageCtrl', { $scope: scope });
  }));

  describe('form submit', function() {
    var changeStateSpy;
    beforeEach(function() {
      scope.quickMessage.name = 'test';
      scope.quickMessage.content = 'thisIsContent';
      scope.quickMessage.email ='[email protected]';
    });

    afterEach(function(){
      $httpBackend.verifyNoOutstandingExpectation();
      $httpBackend.verifyNoOutstandingRequest();
    });

    it('should set submitting indicators on submit', function() {
      scope.postQuickMessageToGoogle();
      expect(scope.quickMessageButtonText).toBe('');
      $httpBackend.flush();
    });
  });
});

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.