jest-dom: toBeVisible () возвращает true, когда должен возвращать false - PullRequest
1 голос
/ 20 мая 2019

Подобный вопрос здесь - Невозможно проверить, ожидают (вяз) .not.toBeVisible () для компонента семантического интерфейса реакции - однако ответ предполагает, что это должно работать для CSS-in-JS, который что я использую.

Я использую компонент Material-UI <Hidden>, чтобы отображать только текст на экранах sm и выше. Вот код (который отлично работает в производстве):

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

Я использую jest-dom с react-testing-library и пытаюсь проверить отзывчивость моей панели навигации, которая содержит этот скрытый текст.

У меня есть следующий тест:

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());
  });
});

Первые 2 теста делают снимок экрана, и когда я смотрю на снимок экрана, я вижу, что текст логотипа не виден:

И когда я просматриваю DOM в браузере с размером xs, я вижу, что родительский компонент действительно скрыт: https://i.imgur.com/TfBpePV.png

Тем не менее, когда я запускаю тест, он не проходит и говорит, что элемент видим:

  ● 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" />

Если я добавлю console.log(innerWidth) перед expect(), он вернет правильную ширину, поэтому проблема не в том, что jsdom выполняет рендеринг с неправильной шириной экрана.

Кроме того, если я изменю реализацию компонента <Hidden> с CSS на JS, он будет работать нормально (поскольку элемент полностью удален из документа с использованием JS, а не просто скрыт с помощью медиазапросов).

Как это исправить, чтобы заставить его работать?

...