Jasmine — Custom Spies

John Au-Yeung - Jan 23 '21 - - Dev Community

Check out my books on Amazon at https://www.amazon.com/John-Au-Yeung/e/B08FT5NT62

Subscribe to my email list now at http://jauyeung.net/subscribe/

Testing is an important part of JavaScript.

In this article, we’ll look at how to create custom spies.

Custom Spies

We can use the jasmine.setDefaultSpyStrategy to create a spy that does what we want.

For instance, we can write:

describe("spy tests", function () {
  beforeEach(function () {
    jasmine.setDefaultSpyStrategy(and => and.returnValue("Hello World"));
  }); 

  it('calls custom spy', function () {
    const spy = jasmine.createSpy();
    expect(spy()).toEqual("Hello World");
  });
});
Enter fullscreen mode Exit fullscreen mode

We called setDefaultSpyStrategy with a callback that returns the 'Hello World' value.

Once we did that, our spy would return 'Hello world' .

So when we call spy , it returns 'Hello World' .

Also, we can call setDefaultSpyStrategy with no arguments to remove a custom default.

For instance, we can write;

describe("spy tests", function () {
  beforeEach(function () {
    jasmine.setDefaultSpyStrategy(and => and.returnValue("Hello World"));
  }); 

  it('calls custom spy', function () {
    const spy = jasmine.createSpy();
    expect(spy()).toEqual("Hello World");
  }); 

  it("throws if you call any methods", function () {
    jasmine.setDefaultSpyStrategy(and => and.throwError(new Error("Do Not Call Me")));
    const program = jasmine.createSpyObj(['start']);
    jasmine.setDefaultSpyStrategy(); expect(() => {
      program.start();
    }).toThrowError("Do Not Call Me");
  });
});
Enter fullscreen mode Exit fullscreen mode

We called createSpyObj in the 2nd test to include a 'start' method in the porgram spy object.

Then we can check if an error is thrown with we call start .

Spying on Properties

We can spy on properties with the spyOnProperty method.

For instance, we can write:

describe("property spy test", function () {
  let someObject = {
    get myValue() {
      return 1
    }
  }; 

  beforeEach(function () {
    this.propertySpy = spyOnProperty(someObject, "myValue", "get").and.returnValue(1);
  }); 

  it("lets you change the spy strategy later", function () {
    this.propertySpy.and.returnValue(3);
    expect(someObject.myValue).toEqual(3);
  });
});
Enter fullscreen mode Exit fullscreen mode

We created a someObject with the myValue getter to return something.

Then in the beforeEach hook, we call spyOnPropoerty spy on the object and return the mocked value we want.

In our test, we called returnValue to make the getter return another value.

And then we can check for the return value we just set.

We can also spy on an object with several properties on it by passing in a hash of properties.

For instance, we can write:

describe("property spy test", function () {
  it("lets you change the spy strategy later", function () {
    const obj = jasmine.createSpyObj("myObject", {}, { x: 3, y: 4 });
    expect(obj.x).toEqual(3); 
    Object.getOwnPropertyDescriptor(obj, "x").get.and.returnValue(7);
    expect(obj.x).toEqual(7);
  });
});
Enter fullscreen mode Exit fullscreen mode

We create a spy object with some properties.

It has the x and y properties.

Then we can check for obj.x and return the value we want.

And then we can check for it.

Conclusion

There are different ways to spy on objects and return values.

We can create spy objects and set the spy strategy to what we want.

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .