Enot Enot - 1 month ago 9
AngularJS Question

Change provide service value to test different cases

I'm testing a modal behaviour where depending of user actions, the result of modal can return several options.

The code based is as follows:

const modalInstance = this.$uibModal.open({
animation: true,
resolve: {},
component: 'modalView',
size: 'lg'
});
let dismissed = false;
modalInstance.result.then((result) => {
if (result.redirect) {
this.redirectToBrowseIfReverted();
} else {
this.redirectToSaveTarget();
}
},
() => {
dismissed = true;
});


So depending of redirect is true or false, it'll call
redirectToBrowseIfReverted
or
redirectToSaveTarget
. To start testing this out I just inject
module
through
angular.mock.module
and passing
$uibModal
service to
$provide
to mock as desired:

let mockModal = () => ({
open: () => {
return { result: $q.resolve({ redirect: true }) };
}
});

beforeEach(() => {
angular.mock.module(moduleName, $provide => {
$provide.service('$uibModal', mockModal);
});


This certainly will return
redirect
value as
true
and call
redirectToBrowseIfReverted
but I want to test the case when this is
false
but I don't know how to tell angular in a particular UT case to override the
$provide
service for
$uibModal
and return
false
instead. Any help will be really much appreciated.

ash ash
Answer Source

Unfortunately you didn't mention what test framework you're working with.

If it's Jasmine, you can utilise a spy (see https://jasmine.github.io/2.0/introduction.html#section-Spies) to dynamically change the returned value.

You would have to inject the service into your test like so:

var $uibModal;
var $q

beforeEach(angular.mock.inject(function(_$uibModal_, _$q_) {
  $uibModal = _$uibModal_;
  $q = _$q_;
}));

Then you can use spies inside the tests themselves:

it('should return redirect as true', function() {
  spyOn($uibModal, 'open').and.returnValue({
    result: $q.resolve({ redirect: true })
  });
  <the rest of your test>
});

it('should return redirect as false', function() {
  spyOn($uibModal, 'open').and.returnValue({
    result: $q.resolve({ redirect: false })
  });
  <the rest of your test>
});

Apologies for not es6ing it, but hopefully you get the jist. :)

edit: Also if you have a lot of tests and you're concerned about putting a spy in every test, you can do something like this to test the failure case only once:

var $uibModal;
var $q;
var modalSpy;

beforeEach(angular.mock.inject(function(_$uibModal_, _$q_) {
  $uibModal = _$uibModal_;
  $q = _$q_;
  modalSpy = spyOn($uibModal, 'open').and.returnValue({
    result: $q.resolve({ redirect: true })
  });
}));

it('returns false for this one test only', function() {
  modalSpy.and.returnValue({
    result: $q.resolve({ redirect: false })
  });
});

As a spy can only ever have a single execution strategy, it takes the last one. It's a bit hacky, but it works.