mtx
mtx

Reputation: 1234

Test function assignment inside a class method in Jest

I have a class in which i use strategy pattern it looks something like this:

class Foo {
   constructor() {
      this.doStuff = function() { /* not used really */ }
   }
   create(config) {
      this.type = config.type;

      // assign other variables to this

      this.doStuff = StuffStrategy(config.type);

      this.doStuff();
   }
}

StuffStrategy is a function that returns other functions which use this context differently based on type.

function StuffStrategy(type) {
   switch(type) {
     case A: return StrategyA;
     case B: return StrategyB;
     // ...
   }
}

function StrategyA() {
  if(this.someVarInFoo) {
    return 'a thing'
  } else 
    return 'a different thing' + this.otherVarInFoo
}

I assign particular Strategy function inside create method. Then I would like to test the create method if it calls doStuff.

describe('how create method works', () => {
    const instance = new Foo();
    const spy = jest.spyOn(instance, 'doStuff');
    instance.create(config); 
    expect(spy).toBeCalled();
});

But when I try to make spy before calling instance.create then it refers to default method assigned in constructor, which gets replaced inside create.

If i make spy after calling instance.create then it will not pick the call . I tried to add .bind when defining this.doStuff:

this.doStuff = StuffStrategy(config.type).bind(this);

but it does not work either.

Is there something wrong with my setup? How can I make this test case work?

Upvotes: 1

Views: 278

Answers (1)

Diego
Diego

Reputation: 124

You have to spyOn the strategy methods of your Foo class. So for every config.type you check then which strategy method has been called.

export class Foo {
  constructor(){
    this.doStuff = null;
  }

  create(config){
     this.type = config.type;

     // assign other variables to this

     this.doStuff = StuffStrategy(config.type);

     this.doStuff();
  }

  strategyA(){...}

  strategyB(){...}

  StuffStrategy(configtype) {
    switch (configtype) {
     case "A": return this.strategyA;
     case "B": return this.strategyB;
   }
  }
}
import { Foo } from 'anyPlaceFoo/foo';

describe('Strategy', () => {

  it('should call strategy A', () => {
    const foo = new Foo();

    // here you can spy on every strategy method.
    jest.spyOn(foo, 'strategyA');
    jest.spyOn(foo, 'strategyB');

    foo.create({ type: 'A' });

    // check if the selected one has been called but not the others
    expect(foo.strategyA).toHaveBeenCalled();
    expect(foo.strategyB).not.toHaveBeenCalled();
  })
})

Upvotes: 1

Related Questions