How do I test for a tooltip appearing on hover in recharts x react testing library x vitest?

1.4k Views Asked by At

I'm trying to write a test and can't work out why my hover isn't working. The full code is here. I have a recharts chart element, which renders, is responsive, and shows a tooltip containing the expected data (here, amino acid name and ratio of total provided sequence, eg: 'A: 0.06') on hover over any bar:

import { useStore } from '@nanostores/react';
import { countAminoAcids } from '../../../functions/utilFunctions/countAminoAcids';
import { inputStore } from '../../../stores/input';
import type { InputLabelProps } from '../../../types';
import {
  ResponsiveContainer,
  BarChart,
  Bar,
  CartesianGrid,
  XAxis,
  YAxis,
  Tooltip,
} from 'recharts';
import { CountAminoAcidsTooltip } from './CountAminoAcidsTooltip';

export default function CountAminoAcids({
  ariaLabelContent,
}: InputLabelProps) {
  const sanitisedInputFromStore = useStore(inputStore);
  const resiCounts = countAminoAcids(sanitisedInputFromStore);
  const resiCountsArray = Object.entries(resiCounts).map(
    ([key, value]) => {
      // add the key to the value
      return { ...value, key };
    }
  );

  // remove total from resiCountsArray
  const individualResiCountsArray = resiCountsArray.slice(0, -1);
  return (
    <ResponsiveContainer aria-label={ariaLabelContent}>
      <BarChart
        className="proteinBar"
        data={individualResiCountsArray}
      >
        <CartesianGrid strokeDasharray="3 3" />
        <YAxis
          dataKey="ratio"
          tick={{ fill: 'hsl(42, 100%, 50%)' }}
        />
        <XAxis dataKey="key" tick={{ fill: 'hsl(42, 100%, 50%)' }} />
        <Bar dataKey="ratio" fill="hsl(42, 100%, 50%)" />
        <Tooltip
          wrapperStyle={{
            outline: 'none',
          }}
          content={<CountAminoAcidsTooltip />}
        />
      </BarChart>
    </ResponsiveContainer>
  );
}

I have tests passing for the error message I've encoded when an invalid protein sequence is entered, and for the Y Axis rendering the expected values when a known protein is input. I also have a sample tooltip test from freecodecamp working perfectly, so I know I have react testing library and userEvent.hover working correctly. However, mine always fails. I patterned my test on this post. I think I have the correct document.querySelectorAll as I get the expected NodeList of 20 items when I run in Chrome's console. Where am I going wrong??

// protParams.test.tsx
// MPKCPKCNKEVYFAERVTSLGKDWHRPCLKCEKCGKTLTSGGHAEHEGKPYCNHPCYAAMFGPKGFGRGGAESHTFK

import { describe, test, expect, vi } from 'vitest';
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
// import modules to test
import { Molecule } from '../../src/types';
import Input from '../../src/components/react/Input';
import CountAminoAcids from '../../src/components/react/protein/CountAminoAcids';
import ProteinParameters from '../../src/components/react/protein/ProteinParameters';
import type { ResponsiveContainerProps } from 'recharts';

vi.mock('recharts', async () => {
  const mockRecharts = await vi.importActual<any>('recharts');
  return {
    ...mockRecharts,
    ResponsiveContainer: ({ children }: ResponsiveContainerProps) => (
      <mockRecharts.ResponsiveContainer width={800} height={800}>
        {children}
      </mockRecharts.ResponsiveContainer>
    ),
  };
});

describe('test amino acid counting', () => {
  const user = userEvent.setup();
  let inputBox: HTMLElement;
  // reset input after each test
  beforeEach(() => {
    render(
      <Input
        ariaLabelContent={'DNA input form for Protein parameters'}
        placeholderText={'Enter DNA sequence here...'}
        inputType={Molecule.Protein}
      />
    );
    inputBox = screen.getByLabelText(
      'DNA input form for Protein parameters'
    );
  });

  // two passing tests omitted

  test('test tooltip on hover', async () => {
    // define input
    const dna =
      'MPKCPKCNKEVYFAERVTSLGKDWHRPCLKCEKCGKTLTSGGHAEHEGKPYCNHPCYAAMFGPKGFGRGGAESHTFK';

    // enter DNA into input box
    await user.type(inputBox, dna);
    expect(inputBox).toHaveValue(dna);
    // render output
    render(<CountAminoAcids ariaLabelContent={'Amino acid count'} />);


    const bars = document.querySelectorAll('.recharts-layer.recharts-bar-rectangle');

    // expected output
    await userEvent.hover(bars[0]);

    // test
    expect(screen.getByText('A: 0.06'));
  });
});

I have tried a different selector for bars (const bars = document.querySelectorAll('.recharts-bar-rectangle');) with the same result

1

There are 1 best solutions below

1
Ben Smith On

Try changing the last line in your test to:

expect(await screen.findByText('A: 0.06'))

As the appearance of the tooltip is an asynchronous event you need your test to wait for it to appear (findBy functions are a combination of getBy queries and waitFor, see here).