nuxt logo

ドキュメント翻訳(非公式)

テスト

Nuxtアプリケーションのテスト方法。

If you are a module author, you can find more specific information in the Module Author's guide.

Nuxtは、@nuxt/test-utilsを通じて、Nuxtアプリケーションのエンドツーエンドテストとユニットテストを第一級のサポートを提供します。これはテストユーティリティと設定のライブラリで、現在Nuxt自体で使用しているテストとモジュールエコシステム全体のテストを動力しています。

インストール

他のテスト依存関係を管理できるようにするために、@nuxt/test-utilsはさまざまなオプションのピア依存関係を提供しています。例えば:

  • Nuxt環境のランタイムにはhappy-domjsdomの間で選択できます
  • エンドツーエンドテストランナーにはvitestcucumberjestplaywrightの間で選択できます
  • playwright-coreは、組み込みのブラウザテストユーティリティを使用したい場合にのみ必要です(そして@playwright/testをテストランナーとして使用していない場合)
npm i --save-dev @nuxt/test-utils vitest @vue/test-utils happy-dom playwright-core

ユニットテスト

現在、Nuxtランタイム環境が必要なコードのユニットテスト環境を提供しています。現在、vitestのみをサポートしています(他のランタイムを追加する貢献は歓迎されます)。

セットアップ

  1. @nuxt/test-utils/modulenuxt.configファイルに追加します(オプション)。これにより、開発中にユニットテストを実行するためのVitest統合がNuxt DevToolsに追加されます。

    export default defineNuxtConfig({
      modules: [
        '@nuxt/test-utils/module'
      ]
    })
    
  2. 次の内容でvitest.config.tsを作成します:

    import { defineVitestConfig } from '@nuxt/test-utils/config'
    
    export default defineVitestConfig({
      // any custom Vitest config you require
    })
    

When importing @nuxt/test-utils in your vitest config, It is necessary to have "type": "module" specified in your package.json or rename your vitest config file appropriately.

ie. vitest.config.m{ts,js}.

It is possible to set environment variables for testing by using the .env.test file.

Nuxtランタイム環境の使用

デフォルトでは、@nuxt/test-utilsはデフォルトのVitest環境を変更しませんので、細かいオプトインを行い、他のユニットテストと一緒にNuxtテストを実行することができます。

テストファイルの名前に.nuxt.を追加する(例:my-file.nuxt.test.tsまたはmy-file.nuxt.spec.ts)か、テストファイル内に直接@vitest-environment nuxtというコメントを追加することで、Nuxt環境をオプトインできます。

// @vitest-environment nuxt
import { test } from 'vitest'

test('my test', () => {
  // ... test with Nuxt environment!
})

また、Vitest設定でenvironment: 'nuxt'を設定することで、すべてのテストにNuxt環境を有効にすることができます。

// vitest.config.ts
import { fileURLToPath } from 'node:url'
import { defineVitestConfig } from '@nuxt/test-utils/config'

export default defineVitestConfig({
  test: {
    environment: 'nuxt',
    // you can optionally set Nuxt-specific environment options
    // environmentOptions: {
    //   nuxt: {
    //     rootDir: fileURLToPath(new URL('./playground', import.meta.url)),
    //     domEnvironment: 'happy-dom', // 'happy-dom' (default) or 'jsdom'
    //     overrides: {
    //       // other Nuxt config you want to pass
    //     }
    //   }
    // }
  }
})

デフォルトでenvironment: 'nuxt'を設定している場合、必要に応じてデフォルト環境からテストファイルごとにオプトアウトすることができます。

// @vitest-environment node
import { test } from 'vitest'

test('my test', () => {
  // ... test without Nuxt environment!
})

