1

How can I test whether or not a React component is visible in the DOM when that component is hidden using a CSS transition with transform: scale(0)?

jest-dom has a .toBeVisible() matcher, but this doesn't work because transform: scale(0) is not one of the supported visible/hidden triggers. Per the docs:

An element is visible if all the following conditions are met:

  • it is present in the document
  • it does not have its css property display set to none
  • it does not have its css property visibility set to either hidden or collapse
  • it does not have its css property opacity set to 0
  • its parent element is also visible (and so on up to the top of the DOM tree)
  • it does not have the hidden attribute
  • if <details /> it has the open attribute

I am not using the hidden attribute because it interfered with my transition animations. I am using aria-hidden, but that is also not one of the supported triggers.

The simplified version of my component is basically this. I am using Tailwind CSS for the transform and the transition.

import React from "react";
import clsx from "clsx";

const MyComponent = ({isSelected = true, text}) => (
  <div
    className={clsx(
      isSelected ? "transform scale-1" : "transform scale-0",
      "transition-all duration-500"
    )}
    aria-hidden={!isSelected}
  >
     <span>{text}</span>
  </div>
)

I could potentially check for hidden elements with:

  • toHaveClass("scale-0")
  • toHaveAttribute("aria-hidden", true)

But unlike toBeVisible, which evaluates the entire parent tree, these matchers only look at the element itself.

If I use getByText from react-testing-library then I am accessing the <span> inside the <div> rather than the <div> which I want to be examining. So this doesn't work:

import React from "react";
import { render } from "@testing-library/react";
import "@testing-library/jest-dom/extend-expect";
import { MyComponent } from "./MyComponent";

it("is visible when isSelected={true}", () => {
  const {getByText} = render(
    <MyComponent
      isSelected={true}
      text="Hello World"
    />
  );
  expect(getByText("Hello World")).toHaveClass("scale-1");
});

What's the best way to approach this?

Linda Paiste
  • 38,446
  • 6
  • 64
  • 102
  • I ended up using `getByTestId` and `toHaveClass` but this feels really hacky and I'd love to know if there's a better solution. Like a way to extend `toBeVisible`? I did `expect(getByTestId("prefix-Hello World")).toHaveClass("scale-1");` – Linda Paiste Jun 15 '21 at 00:57
  • Does this answer your question? [Cannot check expect(elm).not.toBeVisible() for semantic-ui react component](https://stackoverflow.com/questions/52813527/cannot-check-expectelm-not-tobevisible-for-semantic-ui-react-component) – Liam Jul 08 '22 at 10:39
  • @Liam that's definitely related, but even if all styles are loaded and interpreted properly there is still a problem because `transform: scale(0)` is not considered to be "hidden" (unlike the `display: none` in that question). – Linda Paiste Jul 08 '22 at 18:44
  • 1
    I believe the issue you're experiencing here is related to [this question](https://stackoverflow.com/questions/52813527/cannot-check-expectelm-not-tobevisible-for-semantic-ui-react-component). My understanding is the problem isn't so much that the effective visibility calculation is wrong, but that tailwind's CSS isn't being included in the jsdom document. – Dennis Feb 09 '22 at 21:59

0 Answers0