Testing with Jest FakeTimers

157 Views Asked by At

I'm having a problem testing a particular component. It is a wrapper that includes a progress bar which in turn receives a now number prop (0-100 percentage) which dictates the position of the bar. In the test, I've recruited Jest's fakeTimers to confirm that the correct prop is being sent to the ProgressBar component.

This is the implementation of the wrapper:

import React, {useEffect, useRef, useState} from 'react';
import {ProgressBar} from 'local-repo';

export type Props = {
  period: number;
};

const INCREMENT = 1000;

const Wrapper = ({period}: Props): JSX.Element => {
  const [progressPercentage, setProgressPercentage] = useState(0);
  const timerRef = useRef<NodeJS.Timer>();

useEffect(() => {
    timerRef.current = setInterval(() => {
      const getProgressPercentage = (previousState: number) =>
        (((previousState / 100) * period + INCREMENT) * 100) / period;
      setProgressPercentage((previousState) => getProgressPercentage(previousState));
    }, INCREMENT);
    return () => {
      clearInterval(timerRef.current);
    };
  }, []);

  useEffect(() => {
    if (progressPercentage >= 100) clearInterval(timerRef.current);
  }, [progressPercentage]);

  return (
      <ProgressBar now={progressPercentage} />
  );
};

export default Wrapper;

This is the test:

import {render, screen, cleanup} from '@testing-library/react';
import '@testing-library/jest-dom';
import {ProgressBar} from 'local-repo';
import Wrapper, {
  type Props,
} from './Wrapper';

jest.mock('local-repo');
(ProgressBar as jest.Mock).mockImplementation(({}) => <div>ProgressBar</div> );

jest.spyOn(global, 'setInterval');

const INCREMENT = 1000;
const getRenderResult = (props: CreditLimitIncreaseProcessingProps) =>
  render(<Wrapper {...props} />);

const mockProps = { period: 20000, };

describe('Wrapper Tests', () => {
  let asFragment;
  let getByText;

  beforeEach(() => {
    const _ = {asFragment, getByText} = getRenderResult(mockProps);
    jest.useFakeTimers();
  });

  afterEach(() => {
      jest.useRealTimers();
      jest.clearAllMocks();
  });

  it('should match the screenshot', () => {
    expect(asFragment()).toMatchSnapshot();
  });

  it('should render the ProgressBar', () => {
    getByText('ProgressBar');
  });

  it('should update the ProgressBar correctly', () => {
    jest.advanceTimersByTime(INCREMENT * 5)
    expect(ProgressBar).toHaveBeenCalledWith({now: 25});
  });
});

The basic idea is that after INCREMENT * 5 interval, the now prop calculates out to 25(%) considering that the period is 20 times the INCREMENT. In simpler terms, 5 seconds is 25 % of 20 seconds.

The Wrapper works as expected. But the tests fail, complaining that, though it expects 25, it receives a value of 0.

What am I missing?

0

There are 0 best solutions below