简体   繁体   中英

Jasmine test state of object on Ajax method spy call

I'm unit testing an Angular controller that uses a Rails Resource factory to handle GETing and POSTing model data from and to a Rails app. POSTing is done via a method on the model, eg (with a model $scope.resource ):

$scope.resource.update().then(successHandler, failureHandler);

I have a spy on this method to stub out the Ajax calls so I can unit test the controller:

resUpdateSpy = spyOn($scope.resource, 'update').and.callFake(function() { 
  return {then: function(success, failure){ success(resUpdateResponse); }};
});

In one of my controller methods, I expect the resource to be POSTed with certain data (Stripe data in particular). The data will be overridden after the POST in the same method, so I cannot test the state of the model afterwards. Ideally, I would like to something like:

expect($scope.resource.update).toHaveBeenCalled().whileValueOf($scope.resource.stripeKey).isEqualTo('tok123');

Obviously, this method doesn't exist in vanilla Jasmine. Is there a way in Jasmine (either vanilla or through a third-party project) to test the state of a value when a given spy is called? or is there another way to test this situation – specifically, the state of a model before its data POSTs – that I'm missing?

I'm running Jasmine 2.2.0 with Teaspoon 1.0.2 on an Angular 1.3.14 app.

you can add your own jasime matchers, the one you need would be

jasmine.Matchers.prototype.toBeResolvedWith = function() {
  var done, expectedArgs;
  expectedArgs = jasmine.util.argsToArray(arguments);
  if (!this.actual.done) {
    throw new Error('Expected a promise, but got ' + jasmine.pp(this.actual) + '.');
  }
  done = jasmine.createSpy('done');
  this.actual.done(done);
  this.message = function() {
    if (done.callCount === 0) {
      return ["Expected spy " + done.identity + " to have been resolved with " + jasmine.pp(expectedArgs) + " but it was never resolved.", "Expected spy " + done.identity + " not to have been resolved with " + jasmine.pp(expectedArgs) + " but it was."];
    } else {
      return ["Expected spy " + done.identity + " to have been resolved with " + jasmine.pp(expectedArgs) + " but was resolved with " + jasmine.pp(done.argsForCall), "Expected spy " + done.identity + " not to have been resolved with " + jasmine.pp(expectedArgs) + " but was resolved with " + jasmine.pp(done.argsForCall)];
    }
  };
  return this.env.contains_(done.argsForCall, expectedArgs);
};

more available here https://gist.github.com/gr2m/2191748

updated after comment:

basically jasmine supports custom matchers. some in built matchers are toBe, toEqual, etc. You can add your own custom matcher to check the promise.

var customMatchers = {

toHaveBeenResolved: function(util, customEqualityTesters) {
  return {
    compare: function(actual, expected) {
      var result = {};
      // do you comparison logic here
      result.pass = true/false;
      result.message = 'some message about test result';
      return result;
    }
}

this.actual is a promise and you can resolve it like this

result = {};
promise.then(function(value){
  result.value = value;
  result.status = 'Resolved';
}, function(value){
  result.value = value;
  result.status = 'Rejected';
});

once you have declared you custom matcher use it in you test case in beforeEach callback.

beforeEach(function() {
  jasmine.addMatchers(customMatchers);
}); 

As you already have your spy forward the call to a fake function, have that fake function store the value of interest for you:

var scopeResourceStripeKeyDuringSpyCall = '(spy not called, yet)';
resUpdateSpy = spyOn($scope.resource, 'update').and.callFake(function() {
  scopeResourceStripeKeyDuringSpyCall = $scope.resource.stripeKey;
  return {then: function(success, failure){ success(resUpdateResponse); }};
});

Then just check for the stored-away value in your assertion:

expect(scopeResourceStripeKeyDuringSpyCall).toEqual('tok123');

(Depending on whether spy setup and assertion are in the same scope, the variable for storing the value might have to be less local.)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM