Mock backend server (Google Forms) in AngurJS

2019-08-06 01:29发布

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': 'test@test.com', '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 = 'test@test.com';
            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条回答
劳资没心,怎么记你
2楼-- · 2019-08-06 01:46

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.

查看更多
Bombasti
3楼-- · 2019-08-06 02:09

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'+
      '&entry.1=test@test.com'+
      '&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 ='test@test.com';
    });

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

    it('should set submitting indicators on submit', function() {
      scope.postQuickMessageToGoogle();
      expect(scope.quickMessageButtonText).toBe('');
      $httpBackend.flush();
    });
  });
});
查看更多
登录 后发表回答