Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I mock and test chained function with jest?

I have this function chain in my components useEffect hook. I set the response/data to my component state so I can render the data in my component.

client
  .items()
  .type("client")
  .toObservable()
  .subscribe(response => {
    setState(response)
  })

How do I mock this function and call it before the component renders in my test? I'm using testing-library/react.

the response is {items: [{},...]}, somethingElse: {}

like image 920
karolis2017 Avatar asked Aug 30 '19 02:08

karolis2017


People also ask

How do you mock chain methods in Jest?

You can use mockFn. mockReturnThis() to do this. const client = { items: () => { return client; }, type: (name: string) => { return client; }, toObservable: () => { return client; }, subscribe: handler => { handler(); return client; } }; export { client };

How do you make a Jest mock for a function?

Function mock using jest. The simplest and most common way of creating a mock is jest. fn() method. If no implementation is provided, it will return the undefined value. There is plenty of helpful methods on returned Jest mock to control its input, output and implementation.

How do you mock a function inside another function in Jest?

You can create a namespace that you export as the default object and call b using the namespace. This way, when you call jest. mock it will replace the b function on the namespace object. const f = require('./f'); jest.


1 Answers

You can use mockFn.mockReturnThis() to do this.

client.ts, emulate a real third-party module

const client = {
  items: () => {
    return client;
  },
  type: (name: string) => {
    return client;
  },
  toObservable: () => {
    return client;
  },
  subscribe: handler => {
    handler();
    return client;
  }
};

export { client };

Use client.ts module in react component:

class Component {
  private props;
  constructor(props) {
    this.props = props;
  }
  public componentDidMount() {
    this.props.client
      .items()
      .type('client')
      .toObservable()
      .subscribe(response => {
        this.setState(response);
      });
  }
  private setState(state) {
    console.log(state);
  }
}

export { Component };

Unit test, mock chain method of the real client.ts module, inject the mocked client module into your component.

import { Component } from './';

const mockClient = {
  items: jest.fn().mockReturnThis(),
  type: jest.fn().mockReturnThis(),
  toObservable: jest.fn().mockReturnThis(),
  subscribe: jest.fn().mockReturnThis()
};

const mockProps = {
  client: mockClient
};

const component = new Component(mockProps);

describe('Component', () => {
  describe('#componentDidMount', () => {
    it('should mount the component and set state correctly', () => {
      const mockedResponse = { items: [{}], somethingElse: {} };
      mockClient.subscribe.mockImplementationOnce(handler => handler(mockedResponse));
      // tslint:disable-next-line: no-string-literal
      component['setState'] = jest.fn();
      component.componentDidMount();
      expect(mockClient.items().type).toBeCalledWith('client');
      // tslint:disable-next-line: no-string-literal
      expect(component['setState']).toBeCalledWith(mockedResponse);
    });
  });
});

Unit test result:

 PASS  src/mock-function/57719741/index.spec.ts
  Component
    #componentDidMount
      ✓ should mount the component and set state correctly (6ms)

Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        1.542s, estimated 2s
like image 147
slideshowp2 Avatar answered Oct 19 '22 18:10

slideshowp2