@nuxt/test-utils-nightly 3.8.2-1701501460.05dbe7f → 3.8.2-1701549256.62a6ffe

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/config.mjs CHANGED
@@ -1,7 +1,6 @@
1
1
  import { defineConfig } from 'vite';
2
- import vuePlugin from '@vitejs/plugin-vue';
3
- import viteJsxPlugin from '@vitejs/plugin-vue-jsx';
4
2
  import { defu } from 'defu';
3
+ import { createResolver } from '@nuxt/kit';
5
4
 
6
5
  async function startNuxtAndGetViteConfig(rootDir = process.cwd(), overrides) {
7
6
  const { loadNuxt, buildNuxt } = await import('@nuxt/kit');
@@ -23,7 +22,7 @@ async function startNuxtAndGetViteConfig(rootDir = process.cwd(), overrides) {
23
22
  );
24
23
  }
25
24
  const promise = new Promise((resolve, reject) => {
26
- nuxt.hook("vite:extendConfig", (viteConfig, { isClient }) => {
25
+ nuxt.hook("vite:configResolved", (viteConfig, { isClient }) => {
27
26
  if (isClient) {
28
27
  resolve({ nuxt, viteConfig });
29
28
  throw new Error("_stop_");
@@ -37,30 +36,19 @@ async function startNuxtAndGetViteConfig(rootDir = process.cwd(), overrides) {
37
36
  }).finally(() => nuxt.close());
38
37
  return promise;
39
38
  }
40
- const vuePlugins = {
41
- "vite:vue": [vuePlugin, "vue"],
42
- "vite:vue-jsx": [viteJsxPlugin, "vueJsx"]
43
- };
44
39
  async function getVitestConfigFromNuxt(options, overrides) {
40
+ var _a;
45
41
  const { rootDir = process.cwd(), ..._overrides } = overrides || {};
46
- if (!options)
42
+ if (!options) {
47
43
  options = await startNuxtAndGetViteConfig(rootDir, {
48
44
  test: true,
49
45
  ..._overrides
50
46
  });
51
- options.viteConfig.plugins = options.viteConfig.plugins || [];
52
- options.viteConfig.plugins = options.viteConfig.plugins.filter(
47
+ }
48
+ (_a = options.viteConfig).plugins || (_a.plugins = []);
49
+ options.viteConfig.plugins = options.viteConfig.plugins?.filter(
53
50
  (p) => p?.name !== "nuxt:import-protection"
54
51
  );
55
- for (const name in vuePlugins) {
56
- if (!options.viteConfig.plugins?.some((p) => p?.name === name)) {
57
- const [plugin, key] = vuePlugins[name];
58
- options.viteConfig.plugins.unshift(
59
- // @ts-expect-error mismatching component options
60
- plugin(options.viteConfig[key])
61
- );
62
- }
63
- }
64
52
  const resolvedConfig = defu(
65
53
  // overrides
66
54
  {
@@ -82,17 +70,25 @@ async function getVitestConfigFromNuxt(options, overrides) {
82
70
  ["{test,tests}/nuxt/**.*", "nuxt"]
83
71
  ],
84
72
  deps: {
73
+ // TODO: move to server.deps.inline when we update to vite v1
85
74
  inline: [
86
75
  // vite-node defaults
87
76
  /\/node_modules\/(.*\/)?(nuxt|nuxt3|nuxt-nightly)\//,
88
77
  /^#/,
89
78
  // additional deps
90
79
  "@nuxt/test-utils",
80
+ "@nuxt/test-utils-nightly",
81
+ "@nuxt/test-utils-edge",
91
82
  "vitest-environment-nuxt",
92
83
  ...options.nuxt.options.build.transpile.filter(
93
84
  (r) => typeof r === "string" || r instanceof RegExp
94
85
  )
95
- ]
86
+ ],
87
+ optimizer: {
88
+ web: {
89
+ enabled: false
90
+ }
91
+ }
96
92
  }
97
93
  }
98
94
  },
@@ -131,6 +127,11 @@ async function getVitestConfigFromNuxt(options, overrides) {
131
127
  }
132
128
  );
133
129
  delete resolvedConfig.define["process.browser"];
130
+ if (!Array.isArray(resolvedConfig.test.setupFiles)) {
131
+ resolvedConfig.test.setupFiles = [resolvedConfig.test.setupFiles].filter(Boolean);
132
+ }
133
+ const resolver = createResolver(import.meta.url);
134
+ resolvedConfig.test.setupFiles.unshift(resolver.resolve("./runtime/entry"));
134
135
  return resolvedConfig;
135
136
  }
136
137
  function defineVitestConfig(config = {}) {
package/dist/index.d.mts CHANGED
@@ -37,6 +37,11 @@ interface TestContext {
37
37
  url?: string;
38
38
  serverProcess?: ExecaChildProcess;
39
39
  mockFn?: Function;
40
+ /**
41
+ * Functions to run on the vitest `afterAll` hook.
42
+ * Useful for removing anything created during the test.
43
+ */
44
+ teardown?: (() => void)[];
40
45
  }
41
46
  interface TestHooks {
42
47
  beforeEach: () => void;
package/dist/index.d.ts CHANGED
@@ -37,6 +37,11 @@ interface TestContext {
37
37
  url?: string;
38
38
  serverProcess?: ExecaChildProcess;
39
39
  mockFn?: Function;
40
+ /**
41
+ * Functions to run on the vitest `afterAll` hook.
42
+ * Useful for removing anything created during the test.
43
+ */
44
+ teardown?: (() => void)[];
40
45
  }
41
46
  interface TestHooks {
42
47
  beforeEach: () => void;
package/dist/index.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
  import { u as useTestContext, a as url, c as createTestContext, s as setTestContext, b as stopServer, d as startServer } from './shared/test-utils-nightly.ddf5bsCK.mjs';
2
2
  export { $ as $fetch, e as exposeContextToEnv, f as fetch, i as isDev, r as recoverContextFromEnv } from './shared/test-utils-nightly.ddf5bsCK.mjs';
3
3
  import { consola } from 'consola';
4
- import { promises, existsSync } from 'node:fs';
4
+ import { existsSync, promises } from 'node:fs';
5
5
  import { resolve } from 'node:path';
6
6
  import { defu } from 'defu';
7
7
  import * as _kit from '@nuxt/kit';
@@ -83,12 +83,12 @@ async function loadFixture() {
83
83
  ctx.options.rootDir = resolveRootDir();
84
84
  if (!ctx.options.dev) {
85
85
  const randomId = Math.random().toString(36).slice(2, 8);
86
- const buildDir = ctx.options.buildDir || resolve(ctx.options.rootDir, ".nuxt", randomId);
86
+ const buildDir2 = ctx.options.buildDir || resolve(ctx.options.rootDir, ".nuxt", "test", randomId);
87
87
  ctx.options.nuxtConfig = defu(ctx.options.nuxtConfig, {
88
- buildDir,
88
+ buildDir: buildDir2,
89
89
  nitro: {
90
90
  output: {
91
- dir: resolve(buildDir, "output")
91
+ dir: resolve(buildDir2, "output")
92
92
  }
93
93
  }
94
94
  });
@@ -99,7 +99,12 @@ async function loadFixture() {
99
99
  overrides: ctx.options.nuxtConfig,
100
100
  configFile: ctx.options.configFile
101
101
  });
102
- await promises.mkdir(ctx.nuxt.options.buildDir, { recursive: true });
102
+ const buildDir = ctx.nuxt.options.buildDir;
103
+ if (!existsSync(buildDir)) {
104
+ await promises.mkdir(buildDir, { recursive: true });
105
+ ctx.teardown = ctx.teardown || [];
106
+ ctx.teardown.push(() => promises.rm(buildDir, { recursive: true, force: true }));
107
+ }
103
108
  }
104
109
  async function buildFixture() {
105
110
  const ctx = useTestContext();
@@ -151,6 +156,7 @@ function createTest(options) {
151
156
  if (ctx.browser) {
152
157
  await ctx.browser.close();
153
158
  }
159
+ await Promise.all((ctx.teardown || []).map((fn) => fn()));
154
160
  };
155
161
  const setup2 = async () => {
156
162
  if (ctx.options.fixture) {
package/dist/module.mjs CHANGED
@@ -1,20 +1,19 @@
1
1
  import { pathToFileURL } from 'node:url';
2
- import { useNuxt, resolveIgnorePatterns, addVitePlugin, defineNuxtModule, resolvePath, logger } from '@nuxt/kit';
2
+ import { resolvePath, useNuxt, resolveIgnorePatterns, addVitePlugin, defineNuxtModule, createResolver, logger } from '@nuxt/kit';
3
3
  import { mergeConfig } from 'vite';
4
- import { getVitestConfigFromNuxt } from './config.mjs';
5
4
  import { getPort } from 'get-port-please';
6
5
  import { h } from 'vue';
7
6
  import { debounce } from 'perfect-debounce';
8
7
  import { isCI } from 'std-env';
8
+ import { defu } from 'defu';
9
+ import { getVitestConfigFromNuxt } from './config.mjs';
9
10
  import { walk } from 'estree-walker';
10
11
  import MagicString from 'magic-string';
11
12
  import { normalize, resolve } from 'node:path';
12
13
  import { createUnplugin } from 'unplugin';
13
- import '@vitejs/plugin-vue';
14
- import '@vitejs/plugin-vue-jsx';
15
- import 'defu';
14
+ import { readFileSync } from 'node:fs';
16
15
 
17
- const PLUGIN_NAME = "nuxt:vitest:mock-transform";
16
+ const PLUGIN_NAME$1 = "nuxt:vitest:mock-transform";
18
17
  const HELPER_MOCK_IMPORT = "mockNuxtImport";
19
18
  const HELPER_MOCK_COMPONENT = "mockComponent";
20
19
  const HELPER_MOCK_HOIST = "__NUXT_VITEST_MOCKS";
@@ -153,17 +152,11 @@ const createMockPlugin = (ctx) => createUnplugin(() => {
153
152
  ([from, mocks]) => {
154
153
  importPathsList.add(from);
155
154
  const lines = [
156
- `vi.mock(${JSON.stringify(
157
- from
158
- )}, async (importOriginal) => {`,
159
- ` const mocks = global.${HELPER_MOCK_HOIST}`,
160
- ` if (!mocks[${JSON.stringify(
161
- from
162
- )}]) { mocks[${JSON.stringify(
163
- from
164
- )}] = { ...await importOriginal(${JSON.stringify(
165
- from
166
- )}) } }`
155
+ `vi.mock(${JSON.stringify(from)}, async (importOriginal) => {`,
156
+ ` const mocks = globalThis.${HELPER_MOCK_HOIST}`,
157
+ ` if (!mocks[${JSON.stringify(from)}]) {`,
158
+ ` mocks[${JSON.stringify(from)}] = { ...await importOriginal(${JSON.stringify(from)}) }`,
159
+ ` }`
167
160
  ];
168
161
  for (const mock of mocks) {
169
162
  if (mock.import.name === "default") {
@@ -172,9 +165,7 @@ const createMockPlugin = (ctx) => createUnplugin(() => {
172
165
  );
173
166
  } else {
174
167
  lines.push(
175
- ` mocks[${JSON.stringify(from)}][${JSON.stringify(
176
- mock.name
177
- )}] = await (${mock.factory})();`
168
+ ` mocks[${JSON.stringify(from)}][${JSON.stringify(mock.name)}] = await (${mock.factory})();`
178
169
  );
179
170
  }
180
171
  }
@@ -201,7 +192,7 @@ const createMockPlugin = (ctx) => createUnplugin(() => {
201
192
  if (!mockLines.length)
202
193
  return;
203
194
  s.prepend(`vi.hoisted(() => {
204
- if(!global.${HELPER_MOCK_HOIST}){
195
+ if(!globalThis.${HELPER_MOCK_HOIST}){
205
196
  vi.stubGlobal(${JSON.stringify(HELPER_MOCK_HOIST)}, {})
206
197
  }
207
198
  });
@@ -222,28 +213,29 @@ const createMockPlugin = (ctx) => createUnplugin(() => {
222
213
  };
223
214
  }
224
215
  return {
225
- name: PLUGIN_NAME,
216
+ name: PLUGIN_NAME$1,
226
217
  enforce: "post",
227
218
  vite: {
228
219
  transform,
229
220
  // Place Vitest's mock plugin after all Nuxt plugins
230
- configResolved(config) {
231
- const firstSetupFile = Array.isArray(config.test?.setupFiles) ? config.test.setupFiles[0] : config.test?.setupFiles;
221
+ async configResolved(config) {
222
+ const firstSetupFile = Array.isArray(config.test?.setupFiles) ? config.test.setupFiles.find((p) => !p.includes("runtime/entry")) : config.test?.setupFiles;
232
223
  if (firstSetupFile) {
233
- resolvedFirstSetupFile = normalize(resolve(firstSetupFile));
224
+ resolvedFirstSetupFile = await resolvePath(normalize(resolve(firstSetupFile)));
234
225
  }
235
226
  const plugins = config.plugins || [];
236
- const mockPluginIndex = plugins.findIndex(
237
- (i) => i.name === "vite:mocks" || i.name === "vitest:mocks"
238
- );
227
+ const vitestPlugins = plugins.filter((p) => (p.name === "vite:mocks" || p.name.startsWith("vitest:")) && (p.enforce || p.order) === "post");
239
228
  const lastNuxt = findLastIndex(
240
229
  plugins,
241
230
  (i) => i.name?.startsWith("nuxt:")
242
231
  );
243
- if (mockPluginIndex !== -1 && lastNuxt !== -1) {
244
- if (mockPluginIndex < lastNuxt) {
245
- const [mockPlugin] = plugins.splice(mockPluginIndex, 1);
246
- plugins.splice(lastNuxt, 0, mockPlugin);
232
+ if (lastNuxt === -1)
233
+ return;
234
+ for (const plugin of vitestPlugins) {
235
+ const index = plugins.indexOf(plugin);
236
+ if (index < lastNuxt) {
237
+ plugins.splice(index, 1);
238
+ plugins.splice(lastNuxt, 0, plugin);
247
239
  }
248
240
  }
249
241
  }
@@ -307,6 +299,27 @@ function setupImportMocking() {
307
299
  addVitePlugin(createMockPlugin(ctx).vite());
308
300
  }
309
301
 
302
+ const PLUGIN_NAME = "nuxt:vitest:nuxt-root-stub";
303
+ const NuxtRootStubPlugin = createUnplugin((options) => {
304
+ return {
305
+ name: PLUGIN_NAME,
306
+ enforce: "pre",
307
+ vite: {
308
+ async resolveId(id) {
309
+ if (id.endsWith("nuxt-vitest-app-entry")) {
310
+ return id;
311
+ }
312
+ },
313
+ async load(id) {
314
+ if (id.endsWith("nuxt-vitest-app-entry")) {
315
+ const entryContents = readFileSync(options.entry, "utf-8");
316
+ return entryContents.replace("#build/root-component.mjs", options.rootStubPath);
317
+ }
318
+ }
319
+ }
320
+ };
321
+ });
322
+
310
323
  const vitePluginBlocklist = ["vite-plugin-vue-inspector", "vite-plugin-inspect"];
311
324
  const module = defineNuxtModule({
312
325
  meta: {
@@ -321,6 +334,11 @@ const module = defineNuxtModule({
321
334
  if (nuxt.options.test || nuxt.options.dev) {
322
335
  setupImportMocking();
323
336
  }
337
+ const resolver = createResolver(import.meta.url);
338
+ addVitePlugin(NuxtRootStubPlugin.vite({
339
+ entry: await resolvePath("#app/entry", { alias: nuxt.options.alias }),
340
+ rootStubPath: await resolvePath(resolver.resolve("./runtime/nuxt-root"))
341
+ }));
324
342
  if (!nuxt.options.dev)
325
343
  return;
326
344
  if (nuxt.options.test && nuxt.options.app.rootId === "__nuxt") {
@@ -330,7 +348,7 @@ const module = defineNuxtModule({
330
348
  return;
331
349
  const rawViteConfigPromise = new Promise((resolve) => {
332
350
  nuxt.hook("app:resolve", () => {
333
- nuxt.hook("vite:extendConfig", (config, { isClient }) => {
351
+ nuxt.hook("vite:configResolved", (config, { isClient }) => {
334
352
  if (isClient)
335
353
  resolve(config);
336
354
  });
@@ -347,7 +365,7 @@ const module = defineNuxtModule({
347
365
  }, 100);
348
366
  async function start() {
349
367
  const rawViteConfig = mergeConfig({}, await rawViteConfigPromise);
350
- const viteConfig = await getVitestConfigFromNuxt({ nuxt, viteConfig: rawViteConfig });
368
+ const viteConfig = await getVitestConfigFromNuxt({ nuxt, viteConfig: defu({ test: options.vitestConfig }, rawViteConfig) });
351
369
  viteConfig.plugins = (viteConfig.plugins || []).filter((p) => {
352
370
  return !vitePluginBlocklist.includes(p?.name);
353
371
  });
@@ -367,9 +385,8 @@ const module = defineNuxtModule({
367
385
  }
368
386
  };
369
387
  const watchMode = !process.env.NUXT_VITEST_DEV_TEST && !isCI;
370
- const vitestConfig = watchMode ? {
388
+ const overrides = watchMode ? {
371
389
  passWithNoTests: true,
372
- ...options.vitestConfig,
373
390
  reporters: options.logToConsole ? [
374
391
  ...toArray(options.vitestConfig?.reporters ?? ["default"]),
375
392
  customReporter
@@ -381,12 +398,8 @@ const module = defineNuxtModule({
381
398
  api: {
382
399
  port: PORT
383
400
  }
384
- } : {
385
- ...options.vitestConfig,
386
- watch: false
387
- };
388
- viteConfig.configFile = false;
389
- const promise2 = startVitest("test", [], vitestConfig, viteConfig);
401
+ } : { watch: false };
402
+ const promise2 = startVitest("test", [], defu(overrides, viteConfig.test), viteConfig);
390
403
  promise2.catch(() => process.exit(1));
391
404
  if (watchMode) {
392
405
  logger.info(`Vitest UI starting on ${URL}`);
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,8 @@
1
+ if (typeof window !== "undefined" && // @ts-expect-error undefined property
2
+ window.__NUXT_VITEST_ENVIRONMENT__) {
3
+ await import("#app/nuxt-vitest-app-entry").then((r) => r.default());
4
+ const nuxtApp = useNuxtApp();
5
+ await nuxtApp.callHook("page:finish");
6
+ useRouter().afterEach(() => nuxtApp.callHook("page:finish"));
7
+ }
8
+ export {};
@@ -0,0 +1,4 @@
1
+ declare const _default: import("vue").DefineComponent<{}, () => import("vue").VNode<import("vue").RendererNode, import("vue").RendererElement, {
2
+ [key: string]: any;
3
+ }>, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps, Readonly<import("vue").ExtractPropTypes<{}>>, {}, {}>;
4
+ export default _default;
@@ -0,0 +1,21 @@
1
+ import { Suspense, defineComponent, h, onErrorCaptured, provide } from "vue";
2
+ import { isNuxtError, useNuxtApp, useRoute } from "#imports";
3
+ import { PageRouteSymbol } from "#app/components/injections";
4
+ export default defineComponent({
5
+ setup(_options, { slots }) {
6
+ const nuxtApp = useNuxtApp();
7
+ provide(PageRouteSymbol, useRoute());
8
+ const done = nuxtApp.deferHydration();
9
+ const results = nuxtApp.hooks.callHookWith((hooks) => hooks.map((hook) => hook()), "vue:setup");
10
+ if (import.meta.dev && results && results.some((i) => i && "then" in i)) {
11
+ console.error("[nuxt] Error in `vue:setup`. Callbacks must be synchronous.");
12
+ }
13
+ onErrorCaptured((err, target, info) => {
14
+ nuxtApp.hooks.callHook("vue:error", err, target, info).catch((hookError) => console.error("[nuxt] Error in `vue:error` hook", hookError));
15
+ if (isNuxtError(err) && (err.fatal || err.unhandled)) {
16
+ return false;
17
+ }
18
+ });
19
+ return () => h(Suspense, { onResolve: done }, slots.default?.());
20
+ }
21
+ });
@@ -7,6 +7,7 @@ type NuxtBuiltinEnvironment = 'happy-dom' | 'jsdom';
7
7
  interface NuxtWindow extends Window {
8
8
  __app: App;
9
9
  __registry: Set<string>;
10
+ __NUXT_VITEST_ENVIRONMENT__?: boolean;
10
11
  __NUXT__: any;
11
12
  $fetch: any;
12
13
  fetch: any;
@@ -7,6 +7,7 @@ type NuxtBuiltinEnvironment = 'happy-dom' | 'jsdom';
7
7
  interface NuxtWindow extends Window {
8
8
  __app: App;
9
9
  __registry: Set<string>;
10
+ __NUXT_VITEST_ENVIRONMENT__?: boolean;
10
11
  __NUXT__: any;
11
12
  $fetch: any;
12
13
  fetch: any;
@@ -72,6 +72,7 @@ const index = {
72
72
  happyDom: { url },
73
73
  jsdom: { url }
74
74
  }));
75
+ win.__NUXT_VITEST_ENVIRONMENT__ = true;
75
76
  win.__NUXT__ = {
76
77
  serverRendered: false,
77
78
  config: {
@@ -160,13 +161,12 @@ const index = {
160
161
  registry.add(`${manifestOutputPath}/latest.json`);
161
162
  registry.add(`${manifestOutputPath}/meta/test.json`);
162
163
  registry.add(`${manifestOutputPath}/meta/dev.json`);
163
- await import('#app/entry').then((r) => r.default());
164
164
  return {
165
165
  // called after all tests with this env have been run
166
166
  teardown() {
167
- teardown();
168
167
  keys.forEach((key) => delete global[key]);
169
168
  originals.forEach((v, k) => global[k] = v);
169
+ teardown();
170
170
  }
171
171
  };
172
172
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nuxt/test-utils-nightly",
3
- "version": "3.8.2-1701501460.05dbe7f",
3
+ "version": "3.8.2-1701549256.62a6ffe",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/nuxt/test-utils.git"
@@ -65,8 +65,6 @@
65
65
  "@testing-library/vue": "8.0.1",
66
66
  "@types/estree": "1.0.5",
67
67
  "@types/jsdom": "21.1.6",
68
- "@vitejs/plugin-vue": "4.5.1",
69
- "@vitejs/plugin-vue-jsx": "3.1.0",
70
68
  "@vitest/ui": "0.33.0",
71
69
  "@vue/test-utils": "2.4.3",
72
70
  "changelogen": "0.5.5",
@@ -82,15 +80,13 @@
82
80
  "unbuild": "latest",
83
81
  "unimport": "3.6.0",
84
82
  "vite": "5.0.4",
85
- "vitest": "0.33.0",
83
+ "vitest": "0.34.6",
86
84
  "vue-router": "4.2.5",
87
85
  "vue-tsc": "1.8.24"
88
86
  },
89
87
  "peerDependencies": {
90
88
  "@jest/globals": "^29.5.0",
91
89
  "@testing-library/vue": "^7.0.0 || ^8.0.1",
92
- "@vitejs/plugin-vue": "*",
93
- "@vitejs/plugin-vue-jsx": "*",
94
90
  "@vitest/ui": "0.33.0",
95
91
  "@vue/test-utils": "^2.4.2",
96
92
  "h3": "*",
@@ -98,7 +94,7 @@
98
94
  "jsdom": "^22.0.0 || ^23.0.0",
99
95
  "playwright-core": "^1.34.3",
100
96
  "vite": "*",
101
- "vitest": "^0.24.5 || ^0.26.0 || ^0.27.0 || ^0.28.0 || ^0.29.0 || ^0.30.0 || ^0.33.0",
97
+ "vitest": "^0.24.5 || ^0.26.0 || ^0.27.0 || ^0.28.0 || ^0.29.0 || ^0.30.0 || ^0.33.0 || ^0.34.6",
102
98
  "vue": "^3.3.4",
103
99
  "vue-router": "^4.0.0"
104
100
  },