nuxt logo

문서 번역(비공식)

테스트!

Nuxt 애플리케이션을 테스트하는 방법.

모듈 작성자인 경우, 모듈 작성자 가이드에서 더 구체적인 정보를 찾을 수 있습니다.

Nuxt는 @nuxt/test-utils를 통해 Nuxt 애플리케이션의 종단 간 및 단위 테스트에 대한 일류 지원을 제공합니다. 이 라이브러리는 현재 Nuxt 자체에서 사용하는 테스트와 모듈 생태계 전반의 테스트를 지원하는 테스트 유틸리티 및 구성 라이브러리입니다.

설치

다른 테스트 종속성을 관리할 수 있도록 @nuxt/test-utils는 다양한 선택적 피어 종속성과 함께 제공됩니다. 예를 들어:

  • 런타임 Nuxt 환경을 위해 happy-domjsdom 중에서 선택할 수 있습니다.
  • 종단 간 테스트 러너를 위해 vitest, cucumber, jestplaywright 중에서 선택할 수 있습니다.
  • 내장된 브라우저 테스트 유틸리티를 사용하려면 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({
      // 필요한 사용자 정의 Vitest 구성
    })
    

vitest 구성에서 @nuxt/test-utils를 가져올 때, package.json"type": "module"이 지정되어 있거나 vitest 구성 파일의 이름을 적절히 변경해야 합니다.

예: vitest.config.m{ts,js}.

.env.test 파일을 사용하여 테스트를 위한 환경 변수를 설정할 수 있습니다.

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', () => {
  // ... Nuxt 환경에서 테스트!
})

또는 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',
    // 선택적으로 Nuxt 전용 환경 옵션을 설정할 수 있습니다.
    // environmentOptions: {
    //   nuxt: {
    //     rootDir: fileURLToPath(new URL('./playground', import.meta.url)),
    //     domEnvironment: 'happy-dom', // 'happy-dom' (기본값) 또는 'jsdom'
    //     overrides: {
    //       // 전달하려는 다른 Nuxt 구성
    //     }
    //   }
    // }
  }
})

기본적으로 environment: 'nuxt'를 설정한 경우, 필요에 따라 테스트 파일별로 기본 환경을 선택 해제할 수 있습니다.

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

test('my test', () => {
  // ... Nuxt 환경 없이 테스트!
})

Nuxt 환경 내에서 테스트를 실행할 때, 테스트는 happy-dom 또는 jsdom 환경에서 실행됩니다. 테스트가 실행되기 전에 글로벌 Nuxt 앱이 초기화됩니다 (예: app.vue에 정의된 플러그인이나 코드 실행 포함).

이는 테스트에서 글로벌 상태를 변경하지 않도록 주의해야 함을 의미합니다 (또는 필요할 경우, 이후에 상태를 재설정해야 합니다).

🎭 내장된 목(Mock)

@nuxt/test-utils는 DOM 환경을 위한 몇 가지 내장된 목을 제공합니다.

intersectionObserver

기본값 true, IntersectionObserver API에 대한 기능이 없는 더미 클래스를 생성합니다.

indexedDB

기본값 false, fake-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 플러그인에서의 주입에 접근할 수 있게 합니다.

mountSuspended는 내부적으로 @vue/test-utilsmount를 래핑하므로, 전달할 수 있는 옵션 및 이 유틸리티를 사용하는 방법에 대한 자세한 내용은 Vue Test Utils 문서를 참조하세요.

예를 들어:

// @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는 정리(cleanup)를 위한 테스트 전역에 의존합니다. 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는 테스트 파일당 모킹된 가져오기에 대해 한 번만 사용할 수 있습니다. 실제로 이는 vi.mock으로 변환되는 매크로이며, vi.mockVitest 문서에 설명된 대로 호이스팅됩니다.

테스트 간에 다른 구현을 제공하기 위해 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) {
    // ...
  }
})

