測試
Nuxt 透過 @nuxt/test-utils
為你的 Nuxt 應用程式提供一流的端到端和單元測試支援,這是一個測試工具和配置庫,目前支援我們在 Nuxt 本身使用的測試以及整個模組生態系統中的測試。
安裝
為了讓你能夠管理其他測試依賴項,@nuxt/test-utils
附帶了各種可選的對等依賴項。例如
- 你可以選擇
happy-dom
和jsdom
作為 Nuxt 執行時環境 - 你可以選擇
vitest
、cucumber
、jest
和playwright
作為端到端測試執行器 playwright-core
僅在你希望使用內建瀏覽器測試工具(並且不使用@playwright/test
作為測試執行器)時才需要。
npm i --save-dev @nuxt/test-utils vitest @vue/test-utils happy-dom playwright-core
yarn add --dev @nuxt/test-utils vitest @vue/test-utils happy-dom playwright-core
pnpm add -D @nuxt/test-utils vitest @vue/test-utils happy-dom playwright-core
bun add --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 { defineConfig } from 'vitest/config' import { defineVitestProject } from '@nuxt/test-utils/config' export default defineConfig({ test: { projects: [ { test: { name: 'unit', include: ['test/{e2e,unit}/*.{test,spec}.ts'], environment: 'node', }, }, await defineVitestProject({ test: { name: 'nuxt', include: ['test/nuxt/*.{test,spec}.ts'], environment: 'nuxt', }, }), ], }, })
@nuxt/test-utils
時,需要在你的 package.json
中指定 "type": "module"
,或者相應地重新命名你的 Vitest 配置檔案。即,
vitest.config.m{ts,js}
。
.env.test
檔案來設定測試的環境變數。使用 Nuxt 執行時環境
使用Vitest 專案你可以對哪些測試在哪個環境中執行進行細粒度控制
- 單元測試:將常規單元測試放在
test/unit/
中 - 這些測試在 Node 環境中執行以提高速度 - Nuxt 測試:將依賴 Nuxt 執行時環境的測試放在
test/nuxt/
中 - 這些測試將在 Nuxt 執行時環境中執行
替代方案:簡單設定
如果你更喜歡簡單的設定,並希望所有測試都在 Nuxt 環境中執行,你可以使用基本配置
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'
的簡單設定,你可以根據需要選擇 退出Nuxt 環境每個測試檔案。
// @vitest-environment node
import { test } from 'vitest'
test('my test', () => {
// ... test without Nuxt environment!
})
nuxtApp
未初始化。這可能導致難以除錯的錯誤。組織你的測試
透過基於專案的設定,你可以按以下方式組織你的測試
test/
├── e2e/
│ └── ssr.test.ts
├── nuxt/
│ ├── components.test.ts
│ └── composables.test.ts
├── unit/
│ └── utils.test.ts
你當然可以選擇任何測試結構,但將 Nuxt 執行時環境與 Nuxt 端到端測試分開對於測試穩定性很重要。
執行測試
透過專案設定,你可以執行不同的測試套件
# Run all tests
npx vitest
# Run only unit tests
npx vitest --project unit
# Run only Nuxt tests
npx vitest --project nuxt
# Run tests in watch mode
npx vitest --watch
happy-dom
或jsdom
環境中執行。在測試執行之前,將初始化一個全域性 Nuxt 應用程式(例如,包括執行你在 app.vue
中定義的任何外掛或程式碼)。這意味著你應該特別注意不要在測試中修改全域性狀態(或者,如果需要,之後將其重置)。🎭 內建模擬
@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 外掛中的注入。
例如
// 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"',
)
})
// 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 還依賴測試全域性變數進行清理。你應該在你的Vitest 配置.
中開啟這些。傳入的元件將渲染在 <div id="test-wrapper"></div>
中。
示例
// 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()
})
// 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
中所述。如果你需要模擬 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', () => {
// 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 環境覆蓋配置($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 { $fetch, setup } from '@nuxt/test-utils/e2e'
await setup({
setupTimeout: 10000,
})
// ...
使用 @vue/test-utils
如果你更喜歡單獨使用 @vue/test-utils
進行 Nuxt 單元測試,並且只測試不依賴 Nuxt 可組合項、自動匯入或上下文的元件,你可以按照以下步驟進行設定。
- 安裝所需的依賴項
npm i --save-dev vitest @vue/test-utils happy-dom @vitejs/plugin-vue
yarn add --dev vitest @vue/test-utils happy-dom @vitejs/plugin-vue
pnpm add -D vitest @vue/test-utils happy-dom @vitejs/plugin-vue
bun add --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>
元件app/components/HelloWorld.vue
,內容如下<template> <p>Hello world</p> </template>
- 為這個新建立的元件
~/components/HelloWorld.spec.ts
建立一個簡單的單元測試import { describe, expect, it } 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
yarn test
pnpm run test
bun run test
恭喜,你已準備好開始使用 @vue/test-utils
在 Nuxt 中進行單元測試!祝你測試愉快!
端到端測試
對於端到端測試,我們支援Vitest, Jest, Cucumber等等Playwright作為測試執行器。
設定
在每個利用 @nuxt/test-utils/e2e
輔助方法的 describe
塊中,你需要先設定測試上下文。
import { describe, test } from 'vitest'
import { $fetch, setup } from '@nuxt/test-utils/e2e'
describe('My test', async () => {
await setup({
// test context options
})
test('my test', () => {
// ...
})
})
在底層,setup
在 beforeAll
、beforeEach
、afterEach
和 afterAll
中執行多項任務,以正確設定 Nuxt 測試環境。
請使用以下選項進行 setup
方法。
Nuxt 配置
rootDir
:包含要測試的 Nuxt 應用程式的目錄路徑。- 型別:
string
- 預設值:
'.'
- 型別:
configFile
:配置檔名稱。- 型別:
string
- 預設值:
'nuxt.config'
- 型別:
時間
setupTimeout
:允許setupTest
完成其工作(可能包括構建或生成 Nuxt 應用程式的檔案,具體取決於傳遞的選項)的時間(以毫秒為單位)。- 型別:
number
- 預設值:
120000
或在 Windows 上為240000
- 型別:
teardownTimeout
:允許拆除測試環境(例如關閉瀏覽器)的時間(以毫秒為單位)。- 型別:
number
- 預設值:
30000
- 型別:
功能
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 { createPage, setup } from '@nuxt/test-utils/e2e'
import { describe, expect, it } from 'vitest'
describe('login page', async () => {
await setup({
host: 'https://: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')
// 'https://:6840/page'
在瀏覽器中測試
我們透過 @nuxt/test-utils
提供使用 Playwright 的內建支援,無論是透過程式設計方式還是透過 Playwright 測試執行器。
createPage(url)
在 vitest
、jest
或 cucumber
中,你可以使用 createPage
建立一個配置好的 Playwright 瀏覽器例項,並(可選地)將其指向執行伺服器中的路徑。你可以在Playwright 文件.
import { createPage } from '@nuxt/test-utils/e2e'
const page = await createPage('/page')
// you can access all the Playwright APIs from the `page` variable
中找到更多可用的 API 方法。
使用 Playwright 測試執行器進行測試我們還為在.
npm i --save-dev @playwright/test @nuxt/test-utils
yarn add --dev @playwright/test @nuxt/test-utils
pnpm add -D @playwright/test @nuxt/test-utils
bun add --dev @playwright/test @nuxt/test-utils
Playwright 測試執行器
setup()
函式相同。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!')
})
tests/example.test.ts
@nuxt/test-utils/playwright
中的 expect
和 test
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!')
})