Zenn
🌈

next.jsでフルスタック開発をしている場合のvitest.configについて

2025/01/11に公開

課題

元々実装でバックエンド中心に実装をしていた。react-testing-libraryを入れて簡単なテストを実行した。

index.test.tsx
import { render, screen } from '@testing-library/react'
import '@testing-library/jest-dom'
import { test } from 'vitest'
import { BottomNavigation } from '@/components/template/BottomNavigation'

test('loads and displays greeting', ({ expect }) => {
  render(<BottomNavigation />)
  expect(screen.getByRole('link')).toHaveTextContent('ムーブ')
})

すると下記のようなエラーが出た。

documentがないということで、vitest.config.tsを確認する。
environmentのvprismaがnode前提になっているからのようだ。

vitest.config.ts
/// <reference types="vitest" />
import { defineConfig } from 'vitest/config'
import react from '@vitejs/plugin-react'
// biome-ignore lint/correctness/noNodejsModules: <explanation>
import { resolve } from 'node:path'

export default defineConfig({
  plugins: [react()],
  test: {
    include: ['./src/**/*.test.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
    globals: true,
    environment: 'vprisma',
    setupFiles: ['vitest-environment-vprisma/setup', './src/test/vitest.setup.ts'],
    env: {
      POSTGRES_PRISMA_URL: 'postgresql://root:password@localhost:5436/database_name?schema=public',
    },
  },
  resolve: {
    alias: [{ find: '@', replacement: resolve(__dirname, './src') }],
  },
})

テスト方針は下記のように考えて実装をしていた。

  • 全体のユースケースのテストはplaywrightでe2eテストを行う
  • フロントエンドのclient側はReact Testing Library とvitestを使ってテスト
    • server actionsを使う場合にデータベースとの接続部分をモックしたりする必要が出てくるので使わない。
  • バックエンドはprismaを使ったテストを行う想定。

解決方法

そこで一つのファイルでnode環境とjsdomを使ったテストの両方をするのはどうかな?と考えて下記のようにファイルを分けた。

vitest.client.config.ts
/// <reference types="vitest" />
import { defineConfig } from 'vitest/config'
import react from '@vitejs/plugin-react'
// biome-ignore lint/correctness/noNodejsModules: <explanation>
import { resolve } from 'node:path'

export default defineConfig({
  plugins: [react()],

  test: {
    include: ['./src/**/*.test.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
    exclude: ['./src/server/**/*.test.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
    /** @link https://zenn.dev/nyatinte/articles/9ee2926895b83f */
    environment: 'jsdom',
    globals: true,
  },

  resolve: {
    alias: [{ find: '@', replacement: resolve(__dirname, './src') }],
  },
})

vitest.server.config.ts
/// <reference types="vitest" />
import { defineConfig } from 'vitest/config'
// biome-ignore lint/correctness/noNodejsModules: <explanation>
import { resolve } from 'node:path'

export default defineConfig({
  test: {
    include: ['./src/server/**/*.test.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'], // サーバー側の実装だけを対象にする。
    globals: true,
    environment: 'vprisma',
    setupFiles: ['vitest-environment-vprisma/setup', './src/test/vitest.setup.ts'],
    env: {
      POSTGRES_PRISMA_URL: 'postgresql://root:password@localhost:5432/?schema=public',
    },
  },
  resolve: {
    alias: [{ find: '@', replacement: resolve(__dirname, './src') }],
  },
})

下記のようにしてpackage.jsonでscriptsを指定をして実行した。

package.json
"scripts": {
  "test:unit": "vitest run -c vitest.server.config.ts && vitest run -c vitest.client.config.ts",
},

もしも一つのファイルで実行する場合、今回vprismaを扱っていることが原因であり、改めてgithubのコードを確認するとenvironmentOptions.vprisma.baseEnvで環境を指定できるようだった。

https://github.com/aiji42/vitest-environment-vprisma?tab=readme-ov-file#options

vitest.config.ts
/// <reference types="vitest" />
import { defineConfig } from 'vitest/config'
import react from '@vitejs/plugin-react'
// biome-ignore lint/correctness/noNodejsModules: <explanation>
import { resolve } from 'node:path'

export default defineConfig({
  plugins: [react()],
  test: {
    include: ['./src/**/*.test.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
    globals: true,
    environment: 'vprisma',
    setupFiles: ['vitest-environment-vprisma/setup', './src/test/vitest.setup.ts'],
    environmentOptions: {
      vprisma: {
        baseEnv: 'jsdom', // ここで指定
      },
    },
    env: {
      POSTGRES_PRISMA_URL: 'postgresql://root:password@localhost:5436/database_name?schema=public',
    },
  },
  resolve: {
    alias: [{ find: '@', replacement: resolve(__dirname, './src') }],
  },
})

これで成功をした。

最後に

最初は2つのファイルの分けた方がいいかな?と思いつつも、一つのファイルでserver側のコードとclient側のコードの両方が実行するようにしたが、Next.jsでフルスタック開発をする場合は、やはりファイルを分けて対応をした方がそれぞれでconfigを設定できるからいいかもしれない。

immedioテックブログ

Discussion

ログインするとコメントできます