Skip to content

Conversation

@yamachi4416
Copy link
Collaborator

@yamachi4416 yamachi4416 commented Dec 15, 2025

πŸ”— Linked issue

resolves #750
resolves #836
resolves #1185
resolves #1496

❓ Type of change

  • πŸ“– Documentation (updates to the documentation or readme)
  • 🐞 Bug fix (a non-breaking change that fixes an issue)
  • πŸ‘Œ Enhancement (improving an existing functionality)
  • ✨ New feature (a non-breaking change that adds functionality)
  • 🧹 Chore (updates to the build process or auxiliary tools and libraries)
  • ⚠️ Breaking change (fix or feature that would cause existing functionality to change)

πŸ“š Description

The timing for starting Nuxt has been moved from setupFiles to beforeAll hook. This change enables mocking of composables that are loaded during Nuxt initialization.

Please note that migration is required for certain cases, such as test code that partially mocks Nuxt core composables, or code that mounts components outside of the test suite (which requires Nuxt to be initialized). Modifying the test code is required for these patterns to function.

since mockNuxtImport now provides the original composable in its factory function, test code will be updated to mock only the necessary parts using this feature. This approach ensures that Nuxt initialization does not fail even when partially mocking core composables.

For cases where components are mounted outside of the test suite, there are options to either move the mounting logic inside the test suite or perform the mount within beforeAll hook.

Reproductions

@pkg-pr-new
Copy link

pkg-pr-new bot commented Dec 15, 2025

Open in StackBlitz

npm i https://pkg.pr.new/@nuxt/test-utils@1516

commit: 8396dcc

@yamachi4416 yamachi4416 marked this pull request as ready for review December 15, 2025 11:50
@yamachi4416
Copy link
Collaborator Author

I’ve realized there are some points I haven't fully considered yet, so I’ll revert this to a draft for further refinement. My apologies.

@yamachi4416 yamachi4416 marked this pull request as draft December 16, 2025 11:34
@yamachi4416 yamachi4416 force-pushed the feat/support-mock-in-middleware branch from 1823a5c to c2fbe7b Compare December 19, 2025 12:08
@yamachi4416 yamachi4416 changed the title fix(runtime): make mockNuxtImport work inside middleware feat(runtime): add startOn environment option Dec 19, 2025
@yamachi4416 yamachi4416 force-pushed the feat/support-mock-in-middleware branch from c2fbe7b to 4a89806 Compare December 19, 2025 16:40
@yamachi4416 yamachi4416 force-pushed the feat/support-mock-in-middleware branch from 4a89806 to 575fbba Compare December 19, 2025 17:02
@yamachi4416 yamachi4416 force-pushed the feat/support-mock-in-middleware branch 2 times, most recently from 7e235ea to 297fb17 Compare January 6, 2026 12:43
@danielroe
Copy link
Member

danielroe commented Jan 6, 2026

@yamachi4416 are you on Discord or Bluesky/Twitter? would you mind sending me a DM (nothing bad!)?

@yamachi4416
Copy link
Collaborator Author

It turns out that referencing __vitest_worker__ was indeed a hack, and it didn't work in vitest v4...

@yamachi4416 yamachi4416 force-pushed the feat/support-mock-in-middleware branch 3 times, most recently from 145cf17 to e71dfc7 Compare January 10, 2026 03:49
@yamachi4416
Copy link
Collaborator Author

I wish I could have supported @vitest-environment-options, but I have created a separate issue for that.

@yamachi4416 yamachi4416 marked this pull request as ready for review January 10, 2026 05:00
Copy link
Member

@danielroe danielroe left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what are the downsides of using beforeAll?

(we could, for example, make this the new default)

@yamachi4416
Copy link
Collaborator Author

yamachi4416 commented Jan 16, 2026

thank you for the review.

the main downsides of using beforeAll is that it could break existing tests. for example, some tests might be mocking only parts of nuxt's built-in composables like useRuntimeConfig. mounting components outside of a test suite. there could be other side effects, but it's hard to imagine what they might be...

if mockNuxtImport's factory function could receive original, users would be able to merge it with the mock, solving the composable issue. Mounting problems are also fixable, but the reality is that both solutions would require manual updates to the test code.

I'm starting to feel that it might be better to make beforeAll our new default. How do you think we should go about this?

@danielroe
Copy link
Member

agreed- I think beforeAll makes sense if it allows proper mocking, and we can document in v4 release notes as a breaking change. would be nice to give people some migration examples

@yamachi4416
Copy link
Collaborator Author

thank you for the advice.
the goal is to try making beforeAll the new default and migrating the existing tests.
this PR will be moved to draft status while the work is in progress.

@yamachi4416 yamachi4416 marked this pull request as draft January 21, 2026 13:04
@yamachi4416 yamachi4416 force-pushed the feat/support-mock-in-middleware branch from e71dfc7 to 4bf9064 Compare January 24, 2026 00:46
@yamachi4416 yamachi4416 changed the title feat(runtime): add startOn environment option feat(runtime)!: change nuxt start timing to beforeAll hook Jan 24, 2026
@yamachi4416 yamachi4416 marked this pull request as ready for review January 24, 2026 02:25
@coderabbitai
Copy link

coderabbitai bot commented Jan 24, 2026

πŸ“ Walkthrough

Walkthrough

Adds a global counter composable, a plugin that provides it, and a route middleware that uses the counter to conditionally navigate. Extends the inject-value plugin to provide and export a second Symbol-based injection. Introduces new components exercising Nuxt core composables and updates an existing component to inject two values. Adds and expands many Vitest tests covering composable/plugin/middleware behavior, mocking of Nuxt core composables and vue-router, and lifecycle handling. Moves runtime entry Nuxt setup into a Vitest beforeAll hook.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

