테스트!
Nuxt 애플리케이션을 테스트하는 방법.
모듈 작성자인 경우, 모듈 작성자 가이드에서 더 구체적인 정보를 찾을 수 있습니다.
Nuxt는 @nuxt/test-utils
를 통해 Nuxt 애플리케이션의 종단 간 및 단위 테스트에 대한 일류 지원을 제공합니다. 이 라이브러리는 현재 Nuxt 자체에서 사용하는 테스트와 모듈 생태계 전반의 테스트를 지원하는 테스트 유틸리티 및 구성 라이브러리입니다.
설치
다른 테스트 종속성을 관리할 수 있도록 @nuxt/test-utils
는 다양한 선택적 피어 종속성과 함께 제공됩니다. 예를 들어:
- 런타임 Nuxt 환경을 위해
happy-dom
과jsdom
중에서 선택할 수 있습니다. - 종단 간 테스트 러너를 위해
vitest
,cucumber
,jest
및playwright
중에서 선택할 수 있습니다. - 내장된 브라우저 테스트 유틸리티를 사용하려면
playwright-core
가 필요하며, 테스트 러너로@playwright/test
를 사용하지 않는 경우에만 필요합니다.
npm i --save-dev @nuxt/test-utils vitest @vue/test-utils happy-dom playwright-core
단위 테스트
현재 Nuxt 런타임 환경이 필요한 코드를 위한 단위 테스트 환경을 제공합니다. 현재는 vitest
만 지원합니다 (다른 런타임을 추가하는 기여는 환영합니다).
설정
-
@nuxt/test-utils/module
을nuxt.config
파일에 추가합니다 (선택 사항). 이는 개발 중에 단위 테스트를 실행할 수 있는 Vitest 통합을 Nuxt DevTools에 추가합니다.export default defineNuxtConfig({ modules: [ '@nuxt/test-utils/module' ] })
-
다음 내용을 포함한
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-utils
의 mount
를 래핑하므로, 전달할 수 있는 옵션 및 이 유틸리티를 사용하는 방법에 대한 자세한 내용은 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의 유틸리티, 예를 들어 screen
및 fireEvent
와 함께 사용해야 합니다. 이러한 유틸리티를 사용하려면 프로젝트에 @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.mock
은 Vitest 문서에 설명된 대로 호이스팅됩니다.
테스트 간에 다른 구현을 제공하기 위해 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 컴포저블, 자동 가져오기 또는 컨텍스트에 의존하지 않는 컴포넌트만 테스트하는 경우, 다음 단계를 따라 설정할 수 있습니다.
-
필요한 종속성 설치
npm i --save-dev vitest @vue/test-utils happy-dom @vitejs/plugin-vue
-
다음 내용을 포함한
vitest.config.ts
를 생성합니다:import { defineConfig } from 'vitest/config' import vue from '@vitejs/plugin-vue' export default defineConfig({ plugins: [vue()], test: { environment: 'happy-dom', }, });
-
package.json
에 테스트를 위한 새로운 명령어 추가"scripts": { "build": "nuxt build", "dev": "nuxt dev", ... "test": "vitest" },
-
다음 내용을 포함한 간단한
<HelloWorld>
컴포넌트components/HelloWorld.vue
생성<template> <p>Hello world</p> </template>
-
새로 생성된 컴포넌트에 대한 간단한 단위 테스트
~/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') }) })
-
vitest 명령어 실행
npm run test
축하합니다, Nuxt에서 @vue/test-utils
로 단위 테스트를 시작할 준비가 완료되었습니다! 즐거운 테스트 되세요!
종단 간 테스트
종단 간 테스트를 위해, 우리는 테스트 러너로 Vitest, Jest, Cucumber 및 Playwright를 지원합니다.
설정
@nuxt/test-utils/e2e
헬퍼 메서드를 사용하는 각 describe
블록에서 시작하기 전에 테스트 컨텍스트를 설정해야 합니다.
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
, afterEach
및 afterAll
에서 여러 작업을 수행합니다.
아래의 옵션을 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 구성을 제공할 수 있습니다.
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
에서 expect
및 test
를 직접 사용해야 합니다:
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 서버를 직접 구성할 수 있습니다:
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!')
})
※이 페이지는 Nuxt.js 공식 문서의 비공식 번역 페이지입니다.
공식 문서의 해당 페이지는 여기 있습니다:
https://nuxt.com/docs/3.x/getting-started/testing