Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -67,12 +67,13 @@
"dev:prepare": "nuxt prepare && unbuild --stub && pnpm -r dev:prepare"
},
"dependencies": {
"@nuxt/kit": "^4.2.1",
"@nuxt/kit": "^3.20.1",
"c12": "^3.3.2",
"consola": "^3.4.2",
"defu": "^6.1.4",
"destr": "^2.0.5",
"estree-walker": "^3.0.3",
"exsolve": "^1.0.8",
"fake-indexeddb": "^6.2.5",
"get-port-please": "^3.2.0",
"h3": "^1.15.4",
Expand Down Expand Up @@ -128,6 +129,7 @@
"peerDependencies": {
"@cucumber/cucumber": "^10.3.1 || >=11.0.0",
"@jest/globals": "^29.5.0 || >=30.0.0",
"@nuxt/kit": ">=3.20.1",
"@playwright/test": "^1.43.1",
"@testing-library/vue": "^7.0.0 || ^8.0.1",
"@vue/test-utils": "^2.4.2",
Expand All @@ -143,6 +145,9 @@
"@jest/globals": {
"optional": true
},
"@nuxt/kit": {
"optional": true
},
"@playwright/test": {
"optional": true
},
Expand Down Expand Up @@ -170,7 +175,6 @@
},
"resolutions": {
"@cucumber/cucumber": "12.3.0",
"@nuxt/kit": "^4.2.1",
"@nuxt/schema": "4.2.1",
"@nuxt/test-utils": "workspace:*",
"@types/node": "24.10.1",
Expand Down
48 changes: 40 additions & 8 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 3 additions & 2 deletions src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ import type { DotenvOptions } from 'c12'
import type { UserConfig as ViteUserConfig } from 'vite'
import type { DateString } from 'compatx'
import { defu } from 'defu'
import { loadNuxt, buildNuxt, createResolver, findPath } from '@nuxt/kit'
import { createResolver, findPath } from '@nuxt/kit'

import { applyEnv } from './utils'
import { applyEnv, loadKit } from './utils'

interface GetVitestConfigOptions {
nuxt: Nuxt
Expand All @@ -25,6 +25,7 @@ interface LoadNuxtOptions {

// https://github.com/nuxt/framework/issues/6496
async function startNuxtAndGetViteConfig(rootDir = process.cwd(), options: LoadNuxtOptions = {}) {
const { buildNuxt, loadNuxt } = await loadKit(rootDir)
const nuxt = await loadNuxt({
cwd: rootDir,
dev: false,
Expand Down
18 changes: 9 additions & 9 deletions src/e2e/nuxt.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
import { existsSync, promises as fsp } from 'node:fs'
import { resolve } from 'node:path'
import { defu } from 'defu'
import * as _kit from '@nuxt/kit'
import { useTestContext } from './context'

// @ts-expect-error type cast kit default export
const kit: typeof _kit = _kit.default || _kit
import { loadKit } from '../utils'

const isNuxtApp = (dir: string) => {
return existsSync(dir) && (
Expand Down Expand Up @@ -59,7 +56,8 @@ export async function loadFixture() {

// TODO: share Nuxt instance with running Nuxt if possible
if (ctx.options.build) {
ctx.nuxt = await kit.loadNuxt({
const { loadNuxt } = await loadKit(ctx.options.rootDir)
ctx.nuxt = await loadNuxt({
cwd: ctx.options.rootDir,
dev: ctx.options.dev,
overrides: ctx.options.nuxtConfig,
Expand All @@ -78,9 +76,11 @@ export async function loadFixture() {

export async function buildFixture() {
const ctx = useTestContext()
const { buildNuxt, logger } = await loadKit(ctx.options.rootDir)

// Hide build info for test
const prevLevel = kit.logger.level
kit.logger.level = ctx.options.logLevel
await kit.buildNuxt(ctx.nuxt!)
kit.logger.level = prevLevel
const prevLevel = logger.level
logger.level = ctx.options.logLevel
await buildNuxt(ctx.nuxt!)
logger.level = prevLevel
}
1 change: 0 additions & 1 deletion src/experimental.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { $fetch as _$fetch, fetch as _fetch } from 'ofetch'
import * as _kit from '@nuxt/kit'
import { resolve } from 'pathe'
import { stringifyQuery } from 'ufo'
import { useTestContext } from './e2e/context'
Expand Down
9 changes: 6 additions & 3 deletions src/module.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/// <reference types="@nuxt/devtools-kit" />

import { pathToFileURL } from 'node:url'
import { addVitePlugin, createResolver, defineNuxtModule, logger, resolvePath, importModule } from '@nuxt/kit'
import { createResolver, defineNuxtModule, logger, resolvePath, importModule } from '@nuxt/kit'
import type { Vitest, UserConfig as VitestConfig } from 'vitest/node'
import type { Reporter } from 'vitest/reporters'
import type { RunnerTestFile } from 'vitest'
Expand All @@ -11,11 +11,12 @@ import { h } from 'vue'
import { debounce } from 'perfect-debounce'
import { isCI } from 'std-env'
import { defu } from 'defu'
import { join, relative } from 'pathe'

import { getVitestConfigFromNuxt } from './config'
import { setupImportMocking } from './module/mock'
import { NuxtRootStubPlugin } from './module/plugins/entry'
import { join, relative } from 'pathe'
import { loadKit } from './utils'

export interface NuxtVitestOptions {
startOnBoot?: boolean
Expand All @@ -40,9 +41,11 @@ export default defineNuxtModule<NuxtVitestOptions>({
},
async setup(options, nuxt) {
if (nuxt.options.test || nuxt.options.dev) {
setupImportMocking()
await setupImportMocking(nuxt)
}

const { addVitePlugin } = await loadKit(nuxt.options.rootDir)

const resolver = createResolver(import.meta.url)
addVitePlugin(NuxtRootStubPlugin.vite({
entry: await resolvePath('#app/entry', { alias: nuxt.options.alias }),
Expand Down
9 changes: 5 additions & 4 deletions src/module/mock.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
import type { Nuxt } from '@nuxt/schema'
import type { Unimport } from 'unimport'
import { addVitePlugin, resolveIgnorePatterns, useNuxt } from '@nuxt/kit'
import { resolveIgnorePatterns } from '@nuxt/kit'

import { createMockPlugin } from './plugins/mock'
import type { MockPluginContext } from './plugins/mock'
import { loadKit } from '../utils'

/**
* This module is a macro that transforms `mockNuxtImport()` to `vi.mock()`,
* which make it possible to mock Nuxt imports.
*/
export function setupImportMocking() {
const nuxt = useNuxt()

export async function setupImportMocking(nuxt: Nuxt) {
const { addVitePlugin } = await loadKit(nuxt.options.rootDir)
const ctx: MockPluginContext = {
components: [],
imports: [],
Expand Down
9 changes: 3 additions & 6 deletions src/runtime/global-setup.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,14 @@
import * as _kit from '@nuxt/kit'
import { consola } from 'consola'
import { createTest, exposeContextToEnv } from '@nuxt/test-utils/e2e'

// @ts-expect-error type cast kit default export
const kit: typeof _kit = _kit.default || _kit

const options = JSON.parse(process.env.NUXT_TEST_OPTIONS || '{}')
const hooks = createTest(options)

export const setup = async () => {
kit.logger.info('Building Nuxt app...')
consola.info('Building Nuxt app...')
await hooks.beforeAll()
exposeContextToEnv()
kit.logger.info('Running tests...')
consola.info('Running tests...')
}

export const teardown = async () => {
Expand Down
37 changes: 37 additions & 0 deletions src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@

import destr from 'destr'
import { snakeCase } from 'scule'
import { pathToFileURL } from 'node:url'
import { resolveModulePath } from 'exsolve'

type EnvOptions = {
env?: Record<string, any>
Expand Down Expand Up @@ -52,3 +54,38 @@ export function applyEnv(obj: Record<string, any>, opts: EnvOptions, parentKey =
}
return obj
}

export async function loadKit(rootDir: string): Promise<typeof import('@nuxt/kit')> {
try {
const kitPath = resolveModulePath('@nuxt/kit', { from: tryResolveNuxt(rootDir) || rootDir })

let kit: typeof import('@nuxt/kit') = await import(pathToFileURL(kitPath).href)
if (!kit.writeTypes) {
kit = {
...kit,
writeTypes: () => {
throw new Error('`writeTypes` is not available in this version of `@nuxt/kit`. Please upgrade to v3.7 or newer.')
},
}
}
return kit
}
catch (e: any) {
if (e.toString().includes('Cannot find module \'@nuxt/kit\'')) {
throw new Error(
'nuxi requires `@nuxt/kit` to be installed in your project. Try installing `nuxt` v3+ or `@nuxt/bridge` first.',
)
}
throw e
}
}

export function tryResolveNuxt(rootDir: string) {
for (const pkg of ['nuxt-nightly', 'nuxt', 'nuxt3', 'nuxt-edge']) {
const path = resolveModulePath(pkg, { from: rootDir, try: true })
if (path) {
return path
}
}
return null
}
Loading