7

Similar question here - Cannot check expect(elm).not.toBeVisible() for semantic-ui react component - however the answer suggests that this should be working for CSS-in-JS, which is what I'm using.

I'm using Material-UI's <Hidden> component to only display some text on sm screen sizes and up. Here's the code (that works perfectly in production):

<Hidden implementation="css" xsDown>
  <LogoText variant="h5" component="p" />
</Hidden>

I'm using jest-dom with react-testing-library and am trying to test the responsiveness of my navigation bar, which contains this hidden text.

I have the following test:

const initTest = width => {
  Object.defineProperty(window, "innerWidth", {
    writable: true,
    configurable: true,
    value: width
  });
  window.matchMedia = jest.fn().mockImplementation(
    query => {
      return {
        matches: width >= theme.breakpoints.values.sm ? true : false,
        media: query,
        onchange: null,
        addListener: jest.fn(),
        removeListener: jest.fn()
      };
    }
  );
  const height = Math.round((width * 9) / 16);
  return { width, height };
};

describe("Unit: <Navbar> On xs screens", () => {
  it("renders as snapshot at minimum size", async () => {
    const { width, height } = initTest(320);
    const { asFragment, rerender } = render(
      <Container backgroundColor={"#ffffff"}>
        <Navbar />
      </Container>
    );
    rerender(
      <Container backgroundColor={"#ffffff"}>
        <Navbar />
      </Container>
    );
    expect(asFragment()).toMatchSnapshot();
    const screenshot = await generateImage({
      viewport: { width, height }
    });
    expect(screenshot).toMatchImageSnapshot();
  });

  it("renders as snapshot at maximum size", async () => {
    const { width, height } = initTest(theme.breakpoints.values.sm - 1);
    const { asFragment, rerender } = render(
      <Container backgroundColor={"#ffffff"}>
        <Navbar />
      </Container>
    );
    rerender(
      <Container backgroundColor={"#ffffff"}>
        <Navbar />
      </Container>
    );
    expect(asFragment()).toMatchSnapshot();
    const screenshot = await generateImage({
      viewport: { width, height }
    });
    expect(screenshot).toMatchImageSnapshot();
  });

  it("hides logo text", async () => {
    initTest(theme.breakpoints.values.sm - 1);
    const { rerender, getByText } = render(
      <Container backgroundColor={"#ffffff"}>
        <Navbar />
      </Container>
    );
    rerender(
      <Container backgroundColor={"#ffffff"}>
        <Navbar />
      </Container>
    );
    await wait(() => expect(getByText("LOGO TEXT")).not.toBeVisible());
  });
});

The first 2 tests take a screenshot and when I look at the screenshot, I can see that the logo text is not visible:

And when I view the DOM in the browser at xs size, I see that the parent component is indeed hidden: https://i.stack.imgur.com/b7kbU.png

Yet when I run the test it fails and says that the element is visible:

  ● Unit: <Navbar> On xs screens › hides logo text

    expect(element).not.toBeVisible()

    Received element is visible:
      <p class="MuiTypography-root MuiTypography-h5 makeStyles-typography-237" />

If I add in a console.log(innerWidth) before the expect() then it returns the correct width, so the issue isn't that jsdom is rendering at the wrong screen width.

Also, if I change the implementation of the <Hidden> component from CSS to JS, it works fine (as the element is completely taken out of the document using JS instead of just being hidden using media queries).

How do I fix this to get it to work?

Jake
  • 3,865
  • 5
  • 25
  • 58
  • the answer of the other SO thread shares that maybe the styling is out of scope and should be embedded in the test directly that the test registers that the element is display: none - did you try that? – Felix Haeberle May 20 '19 at 00:09
  • I'm not sure how to do that since it's CSS-in-JS. Here's the CSS for the `` component: https://github.com/mui-org/material-ui/blob/master/packages/material-ui/src/Hidden/HiddenCss.js – Jake May 20 '19 at 00:16
  • @Jake did you find a solution for this? My guess is that jest doesn't do the "full flow" with css that browser is normally doing so media queries in css are ignored. If you try to test some element with display none without media query, you will see that it works with not.toBeVisible from testing-library/jest-dom – jbojcic Feb 16 '20 at 18:34

0 Answers0