Search code examples
jestjsenzymets-jestreact-scriptsreact-typescript

Mocking custom Hook with jest and enzyme results in 'xxx is not a function or its return value is not iterable' Error


I am very new to jest and enzyme. In my Project I will use a SPA React based Application. Containing a Context Provider for the data, also several hooks. I Using now Jest (with ts-jest and enzyme)

My jest.config looks like this

module.exports = {
  "roots": [
    "<rootDir>/src"
  ],
  "transform": {
    "^.+\\.tsx?$": "ts-jest"
  },
  "testRegex": "(/__tests__/.*|(\\.|/)(test|spec))\\.tsx?$",
  "moduleFileExtensions": [
    "ts",
    "tsx",
    "js",
    "jsx",
    "json",
    "node"
  ],
  "snapshotSerializers": ["enzyme-to-json/serializer"]

So my first stept so test UI components works. Next step was to test componentes with mocked data. But there I got the error described at the bottom.

I have a functional component like this:

export default function CurrentWeather(props: ICurrentWeatherProps) {
    const [data, Reload] = useCurrentWeather(props.locationID);
    return (<div>......</div>)
}

You will notice the useCurrentWeather hook, here is the code for this:

import { useEffect, useState } from 'react';
import { useLocationState } from '../context/locationContext';
import { ILocationData } from './useLocations';
import _ from 'lodash';

...


export default function useCurrentWeater(locationId: number) {

    const locationState = useLocationState();

    const Reload = () => { GetData() }
    const [Data, SetData] = useState<IWeatherDataInfo>({Id:0,ConditionIcon:'',Date:new Date(),MaxTemp:0, MinTemp:0});

    async function GetData() { .... }
    useEffect(Reload, [locationState.data, locationId]);
    return [Data, Reload] as const;
}

Now I wand to mock these Hook. I tried following

import React from 'react';
import { configure, shallow, mount } from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
import CurrentWeather from '../components/Weather/CurrentWeather';
import { IWeatherDataInfo } from '../Hooks/useWeaters';
configure({ adapter: new Adapter() });


const mockWeatherReload = jest.fn();
const mockdata: IWeatherDataInfo = { Date: new Date(), ConditionIcon: "", MinTemp: 0, MaxTemp: 10 };


jest.mock('../Hooks/useCurrentWeather', () => ({
  useCurrentWeather: jest.fn(()=>{ [mockdata, mockWeatherReload]}) 
}));

describe("WeatherWidget", () => {
  it("RenderOnlyAddButton", () => {
    const container = shallow(<CurrentWeather locationID={1} hidden={false} />);
  });
});

Now, when I execute this test, I will get this error result:

src/tests/WeatherWidget.test.tsx
  ● WeatherWidget › RenderOnlyAddButton

    TypeError: (0 , _useCurrentWeather.default) is not a function or its return value is not iterable

       9 | 
      10 | export default function CurrentWeather(props: ICurrentWeatherProps) {
    > 11 |     const [data, Reload] = useCurrentWeather(props.locationID);
         |                            ^
      12 |     return (

What I'm doing wrong here? Is there what I'm missing?


Solution

  • Try like this:(below should be your functional component's test file)

    const mockUseCurrentWeather = jest.fn();
    
    jest.mock("put here the absolute path", () => ({
      __esModule: true,
      useCurrentWeather: (...args: any) => mockUseCurrentWeather(...args),
    }));
    describe("WeatherWidget", () => {
    beforeEach(() => {
        mockUseCurrentWeather.mockClear();
        mockUseCurrentWeather.mockReturnValue([undefined, undefined]);
    
        
      });
    
      it("RenderOnlyAddButton", () => {
    mockUseCurrentWeather.mockClear();
        mockUseCurrentWeather.mockReturnValue([undefined, undefined]);
        const container = shallow(<CurrentWeather locationID={1} hidden={false} />);
      });
    });