O hirunewani blog

Q. ローカル環境でのE2EテストがReactDevOverlayにより失敗する

Created at

Next.jsを利用したサービスでPlaywrightテストをローカル実行する際に、ReactDevOverlayを非表示する方法について

状況

Next.jsを利用したサービスで動作確認のためにPlaywrightテストをローカル環境で実行したところ、Hydration ErrorによりReactDevOverlayが表示され、テストが失敗するという報告があった。

ReactDevOverlayとは

Next.jsアプリをローカルで開発している際に、エラーが発生すると表示されるモーダルはReactDevOverlayと呼ばれている。

https://www.npmjs.com/package/@next/react-dev-overlay

これの存在意義については、CRAのissueで言及されている。

https://github.com/facebook/create-react-app/issues/6530#issuecomment-662914362

また、ReactDevOverlayを無効にしない理由として上記のissueがNext.jsのメンテナに引用されている。

https://github.com/vercel/next.js/discussions/23970#discussioncomment-599510

つまり、Next.jsはReactDevOverlayを無効にする機能を提供していない。

解決案

次にあげている手法を安直に適用すると、通常の開発時にも影響があるため注意。

ReactDevOverlayを非表示にする

Next.jsで表示されるReactDevOverlayは、nextjs-portalというweb componentが実体のため、これを非表示にすればReactDevOverlayを無効化することが出来る。

nextjs-portal {
  display: none;
}

Next.jsは、next.config.jsなどでReactDevOverlayを無効にする機能を提供していない。

Hydration Errorを無効にする

Reactでは、suppressHydrationWarningを指定することで、その配下で発生するHydration Errorを無効にすることができる。

<div suppressHydrationWarning={true}>
  Current Date: {new Date().toLocaleDateString()}
</div>

雑に無効化したいのであれば、suppressHydrationWarningをhtml要素やbody要素に指定してしまえばいい。 ただし、本来suppressHydrationWarningはHydration Errorを避けることが困難な状況においてのみ限定的に利用するのが望ましい。

https://ja.react.dev/reference/react-dom/client/hydrateRoot#suppressing-unavoidable-hydration-mismatch-errors

解決案の応用例

通常の開発時にもReactDevOverlayが表示されなくなることは好ましくないため、E2Eテストの実行時のみ適用されるのが望ましい。

E2Eテスト実行時のみReactDevOverlayを非表示にする

Next.jsのPage Routerであれば_app.js、App Routerであればlayout.jsなどで、環境変数を参照してReactDevOverlayを非表示にする。

{
  process.env.E2E ? (
    <style>
      {`
        nextjs-portal {
          display: none;
        }
      `}
    </style>
  ) : null;
}

E2Eテスト実行時のみHydration Errorを無効にする

環境変数を参照して、suppressHydrationWarningを指定することでHydration Errorを無効にする。

return (
  <html lang="ja">
    <body suppressHydrationWarning={process.env.E2E ? true : false}>
      {children}
    </body>
  </html>
);

PlaywrightでReactDevOverlayを非表示にする

ページ遷移後に、実行する必要がある点に注意。

await page.goto("http://localhost:3000");
await page.addStyleTag({
  content: `
    nextjs-portal {
      display: none;
    }`,
});

PlaywrightでHydration Errorを無効にする

ページ遷移後に、実行する必要がある点に注意。

await page.goto("http://localhost:3000");
await page.evaluate(() => {
  const body = document.querySelector("body");
  body.setAttribute("suppressHydrationWarning", "true");
});