MaxwellLynn
MaxwellLynn

Reputation: 968

React Hooks jest testing - method is not a function

I'm getting fed up with trying to test hooks but I feel so close with this approach. Here me out.

I've got this test running and it gives me this error:

'TypeError: handleCount is not a function'

describe("<Content />", () => {
  const setCount = jest.fn();
   let activeTab = 'Year';

   test("Ensure that handleCount is fired if activeTab is the type year", () => {
      handleYearTab(setCount, activeTab);
    });
 });

So this makes sense but I'm not sure how I can mock the method that it is complaining about. this is my component that I'm trying to test:

/**
 * Get new count from getTotalAttendances
 * @param dates | New date picked by the user
 * @param setCount | Hook function
 * @param activeTab | Type of tab
 */
function handleCount(
  dates: object,
  setCount: Function,
  activeTab?: string,
) {
  const totalCount = new GetTotal(dates, activeTab);
  setCount(totalCount.totalAttendances());
}

/**
 * Handle count for the year tab.
 * @param setCount | Hook function
 * @param activeTab | Type of tab
 */
export function handleYearTab(
  setCount: Function,
  activeTab: string,
) {
  if (activeTab === 'Year') { 
    handleCount(new Date(), setCount, activeTab);
  }
}

const Content: FC<Props> = ({ activeTab }) => {
  const [count, setCount] = useState<number>(0);

  useEffect(() => {
    handleYearTab(setCount, activeTab);
  });

  return (
    <Container>
      <TotalAttendences count={count} />
    </Container>
  );
}

export default Content;

I'm really curious how you would go about mocking the handleCount method.

Upvotes: 1

Views: 5593

Answers (1)

Lin Du
Lin Du

Reputation: 102587

Here is the unit test solution using jestjs and react-dom/test-utils:

index.tsx:

import React, { FC, useState, useEffect } from 'react';
import { GetTotal } from './getTotal';

interface Props {
  activeTab: string;
}

function handleCount(dates: object, setCount: Function, activeTab?: string) {
  const totalCount = new GetTotal(dates, activeTab);
  setCount(totalCount.totalAttendances());
}

export function handleYearTab(setCount: Function, activeTab: string) {
  if (activeTab === 'Year') {
    handleCount(new Date(), setCount, activeTab);
  }
}

const Content: FC<Props> = ({ activeTab }) => {
  const [count, setCount] = useState<number>(0);

  useEffect(() => {
    handleYearTab(setCount, activeTab);
  });

  return <div>{count}</div>;
};

export default Content;

getTotal.ts:

export class GetTotal {
  constructor(dates, activeTab) {}
  public totalAttendances(): number {
    return 1;
  }
}

index.test.tsx:

import Content from './';
import React from 'react';
import { render, unmountComponentAtNode } from 'react-dom';
import { act } from 'react-dom/test-utils';
import { GetTotal } from './getTotal';

describe('60638277', () => {
  let container;
  beforeEach(() => {
    container = document.createElement('div');
    document.body.appendChild(container);
  });

  afterEach(() => {
    unmountComponentAtNode(container);
    container.remove();
    container = null;
  });
  it('should handle year tab', async () => {
    const totalAttendancesSpy = jest.spyOn(GetTotal.prototype, 'totalAttendances').mockReturnValue(100);
    const mProps = { activeTab: 'Year' };
    await act(async () => {
      render(<Content {...mProps}></Content>, container);
    });
    expect(container.querySelector('div').textContent).toBe('100');
    expect(totalAttendancesSpy).toBeCalled();
    totalAttendancesSpy.mockRestore();
  });

  it('should render initial count', async () => {
    const mProps = { activeTab: '' };
    await act(async () => {
      render(<Content {...mProps}></Content>, container);
    });
    expect(container.querySelector('div').textContent).toBe('0');
  });
});

unit test results with coverage report:

 PASS  stackoverflow/60638277/index.test.tsx (9.331s)
  60638277
    ✓ should handle year tab (32ms)
    ✓ should render initial count (11ms)

-------------|---------|----------|---------|---------|-------------------
File         | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
-------------|---------|----------|---------|---------|-------------------
All files    |   95.24 |      100 |   85.71 |   94.12 |                   
 getTotal.ts |      80 |      100 |   66.67 |      75 | 4                 
 index.tsx   |     100 |      100 |     100 |     100 |                   
-------------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests:       2 passed, 2 total
Snapshots:   0 total
Time:        10.691s

source code: https://github.com/mrdulin/react-apollo-graphql-starter-kit/tree/master/stackoverflow/60638277

Upvotes: 1

Related Questions