React - How to get unit test coverage for toggling open a popover that uses state or determine if it should be open

Viewed 30

I'm trying to get unit test coverage for the code in red (see screenshot) using react-testing-library. Would anyone know what unit test would cover this? I'm still learning the react-testing-library. TIA

screenshot of code here showing red, uncovered code

If you don't open the screenshot above, the code inside this function is what needs to be covered.

 const togglePopover = () => {
    setToolTipOpen((prev) => !prev);
  };

actual full component code block:

import React, { FunctionComponent, useState, KeyboardEvent, useRef, useEffect } from 'react';
import styles from './InfoPopover.module.scss';
import { Popover, PopoverBody } from 'x'
import { PopperPlacementType } from '@material-ui/core';
import { ReactComponent as InfoIcon } from '../../../assets/icons/tooltipIcon.svg';

export interface PopperProps {
  placement?: PopperPlacementType;
  tipMessage: React.ReactNode | string;
  stringedTipMessage: string;
}

const InfoPopover: FunctionComponent<PopperProps> = ({
  placement,
  tipMessage,
  stringedTipMessage
}: PopperProps) => {
  const [toolTipOpen, setToolTipOpen] = useState(false);

  const togglePopover = () => {
    setToolTipOpen((prev) => !prev);
  };

  const handleBlur = () => {
    setToolTipOpen(false);
  };

  return (
    <>
      <button
        id="popoverTarget"
        className={styles.tooltipButton}
        onBlur={handleBlur}
        aria-label={`Tooltip Content - ${stringedTipMessage}`}
      >
        <InfoIcon aria-label="status tooltip" />
      </button>
      <Popover
        target="popoverTarget"
        trigger="legacy"
        toggle={togglePopover}
        placement={placement}
        isOpen={toolTipOpen}
        arrowClassName={styles.toolTipArrow}
        popperClassName={styles.toolTipPopout}
      >
        <PopoverBody>{tipMessage}</PopoverBody>
      </Popover>
    </>
  );
};
export default InfoPopover;
1 Answers

With React Testing Library, the approach is to test what the user can see/do rather than test the internals of your application.

With your example, assuming you are trying to test a simple open/close popup user flow then the user would be seeing a button, and when they activate that button they would see a popover. A simple RTL approach would be as follows:


const popoverTipMessage = "My popover message";

render(<InfoPopover tipMessage={popoverTipMessage} />);

// Popover isn't activated, so it shouldn't be in the DOM
expect(screen.getByText(popoverTipMessage)).not.toBeInDocument();

// Find button and click it to show the Popover
fireEvent.click(screen.getByRole('button', {
  name: /tooltip content/i
}));

// Popover should now be activated, so check if it's visible (in the DOM)
await waitFor(() => { 
   // This relies on RTL's text matching to find the component.
   expect(screen.getByText(popoverTipMessage)).toBeInDocument();
});

// Find button and click it again to hide the Popover
fireEvent.click(screen.getByRole('button', {
  name: /tooltip content/i
}));


// Popover should now be hidden, so check if the DOM element has gone
// Note: There are other ways of checking appearance/disappearance. Check the RTL docs.
await waitFor(() => { 
   // This relies on RTL's text matching to find the component but there are other better ways to find an element
   expect(screen.getByText(popoverTipMessage)).not.toBeInDocument();
});

The query methods I've used above are some of the basic ones, however RTL has many different queries to find the element you need to target. It has accessibility at the forefront of its design so leans heavily on these. Take a look in the docs: https://testing-library.com/docs/react-testing-library/example-intro

Related