// 상대 경로나 별칭도 작동합니다
mockComponent('~/components/my-component.vue', async () => {
  // 또는 팩토리 함수
  return defineComponent({
    setup(props) {
      // ...
    }
  })
})

// 또는 모킹된 컴포넌트로 리디렉션하기 위해 SFC를 사용할 수 있습니다
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 환경 재정의 구성 ($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로 단위 테스트를 시작할 준비가 완료되었습니다! 즐거운 테스트 되세요!

종단 간 테스트

종단 간 테스트를 위해, 우리는 테스트 러너로 Vitest, Jest, CucumberPlaywright를 지원합니다.

설정

@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('my test', () => {
    // ...
  })
})

백그라운드에서, setup은 Nuxt 테스트 환경을 올바르게 설정하기 위해 beforeAll, beforeEach, afterEachafterAll에서 여러 작업을 수행합니다.

아래의 옵션을 setup 메서드에 사용하세요.

Nuxt 구성

  • rootDir: 테스트할 Nuxt 앱이 있는 디렉토리의 경로.
    • 유형: string
    • 기본값: '.'
  • configFile: 구성 파일의 이름.
    • 유형: string
    • 기본값: 'nuxt.config'

타이밍

  • setupTimeout: setupTest가 작업을 완료하는 데 허용되는 시간(밀리초). 이 작업에는 전달된 옵션에 따라 Nuxt 애플리케이션에 대한 파일 빌드 또는 생성이 포함될 수 있습니다.
    • 유형: number
    • 기본값: 60000

기능

  • build: 별도의 빌드 단계를 실행할지 여부.

    • 유형: boolean
    • 기본값: true (browser 또는 server가 비활성화된 경우, 또는 host가 제공된 경우 false)
  • server: 테스트 스위트에서 요청에 응답하기 위해 서버를 시작할지 여부.

    • 유형: boolean
    • 기본값: true (host가 제공된 경우 false)
  • port: 제공된 경우, 시작된 테스트 서버 포트를 해당 값으로 설정.

    • 유형: number | undefined
    • 기본값: undefined
  • host: 제공된 경우, 새 서버를 빌드하고 실행하는 대신 테스트 대상으로 사용할 URL. 배포된 애플리케이션의 "실제" 종단 간 테스트를 실행하거나 이미 실행 중인 로컬 서버에 대해 테스트를 실행하는 데 유용합니다 (이는 테스트 실행 시간을 크게 줄일 수 있습니다). 아래 대상 호스트 종단 간 예제를 참조하세요.

    • 유형: string
    • 기본값: undefined
  • browser: 내부적으로 Nuxt 테스트 유틸리티는 playwright를 사용하여 브라우저 테스트를 수행합니다. 이 옵션이 설정되면 브라우저가 시작되고 이후 테스트 스위트에서 제어할 수 있습니다.

    • 유형: boolean
    • 기본값: false
  • browserOptions

    • 유형: object로 다음 속성을 포함
      • type: 시작할 브라우저 유형 - chromium, firefox 또는 webkit 중 하나
      • launch: 브라우저를 시작할 때 playwright에 전달될 옵션의 object. 전체 API 참조를 참조하세요.
  • 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)

vitest, jest 또는 cucumber 내에서 createPage를 사용하여 구성된 Playwright 브라우저 인스턴스를 생성하고 (선택적으로) 실행 중인 서버의 경로로 지정할 수 있습니다. Playwright 문서에서 사용할 수 있는 API 메서드에 대한 자세한 내용을 확인할 수 있습니다.

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

const page = await createPage('/page')
// `page` 변수에서 모든 Playwright API에 접근할 수 있습니다.

Playwright 테스트 러너로 테스트

Playwright 테스트 러너 내에서 Nuxt를 테스트하기 위한 일류 지원도 제공합니다.

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))
    }
  },
  // ...
})
이것도 참고 전체 예제 구성 보기

테스트 파일은 @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!')
})