visible true

技術的なメモを書く

Material-UIのHidden要素をテストする

個人のプロジェクトでMaterial-UIを使っているんですが、 コンポーネントHiddenを含んでいると、テストがうまく動きません。

hoge.tsx

import * as React from 'react';
import {Hidden} from "@material-ui/core";

export const Hoge = (): JSX.Element => {
  return (
    <div>
      <Hidden mdUp>
        <div>mdUp</div>
      </Hidden>
      <Hidden smDown>
        <div>smDown</div>
      </Hidden>
    </div>
  )
};

hoge.test.tsx

import React from "react";
import {render, cleanup} from '@testing-library/react'
import {Hoge} from "../hoge";

afterEach(async () => {
  await cleanup();
});

describe('hoge', () => {
  describe('ある幅以上の時のレンダリング', () => {
    it('mdUpが表示される', () => {
      const {getByText} = render(
          <Hoge/>
      );
      expect(getByText("mdUp")).toBeVisible()
    });
  });
});

見つけられない...ていうかそもそもHidden要素がどっちもレンダリングされていない

TestingLibraryElementError: Unable to find an element with the text: mdUp. This could be because the text is broken up by multiple elements. In this case, you can provide a function for your text matcher to make your matcher more flexible.

    <body>
      <div>
        <div />
      </div>
    </body>

      13 |           <Hoge/>
      14 |       );
    > 15 |       expect(getByText("mdUp")).toBeVisible()
         |              ^
      16 |     });
      17 |   });
      18 | });

環境

"@material-ui/core": "^4.10.2",
"react": "^16.13.1",
    
"@testing-library/dom": "^7.16.3",
"@testing-library/jest-dom": "^5.10.1",
"@testing-library/react": "^10.3.0",
"@testing-library/user-event": "^12.0.7"

原因など

Unable to test React with Material-UI Hidden element · Issue #2179 · enzymejs/enzyme · GitHub によると、jest-domとmaterial-uiの双方に課題があるようです。 -> https://github.com/enzymejs/enzyme/issues/2179#issuecomment-528973289

対応

対応方法は2つほどあるぽいです、ここではかんたんな方を書きます。 テスト側でrenderするときにcreateMuiThemeを用いて初期の画面幅を指定するやりかたです。

import React from "react";
import {render, cleanup} from '@testing-library/react'
import {createMuiTheme, MuiThemeProvider} from "@material-ui/core";
import {Hoge} from "../hoge";

afterEach(async () => {
  await cleanup();
});

describe('hoge', () => {
  describe('ある幅以上の時のレンダリング', () => {
    it('mdUpが表示される', () => {
      const theme = createMuiTheme({props: {MuiWithWidth: {initialWidth: 'sm'}}})
      const {getByText} = render(
        <MuiThemeProvider theme={theme}>
          <Hoge/>
        </MuiThemeProvider>
      );
      expect(getByText("mdUp")).toBeVisible()
    });
  });
});

これで画面幅を指定して実行できます。 initialWidthをmdにするとsmDownの方の要素が表示状態になります。

おわりに

ReactでTDDでやっていくぞと思って触り始めたけどやはりUI部分はなかなか大変だなと思いつつ、Androidよりは楽かもという気持ち