When you run your tests within the Nuxt environment, they will be running in a happy-dom or jsdom environment. Before your tests run, a global Nuxt app will be initialized (including, for example, running any plugins or code you've defined in your app.vue).

This means you should take particular care not to mutate the global state in your tests (or, if you need to, to reset it afterwards).

🎭 組み込みモック

@nuxt/test-utilsはDOM環境のためのいくつかの組み込みモックを提供しています。

intersectionObserver

デフォルトtrue、IntersectionObserver APIの機能を持たないダミークラスを作成します

indexedDB

デフォルトfalsefake-indexeddbを使用してIndexedDB APIの機能的なモックを作成します

これらはvitest.config.tsファイルのenvironmentOptionsセクションで設定できます:

import { defineVitestConfig } from '@nuxt/test-utils/config'

export default defineVitestConfig({
  test: {
    environmentOptions: {
      nuxt: {
        mock: {
          intersectionObserver: true,
          indexedDb: true,
        }
      }
    }
  }
})

🛠️ ヘルパー

@nuxt/test-utilsはNuxtアプリのテストを容易にするための多くのヘルパーを提供しています。

mountSuspended

mountSuspendedを使用すると、Nuxt環境内で任意のVueコンポーネントをマウントでき、非同期セットアップとNuxtプラグインからの注入へのアクセスが可能になります。

Under the hood, mountSuspended wraps mount from @vue/test-utils, so you can check out the Vue Test Utils documentation for more on the options you can pass, and how to use this utility.

例:

// @noErrors
import { it, expect } from 'vitest'
import type { Component } from 'vue'
declare module '#components' {
  export const SomeComponent: Component
}
// ---cut---
// tests/components/SomeComponents.nuxt.spec.ts
import { mountSuspended } from '@nuxt/test-utils/runtime'
import { SomeComponent } from '#components'

it('can mount some component', async () => {
    const component = await mountSuspended(SomeComponent)
    expect(component.text()).toMatchInlineSnapshot(
        '"This is an auto-imported component"'
    )
})

// @noErrors
import { it, expect } from 'vitest'
// ---cut---
// tests/components/SomeComponents.nuxt.spec.ts
import { mountSuspended } from '@nuxt/test-utils/runtime'
import App from '~/app.vue'

// tests/App.nuxt.spec.ts
it('can also mount an app', async () => {
    const component = await mountSuspended(App, { route: '/test' })
    expect(component.html()).toMatchInlineSnapshot(`
      "<div>This is an auto-imported component</div>
      <div> I am a global component </div>
      <div>/</div>
      <a href="/test"> Test link </a>"
    `)
})

renderSuspended

renderSuspendedを使用すると、@testing-library/vueを使用してNuxt環境内で任意のVueコンポーネントをレンダリングでき、非同期セットアップとNuxtプラグインからの注入へのアクセスが可能になります。

これはTesting Libraryのユーティリティ、例えばscreenfireEventと一緒に使用する必要があります。これらを使用するには、プロジェクトに@testing-library/vueをインストールしてください。

また、Testing Libraryはクリーンアップのためにテストグローバルにも依存しています。これらをVitest設定でオンにする必要があります。

渡されたコンポーネントは<div id="test-wrapper"></div>内にレンダリングされます。

例:

// @noErrors
import { it, expect } from 'vitest'
import type { Component } from 'vue'
declare module '#components' {
  export const SomeComponent: Component
}
// ---cut---
// tests/components/SomeComponents.nuxt.spec.ts
import { renderSuspended } from '@nuxt/test-utils/runtime'
import { SomeComponent } from '#components'
import { screen } from '@testing-library/vue'

it('can render some component', async () => {
  await renderSuspended(SomeComponent)
  expect(screen.getByText('This is an auto-imported component')).toBeDefined()
})
// @noErrors
import { it, expect } from 'vitest'
// ---cut---
// tests/App.nuxt.spec.ts
import { renderSuspended } from '@nuxt/test-utils/runtime'
import App from '~/app.vue'

it('can also render an app', async () => {
  const html = await renderSuspended(App, { route: '/test' })
  expect(html).toMatchInlineSnapshot(`
    "<div id="test-wrapper">
      <div>This is an auto-imported component</div>
      <div> I am a global component </div>
      <div>Index page</div><a href="/test"> Test link </a>
    </div>"
  `)
})

mockNuxtImport

mockNuxtImportを使用すると、Nuxtの自動インポート機能をモックできます。例えば、useStorageをモックする場合は、次のようにします:

import { mockNuxtImport } from '@nuxt/test-utils/runtime'

mockNuxtImport('useStorage', () => {
  return () => {
    return { value: 'mocked storage' }
  }
})

// your tests here

mockNuxtImport can only be used once per mocked import per test file. It is actually a macro that gets transformed to vi.mock and vi.mock is hoisted, as described in the Vitest docs.

テスト間で異なる実装を提供する必要がある場合、Nuxtインポートをモックするには、vi.hoistedを使用してモックを作成して公開し、それらのモックをmockNuxtImportで使用します。そうすることで、モックされたインポートにアクセスし、テスト間で実装を変更することができます。テストの実行間でモックの状態変更を元に戻すために、モックを復元することを忘れないでください。

import { vi } from 'vitest'
import { mockNuxtImport } from '@nuxt/test-utils/runtime'

const { useStorageMock } = vi.hoisted(() => {
  return {
    useStorageMock: vi.fn(() => {
      return { value: 'mocked storage'}
    })
  }
})

mockNuxtImport('useStorage', () => {
  return useStorageMock
})

// Then, inside a test
useStorageMock.mockImplementation(() => {
  return { value: 'something else' }
})

mockComponent

mockComponentを使用すると、Nuxtのコンポーネントをモックできます。 最初の引数はPascalCaseでのコンポーネント名、またはコンポーネントの相対パスです。 二番目の引数はモックされたコンポーネントを返すファクトリ関数です。

例えば、MyComponentをモックするには:

import { mockComponent } from '@nuxt/test-utils/runtime'

mockComponent('MyComponent', {
  props: {
    value: String
  },
  setup(props) {
    // ...
  }
})

// relative path or alias also works
mockComponent('~/components/my-component.vue', async () => {
  // or a factory function
  return defineComponent({
    setup(props) {
      // ...
    }
  })
})

// or you can use SFC for redirecting to a mock component
mockComponent('MyComponent', () => import('./MockComponent.vue'))

// your tests here

注意: ファクトリ関数内ではローカル変数を参照することはできません。Vue APIや他の変数にアクセスする必要がある場合は、ファクトリ関数内でそれらをインポートする必要があります。

import { mockComponent } from '@nuxt/test-utils/runtime'

mockComponent('MyComponent', async () => {
  const { ref, h } = await import('vue')

  return defineComponent({
    setup(props) {
      const counter = ref(0)
      return () => h('div', null, counter.value)
    }
  })
})

registerEndpoint

registerEndpointを使用すると、モックデータを返すNitroエンドポイントを作成できます。APIからデータを取得して表示するコンポーネントをテストしたい場合に便利です。

最初の引数はエンドポイント名(例:/test/)です。 二番目の引数はモックデータを返すファクトリ関数です。

例えば、/test/エンドポイントをモックするには:

import { registerEndpoint } from '@nuxt/test-utils/runtime'

registerEndpoint('/test/', () => ({
  test: 'test-field'
}))

デフォルトでは、リクエストはGETメソッドを使用して行われます。関数の代わりにオブジェクトを二番目の引数として設定することで、別の方法を使用することができます。

import { registerEndpoint } from '@nuxt/test-utils/runtime'

registerEndpoint('/test/', {
  method: 'POST',
  handler: () => ({ test: 'test-field' })
})

注意: コンポーネントのリクエストが外部APIに行く場合、baseURLを使用して、Nuxt Environment Override Config ($test)を使用して空にすることで、すべてのリクエストがNitroサーバーに行くようにすることができます。

エンドツーエンドテストとの競合

@nuxt/test-utils/runtime@nuxt/test-utils/e2eは異なるテスト環境で実行する必要があり、同じファイルで使用することはできません。

エンドツーエンドテストとユニットテストの両方の機能を@nuxt/test-utilsで使用したい場合は、テストを別々のファイルに分けることができます。その後、特別な// @vitest-environment nuxtコメントでファイルごとにテスト環境を指定するか、ランタイムユニットテストファイルの名前に.nuxt.spec.ts拡張子を付けます。

app.nuxt.spec.ts

import { mockNuxtImport } from '@nuxt/test-utils/runtime'

mockNuxtImport('useStorage', () => {
  return () => {
    return { value: 'mocked storage' }
  }
})

app.e2e.spec.ts

import { setup, $fetch } from '@nuxt/test-utils/e2e'

await setup({
  setupTimeout: 10000,
})

// ...

@vue/test-utilsの使用

Nuxtでユニットテストを行うために@vue/test-utilsを単独で使用したい場合、Nuxtのコンポーザブル、自動インポート、またはコンテキストに依存しないコンポーネントのみをテストしている場合は、次の手順に従って設定できます。

  1. 必要な依存関係をインストールします

    npm i --save-dev vitest @vue/test-utils happy-dom @vitejs/plugin-vue
    
  2. 次の内容でvitest.config.tsを作成します:

    import { defineConfig } from 'vitest/config'
    import vue from '@vitejs/plugin-vue'
    
    export default defineConfig({
      plugins: [vue()],
      test: {
        environment: 'happy-dom',
      },
    });
    
  3. package.jsonに新しいテストコマンドを追加します

    "scripts": {
      "build": "nuxt build",
      "dev": "nuxt dev",
      ...
      "test": "vitest"
    },
    
  4. 次の内容でシンプルな<HelloWorld>コンポーネント components/HelloWorld.vueを作成します:

    <template>
      <p>Hello world</p>
    </template>
    
  5. この新しく作成されたコンポーネントのためのシンプルなユニットテスト ~/components/HelloWorld.spec.tsを作成します

    import { describe, it, expect } from 'vitest'
    import { mount } from '@vue/test-utils'
    
    import HelloWorld from './HelloWorld.vue'
    
    describe('HelloWorld', () => {
      it('component renders Hello world properly', () => {
        const wrapper = mount(HelloWorld)
        expect(wrapper.text()).toContain('Hello world')
      })
    })
    
  6. vitestコマンドを実行します

    npm run test
    

おめでとうございます、Nuxtで@vue/test-utilsを使用したユニットテストを開始する準備が整いました!ハッピーなテスティングを!

エンドツーエンドテスト

エンドツーエンドテストには、テストランナーとしてVitestJestCucumberPlaywrightをサポートしています。

セットアップ

@nuxt/test-utils/e2e ヘルパーメソッドを利用する各 describe ブロックでは、テストを開始する前にテストコンテキストを設定する必要があります。

test/my-test.spec.ts
import { describe, test } from 'vitest'
import { setup, $fetch } from '@nuxt/test-utils/e2e'

describe('My test', async () => {
  await setup({
    // test context options
  })

  test('my test', () => {
    // ...
  })
})

内部的には、setupbeforeAllbeforeEachafterEachafterAll で複数のタスクを実行して、Nuxtテスト環境を正しく設定します。

以下のオプションを setup メソッドに使用してください。

Nuxt設定

  • rootDir: テスト対象のNuxtアプリがあるディレクトリへのパス。
    • 型: string
    • デフォルト: '.'
  • configFile: 設定ファイルの名前。
    • 型: string
    • デフォルト: 'nuxt.config'

タイミング

  • setupTimeout: setupTest がその作業を完了するために許される時間(ミリ秒単位)(Nuxtアプリケーションのビルドや生成に関連するファイルを含む場合があります)。
    • 型: number
    • デフォルト: 60000

機能

  • build: 別のビルドステップを実行するかどうか。

    • 型: boolean
    • デフォルト: truebrowser または server が無効の場合、または host が提供されている場合は false
  • server: テストスイートのリクエストに応答するサーバーを起動するかどうか。

    • 型: boolean
    • デフォルト: truehost が提供されている場合は false
  • port: 提供された場合、起動したテストサーバーのポートを値に設定します。

    • 型: number | undefined
    • デフォルト: undefined
  • host: 提供された場合、新しいサーバーを構築して実行する代わりにテスト対象として使用するURL。デプロイされたアプリケーションバージョンや既に実行中のローカルサーバー(テスト実行時間を大幅に短縮する可能性があります)に対して「リアル」なエンドツーエンドテストを実行するのに便利です。以下のターゲットホストエンドツーエンド例を参照してください

    • 型: string
    • デフォルト: undefined
  • browser: Nuxtテストユーティリティは内部的にplaywrightを使用してブラウザテストを行います。このオプションが設定されている場合、ブラウザが起動され、続くテストスイートで制御できます。

    • 型: boolean
    • デフォルト: false
  • browserOptions

  • runner: テストスイートのランナーを指定します。現在はVitestが推奨されています。

    • 型: 'vitest' | 'jest' | 'cucumber'
    • デフォルト: 'vitest'
ターゲット host エンドツーエンド例

エンドツーエンドテストの一般的な使用例は、本番環境で通常使用される同じ環境で実行されているデプロイされたアプリケーションに対してテストを実行することです。

ローカル開発や自動デプロイパイプラインの場合、別のローカルサーバーに対してテストを実行する方が効率的であり、テストフレームワークがテスト間で再ビルドするのを待つよりも通常は速くなります。

エンドツーエンドテストのために別のターゲットホストを使用するには、単に setup 関数の host プロパティに望むURLを提供してください。

import { setup, createPage } from '@nuxt/test-utils/e2e'
import { describe, it, expect } from 'vitest'

describe('login page', async () => {
  await setup({
    host: 'http://localhost:8787',
  })

  it('displays the email and password fields', async () => {
    const page = await createPage('/login')
    expect(await page.getByTestId('email').isVisible()).toBe(true)
    expect(await page.getByTestId('password').isVisible()).toBe(true)
  })
})

API

$fetch(url)

サーバーレンダリングされたページのHTMLを取得します。

import { $fetch } from '@nuxt/test-utils/e2e'

const html = await $fetch('/')

fetch(url)

サーバーレンダリングされたページのレスポンスを取得します。

import { fetch } from '@nuxt/test-utils/e2e'

const res = await fetch('/')
const { body, headers } = res

url(path)

テストサーバーが実行中のポートを含む、指定されたページの完全なURLを取得します。

import { url } from '@nuxt/test-utils/e2e'

const pageUrl = url('/page')
// 'http://localhost:6840/page'

ブラウザでのテスト

@nuxt/test-utils 内で Playwright を使用して組み込みサポートを提供しています。これはプログラム的にもPlaywrightテストランナーを介しても使用できます。

createPage(url)

vitestjest、または cucumber 内で、createPage を使用して設定された Playwright ブラウザインスタンスを作成し、オプションで実行中のサーバーのパスを指定することができます。Playwrightドキュメントで利用可能なAPIメソッドについてもっと知ることができます.

import { createPage } from '@nuxt/test-utils/e2e'

const page = await createPage('/page')
// `page` 変数から Playwright のすべての API をアクセスできます

Testing with Playwright Test Runner

We also provide first-class support for testing Nuxt within the Playwright test runner.

npm i --save-dev @playwright/test @nuxt/test-utils

このセクションの初めに述べた setup() 関数と同じ設定詳細で、グローバルNuxt設定を提供することができます。

playwright.config.ts
import { fileURLToPath } from 'node:url'
import { defineConfig, devices } from '@playwright/test'
import type { ConfigOptions } from '@nuxt/test-utils/playwright'

export default defineConfig<ConfigOptions>({
  use: {
    nuxt: {
      rootDir: fileURLToPath(new URL('.', import.meta.url))
    }
  },
  // ...
})
こちらも参照 See full example config

テストファイルでは、@nuxt/test-utils/playwright から直接 expecttest を使用する必要があります:

tests/example.test.ts
import { expect, test } from '@nuxt/test-utils/playwright'

test('test', async ({ page, goto }) => {
  await goto('/', { waitUntil: 'hydration' })
  await expect(page.getByRole('heading')).toHaveText('Welcome to Playwright!')
})

または、テストファイル内で直接Nuxtサーバーを設定することもできます:

tests/example.test.ts
import { expect, test } from '@nuxt/test-utils/playwright'

test.use({
  nuxt: {
    rootDir: fileURLToPath(new URL('..', import.meta.url))
  }
})

test('test', async ({ page, goto }) => {
  await goto('/', { waitUntil: 'hydration' })
  await expect(page.getByRole('heading')).toHaveText('Welcome to Playwright!')
})