0

How can we test a conditions inside a $get in customer provider, I would like to test if else conditions under showSpinner.

I will be enabling my spinnerSerive in config using

spinnerServiceProvider.spinnerEnabled(true)

and toggling my spinner in controller using

spinnerService.showSpinner(true) or spinnerService.showSpinner(false)



  angular.module('providerModule', []).provider('spinnerService', [
  function() {
    var enabled = true;
    return {
      spinnerEnabled: function(setting) {
        if (angular.isDefined(setting)) {
          enabled = setting;
          return this;
        } else {
          return enabled;
        }
      },
      $get: function($injector) {
        return {
          showSpinner: function(option) {
            if (enabled) {
              if(option){
                  angular.element(document.body).append('<div id="spinner"><div class="modal-backdrop fade in"></div><div class="load5"><div class="loader" ></div></div></div>');
                }
              else{
                angular.element(document.querySelector('#spinner')).remove();

              }
            }
          }
        }
      }
    }

  }
]);

I was able to test whether showSpinner have been called but how to test it is entering if and else block correctly. Below is spec.js

    describe('Spinner Provider', function(){
    var spinnerServiceObj;
    beforeEach(module('providerModule'));
    describe('testing spinner', function(){
        beforeEach(function() {
            inject(function(_spinnerService_,_$rootScope_) {
                spinnerServiceObj = _spinnerService_;
                $rootScope = _$rootScope_;
                $rootScope.showSpinner = jasmine.createSpy(spinnerServiceObj.showSpinner(true))
            });
        });
        it('Should test showSpinner with true and false', function() {
            expect($rootScope.showSpinner ).toHaveBeenCalled();

        });
    })
})
Naresh217
  • 410
  • 1
  • 6
  • 19

2 Answers2

0

Inside of a describe block, use:

beforeEach(function() {
  module('providerModule')
    .config(function(spinnerServiceProvider) {
       // set enabled/disabled here 
    });
});

That should allow you to test either condition.

Shaun Scovil
  • 3,905
  • 5
  • 39
  • 58
0

Unit tests aren't supposed to be tested against real DOM, especially if this may create problems for test runner.

Direct document references should be replaced with $window.document. $window is there to make mocking the globals easier.

Then it can be mocked with

var bodyMock = {};

beforeEach(module('providerModule', { $window: {
  document: {
    body: bodyMock,
    querySelector: jasmine.createSpy()
  }
} }));

angular.element or jQuery can be tested by mocking it entirely or only prototype methods:

// angular.element.prototype should be stubbed before angular.element
// because a spy doesn't expose original `prototype`
spyOn(angular.element.prototype, 'append');
spyOn(angular.element.prototype, 'remove');
spyOn(angular, 'element').and.callThrough();

One condition can be tested with

spinnerService.showSpinner(true);

expect(angular.element).toHaveBeenCalled();
expect(angular.element.calls.mostRecent().args[0]).toBe(bodyMock);
expect(angular.element.prototype.append).toHaveBeenCalledWith('<div...);
expect($window.document.querySelector).not.toHaveBeenCalled();

And another condition can be tested with

var spinnerMock = {};
$window.document.querySelector.and.returnValue(spinnerMock);

spyOn(angular, 'element').and.callThrough();

spinnerService.showSpinner();

expect($window.document.querySelector).toHaveBeenCalled('#spinner');

expect(angular.element).toHaveBeenCalled();
expect(angular.element.calls.mostRecent().args[0]).toBe(spinnerMock);
expect(angular.element.prototype.remove).toHaveBeenCalled();
expect(angular.element.prototype.append).not.toHaveBeenCalled();

Alternatively, $window.document can be mocked alone to operate on some detached DOM element, so the result of showSpinner call could be tested against element contents.

Community
  • 1
  • 1
Estus Flask
  • 206,104
  • 70
  • 425
  • 565
  • i have modified as per your suggestion i got below errors for expect(angular.element.calls.mostRecent().args[0]).toBe(bodyMock); expect(angular.element.prototype.append).toHaveBeenCalledWith('
    '); Expected HTMLNode to be Object({ }). at Object. (/Users/spinner/@spinnerServiceSpec.js:59:60) Error: Expected a spy, but got undefined. at Object.
    – Naresh217 Jul 19 '16 at 18:38
  • This may happen if you haven't replaced `document` with `$window.document` in original code. The fiddle contains the spec but not the module it tests. – Estus Flask Jul 19 '16 at 18:44
  • i have replaced with $window.document also updated fiddle now – Naresh217 Jul 19 '16 at 18:49
  • Please, check it again, it throws `ReferenceError: describe is not defined` and there's no module itself. – Estus Flask Jul 19 '16 at 19:13
  • Your fiddle contains syntax errors and doesn't execute the spec - there's also no angular and no angular-mocks. The question was 'How can we test a conditions inside a $get in customer provider' and I believe the answer explains that. Please, provide a *working* fiddle that is able to replicate the error if you need help on solving it. Currently there's not enough information to suggest anything useful. – Estus Flask Jul 19 '16 at 21:03