vitest+reactでreact-error-boundryによってフォールバック画面が表示されるかテストする

2023/06/20に公開

はじめに

bulletproof-reactに従ってwebアプリを作ったのですが、vitestでエラーフォールバック画面のテストを書くのに死ぬほど苦労したので後続の方のために記事を残します
ためになったらハート下さい(乞食)

テスト対象コンポーネント

App.tsx
import {AppProvider} from "@/providers/app.tsx"
import {ArticleList} from "@/features/article"

const App = () => {
  return (
    <AppProvider>
      {/* 省略 */}  
      <ArticleList/>
      {/* 省略 */}
    </AppProvider>
  )
}

export default App

エラーハンドリング

テスト対象のAppはAppProviderでエラーハンドリングしています

app.tsx
export const AppProvider: FC<Props> = (props) => {
  return (
    <ErrorBoundary FallbackComponent={<div>Something went wrong.</div>}>
      {props.children}
    </ErrorBoundary>
  )
}

テスト実装

App.test.tsx
import App from "./App"
import {ArticleList} from "@/features/article"
import {render, screen} from "@testing-library/react"

vi.mock("@/features/article", async () => {
  const actual = await vi.importActual("@/features/article") as object

  return {
    ...actual,
    ArticleList: vi.fn(() => <AritcleList/>)
  }
})
const mockedArticleList = ArticleList as jest.Mock

describe("App", () => {
  beforeEach(() => {
    vi.resetAllMocks()
  })

  test("エラー発生時フォールバック画面を表示する", () => {
    mockedArticleList.mockImplementation(() => {throw new Error("test error")})

    render(<App/>)

    expect(screen.getByText("Something went wrong.")).toBeInTheDocument()
  })

解説

"@/features/article"というパスでimportされるすべての関数をモックしています
ただし、ArticleList以外は実際の関数を返しています
ArticleListは実行されるとデフォルトでは本来のコンポーネントを返すモック関数になっています

vi.mock("@/features/article", async () => {
  const actual = await vi.importActual("@/features/article") as object

  return {
    ...actual,
    ArticleList: vi.fn(() => <AritcleList/>)
  }
})

このテストに限りArticleListをレンダリングしようとするとエラーが発生するようにします

mockedArticleList.mockImplementation(() => {throw new Error("test error")})

こうすることで他のテストではArticleListの状態を気にする必要がなくなります

結果

成功!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

最後に

jestの古臭すぎる所が嫌でvitestを使ってみたのですが、新しすぎるが故にChatGPTが使い物にならなかったりして死ぬほどめちゃくちゃ大変でした
皆でvitestを盛り上げよう!!!!!!!!!!!!!!!!!!!!!!!!

Discussion