HYUDORO

勉強したことや日記など

next/headの導入

それなりに大きなNext.jsのプロジェクトにnext/headを導入するにあたってやったことなどのメモ。

共通Headコンポーネント

下記では色々と簡略化してるけど、各ページ共通で使うtitleやmetaタグなどをまとめてprops経由で設定できるようにする。

// Head.tsx

import NextHead from 'next/head';

export type Props = {
  title: string;
  description?: string;
};

export const Head = ({ title, description = 'Test description' }: Props): JSX.Element => {
  return (
    <NextHead>
      <title>{title}</title>
      <meta property="description" content={description} />
    </NextHead>
  );
};

<Head title="Test" />的な感じで利用できる。

参考にしたのは下記のページ。

t-cr.jp

テスト

Jest + React Testing Libraryを利用しており、単にHeadコンポーネントrenderしてもbodyタグしか表示されないので、少し工夫する必要があった。結果が下記のコード。

import { render } from '@testing-library/react';
import { Head } from '../';

jest.mock('next/head', () => 'Head');

describe('Head', () => {
  it('default', () => {
    render(<Head title="Test title" />, {
      container: document.head,
    });
    expect(document.title).toBe('Test title');
    expect(
      document
        .querySelector("meta[property='description']")
        ?.attributes.getNamedItem('content')?.value
    ).toBe('Test description');
  });
});

zenn.dev

こちらのページを参考にした。next/headをモックする必要があり、最初は参考ページと同じコードを書いてみた。

jest.mock('next/head', () => {
  return {
    __esModule: true,
    default: ({ children }: { children: Array<React.ReactElement> }) => {
      return <>{children}</>;
    },
  };
});

この方法だと、自分の環境ではテスト実行時にbabel関連の参照エラーが発生してしまった。

ReferenceError: /dev/head/__tests__/head.test.tsx: The module factory of `jest.mock()` is not allowed to reference any out-of-scope variables.
    Invalid variable access: jsx_runtime_1
    ...
    Note: This is a precaution to guard against uninitialized mock variables. If it is ensured that the mock is required lazily, variable names prefixed with `mock` (case insensitive) are permitted.

       6 |         __esModule: true,
       7 |         default: ({ children }) => {
    >  8 |             return (0, jsx_runtime_1.jsx)(jsx_runtime_1.Fragment, { children: children }, void 0);
         |                        ^^^^^^^^^^^^^
       9 |         },
      10 |     };
      11 | });

...

いくらか調べてみたが、有効そうな解決方法が見当たらなかったので、シンプルにファクトリ関数にモジュール名を指定してみたところうまくモックができた。

なぜエラーが発生したのかについてはまだ詳しくわかってない。先ほどのコードでdoMockを試してみたら参照エラーは無くなったが、今度はrenderした結果が空だった...という経緯があった。


ひとまず、これで共通で使えるコンポーネントとテストができるようになった。やったぜ。