1

I have just started using Jest and enzymes for Reactjs testing. I am using a async function to fetch data inside componentDidMount. I am trying to mock getData function but its failing when function is solving.

export class ListNamespaces extends React.Component<IListNamespacesProps, IListNamespacesState> {

  constructor(props: IListNamespacesProps) {
    super(props);
  }

  componentDidMount() {
    this.getAllData()
      .then((response: Types.ListNamespacesResponse) => {
        this.setState({
          ...
        })
      });
  }

  getAllData() {
    this.setState({
      isLoading: true
    });

    const client = new Client();
    return client.getAlldata();
  }

  ...
}

export class Client { 

  public getAlldata() {
    //async call
  }

}


describe('ListNamespaces', () => {
  test("Shallow Render matches initial snapshot", () => {
    const listNamespaceView = <ListNamespaces/>;
    listNamespaceView.prototype.getAllNamespaces = jest.fn();
    const listNamespacesShallowView = shallow(listNamespaceView);
    expect(listNamespacesShallowView).toMatchSnapshot();
  });
});    

Error -

TypeError: Cannot read property 'then' of undefined

  138 | 
  139 |   componentDidMount() {
> 140 |     this.getAllData()
  141 |       .then((response: Types.ListNamespacesResponse) => {
  142 |         ...

  at ListNamespaces.Object.<anonymous>.ListNamespaces.componentDidMount (src/modules/bulk-namespace/views/list-namespaces.tsx:140:28)
  at node_modules/enzyme/build/ShallowWrapper.js:215:22
  at Object.batchedUpdates (node_modules/enzyme-adapter-react-16/build/ReactSixteenAdapter.js:474:22)
  at new ShallowWrapper (node_modules/enzyme/build/ShallowWrapper.js:214:26)
  at Object.shallow (node_modules/enzyme/build/shallow.js:21:10)
  at Object.<anonymous> (tst/modules/bulk-namespace/list-namespaces.tsx:10:39)

How to mock this function properly.

Andreas Köberle
  • 106,652
  • 57
  • 273
  • 297
user2696466
  • 650
  • 1
  • 14
  • 33
  • Does the class method `getAllData` of `Client` returns a promise? – mmohammad Sep 30 '18 at 06:58
  • 1
    *I am trying to mock getData function* - where? The question should contain https://stackoverflow.com/help/mcve – Estus Flask Sep 30 '18 at 07:00
  • 1
    Your mock implementation should return a Promise. e.g. `jest.fn().mockResolvedValueOnce({data: ['A', 'B']})` See here https://jestjs.io/docs/en/mock-function-api.html#mockfnmockresolvedvalueoncevalue – Hardik Modha Sep 30 '18 at 07:27
  • The following answer demonstrates a way to mock an async. function with Jest at the following link: https://stackoverflow.com/a/42643531/3105371. Another option is to mock `Client`. (Doing so provides coverage of `ListNamespaces.prototype.getAllData` in case a future developer changes it.) See the following for mocking a module: https://stackoverflow.com/a/52453562/3105371. – webprojohn Sep 30 '18 at 12:45

1 Answers1

2

You need to mock the Client class. As getAlldata returns a promise and you need to wait for this promise to be resolved in the test, a solution could look like this:

// first mock the module so it will return a jest mock
jest.mock('./path/to/client', () => jest.fn())

// import the mocked module
import Client from './path/to/client'

// create a promise
const result = Promise.resolve({some: 'result'})
// now mock Client so it will behave like your class 
//  and make `getAlldata` return it
client.mockReturnValue(()=> ({getAllData: ()=> result}))


describe('ListNamespaces',() => {
  // create a `async` test function so you can wait for the result promise
  test("Shallow Render matches initial snapshot", async() => {
    const listNamespacesShallowView = shallow(<ListNamespaces/>);
    // wait for the promise to be resolved
    await result
    expect(listNamespacesShallowView).toMatchSnapshot();
  });
});   

The confusing part is, that you have to create a resolved promise but still have to wait for it in the test itself.

Andreas Köberle
  • 106,652
  • 57
  • 273
  • 297