Skip to content
James Richford edited this page Jun 11, 2017 · 5 revisions

When we want to check functions are called, this is simple first we need to turn it into a spy...

import { SpyOn } from "alsatian";

let some = {
  function: () => {}
};

SpyOn(some, "function");

... then check it's been called ...

Expect(some.function).toHaveBeenCalled();

... or check it's been called with certain arguments ...

Expect(some.function).toHaveBeenCalledWith(this, "and that");

... you can match arguments based on certain criteria using the Any function ...

import { Any } from "alsatian";

... such as type ...

Expect(some.function).toHaveBeenCalledWith(Any(Number));
Expect(some.function).toHaveBeenCalledWith(Any(Object));
Expect(some.function).toHaveBeenCalledWith(Any(YourCustomClass));

... something with a specific property ...

Expect(some.function).toHaveBeenCalledWith(Any(YourClass).thatMatches("property", "value"));

... something with a selection of properties ...

Expect(some.function).toHaveBeenCalledWith(Any(YourClass).thatMatches({
   "propertyOne", "value one",
   "propertyTwo", "value two"
}));

... something which matches your own custom delegate function ...

Expect(some.function).toHaveBeenCalledWith(Any(YourClass).thatMatches((argument) => argument > 42));

... or just anything at all ...

Expect(some.function).toHaveBeenCalledWith(Any);

... or a specific number of times ...

Expect(some.function).toHaveBeenCalled().exactly(42).times;
Expect(some.function).toHaveBeenCalledWith("something").anythingBut(10).times;
Expect(some.function).toHaveBeenCalledWith(Any).lessThan(5).times;
Expect(some.function).toHaveBeenCalledWith(Any(Number), Any(Array)).greaterThan(2).times;

// Note that this functionality must not be used with the not operator
// e.g. the following throws an error
Expect(some.function).not.toHaveBeenCalled().lessThan(42).times;

// this should be written
Expect(some.function).toHaveBeenCalled().greaterThan(41).times;

... you can stub it out ...

SpyOn(some, "function").andStub();

... you can make it call something else ...

SpyOn(some, "function").andCall(() => {
  console.log("I are called");  // make it do whatever you like
  return "whatever you like";   // and also return stuff too!
});

... or make it return whatever you desire ...

SpyOn(some, "function").andReturn(42);

... and even return it to how it started

const spy = SpyOn(some, "function");

// restores the function to it's initial state
spy.restore();

// you may also access other internal info from the spy
// for example all the calls are recorded in the below property
spy.calls;

Creating a spy from thin air

You may want to just create a fake spy property this is easy to do and has all the same functionality as a Spy created through SpyOn

import { createFunctionSpy } from "alsatian";

const spy = createFunctionSpy();

Spying on a property

Similarly to spying on functions you can also spy on properties as below ...

import { SpyOnProperty } from "alsatian";

class Test {

   private _property: number = 42;

   get property() {
      return this._property;
   }

   set property(value: number) {
      this._property = value;
   }
}

const test = new Test();

SpyOnProperty(test, "property");

... then check it's been set ...

const propertySpy = SpyOnProperty(test, "property");

// unlike function spies expect calls on property spies
// only works using the returned spy from SpyOnProperty
// and not the property itself
Expect(propertySpy).toHaveBeenSet();

... or check it's been set to a specific value ...

Expect(propertySpy).toHaveBeenSetTo(42);

... add a fake getter ...

SpyOnProperty(test, "property").andCallGetter(() => { return "something"; });

... or setter ...

SpyOnProperty(test, "property").andCallSetter((value: any) => { doSomethingWith(value); });

... return a set value ...

SpyOnProperty(test, "property").andReturnValue(42);

... and restore it to how it was before

const properySpy = SpyOnProperty(test, "property");

properySpy.restore();