Closed10

【key-front】react-testing-libraryの素振りをしてみた(後編)

1zushun1zushun

モチベーション

  • 毎週木曜日Slackのkey_frontチャンネルでハドル機能を使いお題に対してメンバー同士ディスカッションをする時間を15〜30分程度設けている
  • 今回は「react-testing-libraryを触ってみて(前編)」の後編を共有する
  • ファシリテーターは筆者なので、事前に読み込んで気になった点などをスクラップに投げていく
  • 開催日は10/26(木)で最終的に議事録として結論をまとめる

前編

https://zenn.dev/shuuuuuun/scraps/11262e3391599a

1zushun1zushun

jestにエイリアスを追加する

記事を参考にjestにもエイリアスを追加する。jestはVite経由で実行されないのが原因ぽい。

jest.config.json
{
  "roots": ["<rootDir>/resources/js"],
  "testMatch": [
    "**/__tests__/**/*.+(ts|tsx|js)",
    "**/?(*.)+(spec|test).+(ts|tsx|js)"
  ],
  "transform": {
    "^.+\\.(ts|tsx)$": "ts-jest"
  },
  "testEnvironment": "jest-environment-jsdom",
  "setupFilesAfterEnv": ["<rootDir>/jest.setup.ts"],
  "moduleNameMapper": {
    "^@/(.*)$": "<rootDir>/resources/js/$1" // 追加する
  }
}
import { render, screen } from '@testing-library/react'
import Test from '@/pages/Test' // エイリアスが有効になっている

describe('get by text', () => {
  it('get by text', () => {
    render(<Test />)
    const element = screen.getByText('Hello')
    expect(element).toBeInTheDocument()
  })
})

参考記事

https://www.asobou.co.jp/blog/web/rtl#Vitealiasjest

https://blog.mitsuruog.info/2019/06/jest-module-name-mapper

1zushun1zushun

MUIコンポーネントのユニットテストをする

paletteを使っている場合(Providerを使用している場合)は下記のように改修する必要がある

import { ThemeProvider } from '@mui/material/styles'
import { render, screen, fireEvent } from '@testing-library/react'
import { Button } from '@/components/uis/Button'
import { theme } from '@/functions/libs'

describe('Buttonコンポーネントのテスト', () => {
  it('正しくレンダリングされる', () => {
    render(
      <ThemeProvider theme={theme}> // 追加する
        <Button>Test</Button>
      </ThemeProvider>
    )

    const buttonElement = screen.getByRole('button')
    expect(buttonElement).toBeInTheDocument()
  })
})

参考記事

https://qreat.tech/5309/


しかし、このままだとテストを作るたびにButtonコンポーネントにProviderをラップさせる必要がある。記事を参考にrender関数をオーバーライドさせる。

import { render, screen, fireEvent } from '@/__tests__/utilities/test-utils'
import { Button } from '@/components/uis/Button'

describe('Buttonコンポーネントのテスト', () => {
  it('正しくレンダリングされる', () => {
    render(<Button>Test</Button>)

    const buttonElement = screen.getByRole('button')
    expect(buttonElement).toBeInTheDocument()
  })
})

参考記事

https://zenn.dev/spacemarket/articles/jest-unit-testing-tips#custom-render関数を作る

https://testing-library.com/docs/react-testing-library/setup/#custom-render

1zushun1zushun

特定のディレクトリをignoreする

先ほど作ったcustom-renderをテストの対象外にする

jest.config.json
module.exports = {
  "testPathIgnorePatterns": ["<rootDir>/resources/js/__tests__/utilities"],
}
1zushun1zushun

SVGファイルを読み込めるようにする

記事を参考に実装する。jest-svg-transformerとかライブラリは使わなくてok。

fileTransformer.js
const path = require('path');

module.exports = {
  process(sourceText, sourcePath, options) {
    return {
      code: `module.exports = ${JSON.stringify(path.basename(sourcePath))};`,
    };
  },
};
jest.config.json
module.exports = {
  "transform": {
    "\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "<rootDir>/fileTransformer.js"
  },
}

https://jestjs.io/docs/code-transformation#examples

1zushun1zushun

userEventをcustomRenderに組み込む

下記を多用するのでどうにかしたい

import userEvent from '@testing-library/user-event'

const user = userEvent.setup()

ドキュメントを見るとrenderに組み込む実装が案内されているので、先ほどのcustomRenderに組み込む

import { ThemeProvider } from '@mui/material/styles'
import { render, RenderOptions } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import { theme } from '@/functions/libs'

const AllTheProviders = ({ children }: { children: React.ReactNode }) => {
  return <ThemeProvider theme={theme}>{children}</ThemeProvider>
}

const customRender = (
  ui: React.ReactElement,
  options?: Omit<RenderOptions, 'wrapper'>
) => {
  return {
    user: userEvent.setup(),
    ...render(ui, { wrapper: AllTheProviders, ...options })
  }
}

// re-export everything
export * from '@testing-library/react'

// override render method
export { customRender as render }

https://testing-library.com/docs/user-event/intro/#writing-tests-with-userevent


補足

次の記事が全く考えで同じことを実装していたのでメモ

補足内容としてはuserEventがv14から実装が微妙に異なる。react-testing-libraryに関する記事も古いものが見受けられるので注意。

import userEvent from '@testing-library/user-event';

// v14以前
userEvent.click(button);

// v14移行
const user = userEvent.setup();
await user.click(button);

https://www.linkedin.com/pulse/how-use-user-event14-when-writing-tests-your-react-components-johal


さらに補足

RTLではfireEventよりuserEventを使った方が良いメモ

https://zenn.dev/tnyo43/scraps/6d15ee29867b7e

1zushun1zushun

議事録_20231026

  • 10/26(木)に実施
  • 参加人数は11名(以下エビデンス)
    • 4ヶ月続けて初の参加者10人越えだったので素直に嬉しかった。

  • テスト経験者は3名ほどしかいなくどうしても受託会社という側面があるので、テストより実装を優先して欲しいと先方から言われることがある
  • そもそもフロントのリソースが足りなくテストまで余力がない
  • 案件によってはテストを実施しているものもあるので一概にテストを軽視しているわけではない
  • 結論としては品質の良いものを納品する=テストで品質担保は直結するので基盤開発周りのテンプレートを作って実装までのショートカットを作れば良いのではという形に落ち着いた

TODO

  • Reactでテストをするための技術選定を行う
  • テストのテンプレートを作る
このスクラップは2023/10/26にクローズされました