Testing
Nuxt offers first-class support for end-to-end and unit testing of your Nuxt application via @nuxt/test-utils, a library of test utilities and configuration that currently powers the tests we use on Nuxt itself and tests throughout the module ecosystem.
Installation
In order to allow you to manage your other testing dependencies, @nuxt/test-utils ships with various optional peer dependencies. For example:
- you can choose between
happy-domandjsdomfor a runtime Nuxt environment - you can choose between
vitest,cucumber,jestandplaywrightfor end-to-end test runners playwright-coreis only required if you wish to use the built-in browser testing utilities (and are not using@playwright/testas your test runner)
npm i --save-dev @nuxt/test-utils vitest @vue/test-utils happy-dom playwright-coreyarn add --dev @nuxt/test-utils vitest @vue/test-utils happy-dom playwright-corepnpm add -D @nuxt/test-utils vitest @vue/test-utils happy-dom playwright-corebun add --dev @nuxt/test-utils vitest @vue/test-utils happy-dom playwright-coreTest Environments
@nuxt/test-utils provides helpers for two different test environments:
- Nuxt environment: tests run inside a Nuxt app in a
happy-domorjsdomenvironment, with access to auto-imports, plugins and injections. Helpers from@nuxt/test-utils/runtime(such asmountSuspendedandmockNuxtImport) require this environment, which is currently only available with Vitest. - Node environment: tests run in plain Node. End-to-end tests using
@nuxt/test-utils/e2erequire this environment, as they test your Nuxt app from the outside, over HTTP or through a browser. Unit tests that do not need Nuxt can also run here.
A test file can only run in one of these environments, so @nuxt/test-utils/runtime and @nuxt/test-utils/e2e cannot be used in the same file. With Vitest, you can use projects to make sure that each test file runs in the right environment, as shown in the setup below.
Unit Testing
We currently ship an environment for unit testing code that needs a Nuxt runtime environment. It currently only has support for vitest (although contribution to add other runtimes would be welcome).
Setup
Add
@nuxt/test-utils/moduleto yournuxt.configfile (optional). It adds a Vitest integration to your Nuxt DevTools which supports running your unit tests in development.export default defineNuxtConfig({ modules: [ '@nuxt/test-utils/module', ], })Create a
vitest.config.tswith the following content:import { defineConfig } from 'vitest/config' import { defineVitestProject } from '@nuxt/test-utils/config' export default defineConfig({ test: { projects: [ { test: { name: 'unit', include: ['test/unit/*.{test,spec}.ts'], environment: 'node', }, }, { test: { name: 'e2e', include: ['test/e2e/*.{test,spec}.ts'], environment: 'node', }, }, await defineVitestProject({ test: { name: 'nuxt', include: ['test/nuxt/*.{test,spec}.ts'], environment: 'nuxt', }, }), ], }, })defineVitestProjectis only for Nuxt-environment tests. End-to-end tests should be configured as a regulartest.environment: 'node'project.- If your Nuxt-environment tests live outside
test/nuxt/, see TypeScript Support in Tests to add them to the TypeScript context.
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.
i.e., vitest.config.m{ts,js}..env.test file.Nuxt Environment Options
You can pass Nuxt-specific options to a defineVitestProject project with test.environmentOptions.nuxt:
import { fileURLToPath } from 'node:url'
import { defineConfig } from 'vitest/config'
import { defineVitestProject } from '@nuxt/test-utils/config'
export default defineConfig({
test: {
projects: [
await defineVitestProject({
test: {
name: 'nuxt',
include: ['test/nuxt/*.{test,spec}.ts'],
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
},
},
},
},
}),
],
},
})Organizing Your Tests
With the project-based setup, each project's include glob determines which environment a test file runs in:
- Unit tests in
test/unit/run in the Node environment. - Nuxt tests in
test/nuxt/run in the Nuxt environment. - End-to-end tests in
test/e2e/run in the Node environment.
test/
├── e2e/
│ └── ssr.test.ts
├── nuxt/
│ ├── components.test.ts
│ └── composables.test.ts
├── unit/
│ └── utils.test.tsIf you prefer to keep tests next to your source files, you can use file suffixes such as *.unit.spec.ts, *.nuxt.spec.ts and *.e2e.spec.ts instead, with matching include globs (for example, include: ['**/*.nuxt.{test,spec}.ts']). See the co-location example for a full configuration.
You can of course opt for any test structure, but each test file should match exactly one project. In particular, keeping Nuxt-environment tests separate from end-to-end tests is important for test stability.
include globs to choose the environment for a test file, rather than a // @vitest-environment comment. The comment changes the environment without adding or removing the Nuxt Vite plugins configured by defineVitestProject.TypeScript Support in Tests
By default, test files in test/nuxt/ and tests/nuxt/ directories are included in the Nuxt app TypeScript context. That means they will recognise Nuxt aliases (like ~/, @/, #imports) and TypeScript will be aware of auto-imports that work in your Nuxt app.
test/unit/ can be added manually if needed.Adding other test directories
If you have tests in other directories that you will be running in the Nuxt Vitest environment, you can include them in the Nuxt app TypeScript context by adding them to your configuration:
export default defineNuxtConfig({
typescript: {
tsConfig: {
include: [
// this path is relative to the generated .nuxt/tsconfig.json
'../test/other-nuxt-context/**/*',
],
},
},
})~/utils/helpers), not for Nuxt-specific features.Running Tests
With the project setup, you can run different test suites:
# Run all tests
npx vitest
# Run only unit tests
npx vitest --project unit
# Run only Nuxt tests
npx vitest --project nuxt
# Run only end-to-end tests
npx vitest --project e2e
# Run tests in watch mode
npx vitest --watchWhen 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).
🎭 Built-In Mocks
@nuxt/test-utils provides some built-in mocks for the DOM environment. These are only available in the Nuxt environment.
intersectionObserver
Default true, creates a dummy class without any functionality for the IntersectionObserver API
indexedDB
Default false, uses fake-indexeddb to create a functional mock of the IndexedDB API
These can be configured in the Nuxt environment options of your vitest.config.ts file:
import { defineConfig } from 'vitest/config'
import { defineVitestProject } from '@nuxt/test-utils/config'
export default defineConfig({
test: {
projects: [
await defineVitestProject({
test: {
name: 'nuxt',
include: ['test/nuxt/*.{test,spec}.ts'],
environmentOptions: {
nuxt: {
mock: {
intersectionObserver: true,
indexedDb: true,
},
},
},
},
}),
],
},
})🛠️ Helpers
@nuxt/test-utils provides a number of helpers to make testing Nuxt apps easier.
mountSuspended
mountSuspended allows you to mount any Vue component within the Nuxt environment, allowing async setup and access to injections from your Nuxt plugins.
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.For example:
// @noErrors
import type { Component } from 'vue'
declare module '#components' {
export const SomeComponent: Component
}
// ---cut---
import { expect, it } from 'vitest'
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"',
)
})import { expect, it } from 'vitest'
import { mountSuspended } from '@nuxt/test-utils/runtime'
import App from '~/app.vue'
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>"
`)
})If you need to spy on component setup state, you can set the spy option to true and access the return value of the setup via setupState.
// @noErrors
import type { Component } from 'vue'
declare module '#components' {
export const SomeComponent: Component
}
// ---cut---
import { expect, it, vi } from 'vitest'
import { mountSuspended } from '@nuxt/test-utils/runtime'
import { SomeComponent } from '#components'
it('can spy on setup state', async () => {
const component = await mountSuspended(SomeComponent, { spy: true })
vi.mocked(component.setupState.someMethod).mockImplementation(() => 'mocked')
})The options object accepts @vue/test-utils mount options and the following properties:
route: the initial route, orfalseto skip the initial route change (default/).spy: enable spy component setup state (defaultfalse).
The return object includes the @vue/test-utils mount result and the following properties:
setupState: the return value of the component setup.
renderSuspended
renderSuspended allows you to render any Vue component within the Nuxt environment using @testing-library/vue, allowing async setup and access to injections from your Nuxt plugins.
This should be used together with utilities from Testing Library, e.g. screen and fireEvent. Install @testing-library/vue in your project to use these.
Additionally, Testing Library also relies on testing globals for cleanup. You should turn these on in your Vitest config.
The passed in component will be rendered inside a <div id="test-wrapper"></div>.
Examples:
// @noErrors
import type { Component } from 'vue'
declare module '#components' {
export const SomeComponent: Component
}
// ---cut---
import { expect, it } from 'vitest'
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()
})import { expect, it } from 'vitest'
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>"
`)
})The options object accepts @testing-library/vue render options and the following properties:
route: the initial route, orfalseto skip the initial route change (default/).spy: enable spy component setup state (defaultfalse). See themountSuspendedexample above.
The return object includes the @testing-library/vue render result and the following properties:
setupState: the return value of the component setup.
mockNuxtImport
mockNuxtImport allows you to mock Nuxt's auto import functionality. For example, to mock useState, you can do so like this:
import { mockNuxtImport } from '@nuxt/test-utils/runtime'
mockNuxtImport('useState', () => {
return () => {
return { value: 'mocked storage' }
}
})
// your tests hereYou can explicitly type the mock for type safety, and use the original implementation passed to the factory function when mocking complex functionality.
import { mockNuxtImport } from '@nuxt/test-utils/runtime'
mockNuxtImport<typeof useState>('useState', (original) => {
return (...args) => {
return { ...original('some-key'), value: 'mocked state' }
}
})
// or specify the target to mock
mockNuxtImport(useState, (original) => {
return (...args) => {
return { ...original('some-key'), value: 'mocked state' }
}
})
// your tests heremockNuxtImport 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.If you need to mock a Nuxt import and provide different implementations between tests, you can do it by creating and exposing your mocks using vi.hoisted, and then use those mocks in mockNuxtImport. You then have access to the mocked imports, and can change the implementation between tests. Be careful to restore mocks before or after each test to undo mock state changes between runs.
import { vi } from 'vitest'
import { mockNuxtImport } from '@nuxt/test-utils/runtime'
const { useStateMock } = vi.hoisted(() => {
return {
useStateMock: vi.fn(() => {
return { value: 'mocked storage' }
}),
}
})
mockNuxtImport('useState', () => {
return useStateMock
})
// Then, inside a test
useStateMock.mockImplementation(() => {
return { value: 'something else' }
})If you need to mock behavior only inside a test, you can also use the following approach.
import { beforeEach, vi } from 'vitest'
import { mockNuxtImport } from '@nuxt/test-utils/runtime'
mockNuxtImport(useRoute, original => vi.fn(original))
beforeEach(() => {
vi.resetAllMocks()
})
// Then, inside a test
const useRouteOriginal = vi.mocked(useRoute).getMockImplementation()!
vi.mocked(useRoute).mockImplementation(
(...args) => ({ ...useRouteOriginal(...args), path: '/mocked' }),
)mockComponent
mockComponent allows you to mock Nuxt's component.
The first argument can be the component name in PascalCase, or the relative path of the component.
The second argument is a factory function that returns the mocked component.
For example, to mock MyComponent, you can:
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 hereNote: You can't reference local variables in the factory function since they are hoisted. If you need to access Vue APIs or other variables, you need to import them in your factory function.
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 allows you create Nitro endpoint that returns mocked data. It can come in handy if you want to test a component that makes requests to API to display some data.
The first argument is the endpoint name (e.g. /test/).
The second argument is a factory function that returns the mocked data.
For example, to mock /test/ endpoint, you can do:
import { registerEndpoint } from '@nuxt/test-utils/runtime'
registerEndpoint('/test/', () => ({
test: 'test-field',
}))By default, your request will be made using the GET method. You may use another method by setting an object as the second argument instead of a function.
import { registerEndpoint } from '@nuxt/test-utils/runtime'
registerEndpoint('/test/', {
method: 'POST',
handler: () => ({ test: 'test-field' }),
})This object accepts the following properties:
handler: the event handler functionmethod: (optional) HTTP method to match (e.g., 'GET', 'POST')once: (optional) if true, the handler will only be used for the first matching request and then automatically removed
Note: If your requests in a component go to an external API, you can usebaseURLand then make it empty using Nuxt Environment Override Config ($test) so all your requests will go to Nitro server.
Conflict with End-To-End Testing
@nuxt/test-utils/runtime and @nuxt/test-utils/e2e need to run in different test environments and so can't be used in the same file.
If you would like to use both the end-to-end and unit testing functionality of @nuxt/test-utils, split your tests into separate files and make sure each file matches only one project: Nuxt-environment tests should be matched by a defineVitestProject project, and end-to-end tests by a regular environment: 'node' project. See Organizing Your Tests for folder- and suffix-based layouts.
app.nuxt.spec.ts
import { mockNuxtImport } from '@nuxt/test-utils/runtime'
mockNuxtImport('useState', () => {
return () => {
return { value: 'mocked storage' }
}
})app.e2e.spec.ts
import { $fetch, setup } from '@nuxt/test-utils/e2e'
await setup({
setupTimeout: 10000,
})
// ...Using @vue/test-utils
If you prefer to use @vue/test-utils on its own for unit testing in Nuxt, and you are only testing components which do not rely on Nuxt composables, auto-imports or context, you can follow these steps to set it up.
Install the needed dependencies
npm i --save-dev vitest @vue/test-utils happy-dom @vitejs/plugin-vueyarn add --dev vitest @vue/test-utils happy-dom @vitejs/plugin-vuepnpm add -D vitest @vue/test-utils happy-dom @vitejs/plugin-vuebun add --dev vitest @vue/test-utils happy-dom @vitejs/plugin-vueCreate a
vitest.config.tswith the following content:import { defineConfig } from 'vitest/config' import vue from '@vitejs/plugin-vue' export default defineConfig({ plugins: [vue()], test: { environment: 'happy-dom', }, })Add a new command for test in your
package.json"scripts": { "build": "nuxt build", "dev": "nuxt dev", ... "test": "vitest" },Create a simple
<HelloWorld>componentapp/components/HelloWorld.vuewith the following content:<template> <p>Hello world</p> </template>Create a simple unit test for this newly created component
~/components/HelloWorld.spec.tsimport { 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') }) })Run vitest command
npm run testyarn testpnpm run testbun run test
Congratulations, you're all set to start unit testing with @vue/test-utils in Nuxt! Happy testing!
Vitest Browser Mode
@nuxt/test-utils provides helpers for testing in Vitest Browser Mode via @nuxt/test-utils/browser.
Setup
Install Vitest browser packages and a browser provider:
npm i --save-dev @vitest/browser-playwrightyarn add --dev @vitest/browser-playwrightpnpm add -D @vitest/browser-playwrightbun add --dev @vitest/browser-playwrightConfigure browser mode in your
vitest.config.ts:// @errors: 2307 // ---cut--- import { defineConfig } from 'vitest/config' import { defineVitestProject } from '@nuxt/test-utils/config' import { playwright } from '@vitest/browser-playwright' export default defineConfig({ test: { projects: [ await defineVitestProject({ test: { name: 'browser', include: ['test/browser/**/*.{test,spec}.ts'], browser: { enabled: true, provider: playwright(), instances: [{ browser: 'chromium' }], }, // If you want to enable `page.render` and automatic cleanup, add this setup file setupFiles: ['@nuxt/test-utils/browser'], }, }), ], }, })When adding@nuxt/test-utils/browsertosetupFiles, if TypeScript does not automatically recognize the types forpage.render, you can add@nuxt/test-utils/browserviatypescript.tsConfig.compilerOptions.typesin yournuxt.config.ts.If your Vitest browser mode tests live outsidetest/nuxt/(such as intest/browser/), see Adding other test directories to add them to the TypeScript context.
Usage
You can use page.render from vitest/browser:
// @noErrors
import type { Component } from 'vue'
declare module '#components' {
export const MyCounter: Component
}
// ---cut---
import { expect, it } from 'vitest'
import { page } from 'vitest/browser'
// If you added the setup file, the following import is not needed
import '@nuxt/test-utils/browser'
import { MyCounter } from '#components'
it('counter button increments the count', async () => {
const screen = await page.render(MyCounter)
await screen.getByRole('button', { name: 'Increment' }).click()
await expect.element(screen.getByText('Count: 1')).toBeVisible()
})You can also import render directly from @nuxt/test-utils/browser:
// @noErrors
import type { Component } from 'vue'
declare module '#components' {
export const MyCounter: Component
}
// ---cut---
import { expect, it } from 'vitest'
import { render } from '@nuxt/test-utils/browser'
import { MyCounter } from '#components'
it('can render using the render helper', async () => {
const screen = await render(MyCounter)
await screen.getByRole('button', { name: 'Increment' }).click()
await expect.element(screen.getByText('Count: 1')).toBeVisible()
})The options object accepts @vue/test-utils mount options (use container instead of attachTo) and the following properties:
route: the initial route, orfalseto skip the initial route change (default/).spy: enable spy component setup state (defaultfalse). See themountSuspendedexample above.container: customHTMLElementcontainer to render into (use this option instead of@vue/test-utilsattachTo).baseElement: custom baseHTMLElement(defaultdocument.body).
The return object includes the following properties:
container: the containerHTMLElementthe component is rendered into.baseElement: the baseHTMLElement(defaultdocument.body).locator: root elementLocator.setupState: the return value of the component setup, mocked when thespyoption is enabled.debug(): print formatted DOM to console.unmount(): unmount the component. Also records anuxt.unmounttrace mark.emitted(): get emitted events.rerender(props): re-render the component with new props. Also records anuxt.rerendertrace mark.
End-To-End Testing
For end-to-end testing, we support Vitest, Jest, Cucumber and Playwright as test runners.
Setup
In each describe block where you are taking advantage of the @nuxt/test-utils/e2e helper methods, you will need to set up the test context before beginning.
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', () => {
// ...
})
})Behind the scenes, setup performs a number of tasks in beforeAll, beforeEach, afterEach and afterAll to set up the Nuxt test environment correctly.
Please use the options below for the setup method.
Nuxt Config
rootDir: Path to a directory with a Nuxt app to be put under test.- Type:
string - Default:
'.'
- Type:
configFile: Name of the configuration file.- Type:
string - Default:
'nuxt.config'
- Type:
Timings
setupTimeout: The amount of time (in milliseconds) to allow forsetupTestto complete its work (which could include building or generating files for a Nuxt application, depending on the options that are passed).- Type:
number - Default:
120000or240000on windows
- Type:
teardownTimeout: The amount of time (in milliseconds) to allow tearing down the test environment, such as closing the browser.- Type:
number - Default:
30000
- Type:
Features
build: Whether to run a separate build step.- Type:
boolean - Default:
true(falseifbrowserorserveris disabled, or if ahostis provided)
- Type:
server: Whether to launch a server to respond to requests in the test suite.- Type:
boolean - Default:
true(falseif ahostis provided)
- Type:
port: If provided, set the launched test server port to the value.- Type:
number | undefined - Default:
undefined
- Type:
host: If provided, a URL to use as the test target instead of building and running a new server. Useful for running "real" end-to-end tests against a deployed version of your application, or against an already running local server (which may provide a significant reduction in test execution timings). See the target host end-to-end example below.- Type:
string - Default:
undefined
- Type:
browser: Under the hood, Nuxt test utils usesplaywrightto carry out browser testing. If this option is set, a browser will be launched and can be controlled in the subsequent test suite.- Type:
boolean - Default:
false
- Type:
browserOptionsType:
objectwith the following propertiestype: The type of browser to launch - eitherchromium,firefoxorwebkitlaunch:objectof options that will be passed to playwright when launching the browser. See full API reference.
runner: Specify the runner for the test suite. Currently, Vitest is recommended.- Type:
'vitest' | 'jest' | 'cucumber' - Default:
'vitest'
- Type:
logLevel: Overrides the consola log level for the server subprocess. (use NUXT_TEST_LOG_LEVEL environment variable to override)- Type:
number - Default:
1
- Type:
captureServerLogs: Whether to capture server process output instead of inheriting stdio. Whentrue(default), server stdout/stderr is suppressed from the console and accessible viagetServerLogs(). Set tofalseto restore the old inherit-stdio behaviour (useful when debugging a test locally).- Type:
boolean - Default:
true
- Type:
Target host end-to-end example
A common use-case for end-to-end testing is running the tests against a deployed application running in the same environment typically used for Production.
For local development or automated deploy pipelines, testing against a separate local server can be more efficient and is typically faster than allowing the test framework to rebuild between tests.
To utilize a separate target host for end-to-end tests, simply provide the host property of the setup function with the desired URL.
import { createPage, setup } from '@nuxt/test-utils/e2e'
import { describe, expect, it } 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)
})
})APIs
$fetch(url)
Get the HTML of a server-rendered page.
import { $fetch } from '@nuxt/test-utils/e2e'
const html = await $fetch('/')fetch(url)
Get the response of a server-rendered page.
import { fetch } from '@nuxt/test-utils/e2e'
const res = await fetch('/')
const { body, headers } = resurl(path)
Get the full URL for a given page (including the port the test server is running on.)
import { url } from '@nuxt/test-utils/e2e'
const pageUrl = url('/page')
// 'http://localhost:6840/page'getServerLogs()
Returns the lines captured from the server subprocess's stdout/stderr since the last startServer() call (or clearServerLogs()). Only populated when captureServerLogs is true (the default).
import { expect, it, vi } from 'vitest'
import { $fetch, clearServerLogs, getServerLogs } from '@nuxt/test-utils/e2e'
it('captures console.log output from a server route', async () => {
clearServerLogs()
await $fetch('/api/log-test')
await vi.waitFor(() => {
expect(getServerLogs().some(line => line.includes('[test] server-log-marker'))).toBe(true)
})
})clearServerLogs()
Clears the captured server log lines. Useful between requests when you want to assert only on the logs produced by a specific operation.
Testing in a Browser
We provide built-in support using Playwright within @nuxt/test-utils, either programmatically or via the Playwright test runner.
createPage(url)
Within vitest, jest or cucumber, you can create a configured Playwright browser instance with createPage, and (optionally) point it at a path from the running server. You can find out more about the API methods available in the Playwright documentation.
When you pass a path, createPage waits for your Nuxt app to finish hydrating before it resolves. On later navigations, pass waitUntil: 'hydration' to page.goto to wait for hydration again.
import { createPage, url } from '@nuxt/test-utils/e2e'
const page = await createPage('/page')
// you can access all the Playwright APIs from the `page` variable
await page.goto(url('/other-page'), { waitUntil: 'hydration' })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-utilsyarn add --dev @playwright/test @nuxt/test-utilspnpm add -D @playwright/test @nuxt/test-utilsbun add --dev @playwright/test @nuxt/test-utilsdeno add --dev npm:@playwright/test npm:@nuxt/test-utilsYou can provide global Nuxt configuration, with the same configuration details as the setup() function mentioned earlier in this section.
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)),
},
},
// ...
})Your test file should then use expect and test directly from @nuxt/test-utils/playwright:
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!')
})You can alternatively configure your Nuxt server directly within your test file:
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!')
})