Skip to content
This repository

Jasmine integrates 'spies' that permit many spying, mocking, and faking behaviors. A 'spy' replaces the function it is spying on.

Here are a few examples:

var Klass = function () {
};

Klass.staticMethod = function (arg) {
  return arg;
};

Klass.prototype.method = function (arg) {
  return arg;
};

Klass.prototype.methodWithCallback = function (callback) {
  return callback('foo');
};

//...

describe("spy behavior", function() {
  it('should spy on a static method of Klass', function() {
    spyOn(Klass, 'staticMethod');
    Klass.staticMethod('foo argument');

    expect(Klass.staticMethod).toHaveBeenCalledWith('foo argument');
  });

  it('should spy on an instance method of a Klass', function() {
    var obj = new Klass();
    spyOn(obj, 'method');
    obj.method('foo argument');

    expect(obj.method).toHaveBeenCalledWith('foo argument');

    var obj2 = new Klass();
    spyOn(obj2, 'method');
    expect(obj2.method).not.toHaveBeenCalled();
  });

  it('should spy on Klass#methodWithCallback', function() {
    var callback = jasmine.createSpy();
    new Klass().methodWithCallback(callback);

    expect(callback).toHaveBeenCalledWith('foo');
  });
});

Spies can be used to test constructor calls

var namespace = { 
  Klass : function (something) { 
    this.something = something; 
  }
};

describe('spy class constructor', function () {

  it('should be possible', function () {
    var k;

    spyOn(namespace, 'Klass').andCallThrough();
    k = new namespace.Klass();

    expect(namespace.Klass).toHaveBeenCalled();
    expect(k instanceof namespace.Klass).toBeTruthy();
  });

  it('should spy the constructor argument', function () {
    var k;

    spyOn(namespace, 'Klass').andCallThrough();
    k = new namespace.Klass('some value');

    expect(namespace.Klass).toHaveBeenCalledWith('some value');
    expect(k.something).toBe('some value');
  });
});

Spies can be very useful for testing AJAX or other asynchronous behaviors that take callbacks by faking the method firing an async call.

var Klass = function () {
};

Klass.asyncMethod = function (callback) {
  someAsyncCall(callback);
};

...

it('should test async call', function () {
  spyOn(Klass, 'asyncMethod');
  var callback = jasmine.createSpy();

  Klass.asyncMethod(callback);
  expect(callback).not.toHaveBeenCalled();

  var someResponseData = 'foo';
  Klass.asyncMethod.mostRecentCall.args[0](someResponseData);
  expect(callback).toHaveBeenCalledWith(someResponseData);

});

Spy-specific Matchers

When working with spies, these matchers are quite handy:

expect(x).toHaveBeenCalled() passes if x is a spy and was called

expect(x).toHaveBeenCalledWith(arguments) passes if x is a spy and was called with the specified arguments

expect(x).not.toHaveBeenCalled() passes if x is a spy and was not called

expect(x).not.toHaveBeenCalledWith(arguments) passes if x is a spy and was not called with the specified arguments

The old matchers wasCalled, wasNotCalled, wasCalledWith, and wasNotCalledWith have been deprecated and will be removed in a future release. Please change your specs to use toHaveBeenCalled, not.toHaveBeenCalled, toHaveBeenCalledWith, and not.toHaveBeenCalledWith respectively.

Spies can be trained to respond in a variety of ways when invoked:

spyOn(x, 'method').andCallThrough(): spies on AND calls the original function spied on

spyOn(x, 'method').andReturn(arguments): returns passed arguments when spy is called

spyOn(x, 'method').andThrow(exception): throws passed exception when spy is called

spyOn(x, 'method').andCallFake(function): calls passed function when spy is called

Spies can also be retrained after first being invoked:

spyOn(x, 'method').andReturn(value1); ... ; x.method.andReturn(value2): changes the value returned by x.method()

Spies have some useful properties:

callCount: returns number of times spy was called

mostRecentCall.args: returns argument array from last call to spy.

argsForCall[i] returns arguments array for call i to spy.

Spies are automatically removed after each spec. They may be set in the beforeEach function.

Something went wrong with that request. Please try again.