πŸš₯ Pre-merge checks | βœ… 4 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
βœ… Passed checks (4 passed)
Check name Status Explanation
Title check βœ… Passed The title clearly describes the main change: moving Nuxt startup from setupFiles to a beforeAll hook. It uses the conventional commit format with breaking change indicator (!), is concise, and directly reflects the core modification.
Description check βœ… Passed The description explains the rationale (enabling mocking of composables during initialization), documents the breaking change, references linked issues (#750, #836, #1185, #1496), and provides migration guidance for affected test patterns.
Linked Issues check βœ… Passed The PR implements changes addressing all four linked issues: #750 and #836 are resolved by enabling Symbol-based provide/inject in tests; #1185 is resolved by ensuring module consistency during Nuxt initialization; #1496 is resolved by allowing mockNuxtImport to receive the original composable for middleware mocking.
Out of Scope Changes check βœ… Passed All changes are in-scope: runtime/entry.ts implements the core beforeAll hook migration; example files demonstrate new patterns (composables, middleware, plugins, components); test files validate the new mocking and timing behavior across various scenarios.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • πŸ“ Generate docstrings
πŸ§ͺ Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❀️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

πŸ€– Fix all issues with AI agents
In `@examples/app-vitest-full/tests/nuxt/middleware.spec.ts`:
- Line 33: The test description for the spec named "can original nuxt core
composable inside middleware" has a typoβ€”add the missing verb to read "can use
original nuxt core composable inside middleware". Update the string in the
it(...) call in tests/nuxt/middleware.spec.ts (the test labelled by that
description) to "can use original nuxt core composable inside middleware".
🧹 Nitpick comments (4)
examples/app-vitest-full/tests/nuxt/mock-vue-router.spec.ts (1)

18-21: Consider removing vi.restoreAllMocks() or verifying expected behavior.

vi.restoreAllMocks() restores spied functions to their original implementations. However, since you're using vi.mock() (which is hoisted and persistent), calling restoreAllMocks() after resetAllMocks() may not behave as intended. The vi.fn(original) wrappers from lines 11 and 15 should persist through resets.

If the intent is just to clear mock call history between tests, vi.resetAllMocks() alone should suffice.

Suggested simplification
   beforeEach(() => {
     vi.resetAllMocks()
-    vi.restoreAllMocks()
   })
examples/app-vitest-full/tests/nuxt/mock-nuxt-composable-1.spec.ts (3)

15-22: Consider Symbol-keyed properties if needed for complete merging.

Object.getOwnPropertyNames captures non-enumerable properties but excludes Symbol-keyed properties. Given the PR objectives mention Symbol-based injection testing (#750, #836), verify this limitation doesn't affect test scenarios. If Symbol keys are needed, consider adding Object.getOwnPropertySymbols:

♻️ Optional enhancement
 function mergeObject<V, T extends Record<string, V>>(target: T, merge: Partial<T>) {
   return {
     ...Object.fromEntries(
-      Object.getOwnPropertyNames(target).map(key => [key, target[key]]),
+      [
+        ...Object.getOwnPropertyNames(target),
+        ...Object.getOwnPropertySymbols(target),
+      ].map(key => [key, target[key as keyof T]]),
     ),
     ...merge,
   } as T
 }

25-28: Clarify the mock reset strategy.

Using both resetAllMocks() and restoreAllMocks() is redundant here. restoreAllMocks() only affects spies created with vi.spyOn(), not vi.fn() mocks. Since mockNuxtImport uses vi.fn(), consider:

  • Use vi.clearAllMocks() if only clearing call history between tests (preserves mock implementations set in nested beforeEach hooks).
  • Use vi.resetAllMocks() alone if resetting implementations is intended.

The nested beforeEach hooks in each describe block re-set implementations anyway, so clearAllMocks() may be more appropriate here.


118-123: Minor inconsistency: spread vs mergeObject.

Line 121 uses the spread operator while other mock implementations use mergeObject. The spread operator only copies enumerable properties, whereas mergeObject handles non-enumerable properties. Consider using mergeObject for consistency:

♻️ Suggested consistency fix
     beforeEach(() => {
       useRouteMock.mockImplementation((...args) => {
         const original = useRouteOriginal(...args)
-        return { ...original, path: '/mocked' }
+        return mergeObject(original, { path: '/mocked' })
       })
     })

@yamachi4416 yamachi4416 force-pushed the feat/support-mock-in-middleware branch from 4bf9064 to bda3496 Compare January 24, 2026 02:37
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

πŸ€– Fix all issues with AI agents
In `@examples/app-vitest-full/tests/nuxt/mock-nuxt-composable-1.spec.ts`:
- Around line 15-21: mergeObject currently uses
Object.getOwnPropertyNames(target) which omits Symbol keys; update the function
to include symbol-keyed properties by collecting both
Object.getOwnPropertyNames(target) and Object.getOwnPropertySymbols(target) (or
use Reflect.ownKeys/Object.getOwnPropertyDescriptors) when building the entries
from the target parameter in mergeObject, and adjust the type constraint (e.g.,
allow symbol keys via PropertyKey or Record<PropertyKey, V>) so symbol
properties are preserved in the returned object before spreading in merge.

@yamachi4416 yamachi4416 marked this pull request as draft January 24, 2026 02:53
@yamachi4416 yamachi4416 force-pushed the feat/support-mock-in-middleware branch from bda3496 to 8396dcc Compare January 24, 2026 02:58
@yamachi4416 yamachi4416 marked this pull request as ready for review January 24, 2026 03:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

2 participants