2

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.

3
  • You should consider testing what is rendered (like a real user) rather than internal logic or function calls (see the excellent testing-library.com/docs/dom-testing-library/intro for more info on this approach). This will simplify your tests and give you more confidence since they will be closer to a real user experience. Commented Mar 11, 2020 at 14:36
  • You wouldn't--it's not exposed. (You can with something like rewire, but whether or not you should... arguable.) You also don't need to--you just need to test that setCount is called with the right value, and you control setCount in your test. Commented Mar 11, 2020 at 14:43
  • Cheers Flo. I'm trying to write tests for my functions not what looks like acceptance tests. Dave I'd like to write a test for the if statement logic. Any ideas welcome :) Commented Mar 11, 2020 at 14:45

1 Answer 1

1

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

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.