Repository: nuxt/test-utils (ts)

Issue:
BUG | vitest v3 | `There was an error when mocking a module` when `mockNuxtImport` with existing `vi` import
### Environment

- Operating System: `Linux`
- Node Version:     `v23.5.0`
- Nuxt Version:     `3.15.4`
- CLI Version:      `3.21.1`
- Nitro Version:    `2.10.4`
- Package Manager:  `pnpm@9.15.5`
- Builder:          `-`
- User Config:      `-`
- Runtime Modules:  `-`
- Build Modules:    `-`


### Reproduction

https://github.com/nuxt/test-utils/pull/1128

### Describe the bug

when not using vitest globals and importing and using `vi` and `mockNuxtImport` vitest 3 fails with:

```
Error: [vitest] There was an error when mocking a module. If you are using "vi.mock" factory, make sure there are no top level variables inside, since this call is hoisted to top of the file. Read more: https://vitest.dev/api/vi.html#vi-mock
Caused by: TypeError: Cannot read properties of undefined
```

### Additional context

_No response_

### Logs

```shell-script

```

Pull request:
fix(module): ensure `vi.hoisted` is injected after `vi` import
### 🔗 Linked issue

<!-- Please ensure there is an open issue and mention its number. For example, "resolves #123" -->

### ❓ Type of change

<!-- What types of changes does your code introduce? Put an `x` in all the boxes that apply. -->

- [ ] 📖 Documentation (updates to the documentation or readme)
- [ ] 🐞 Bug fix (a non-breaking change that fixes an issue)
- [x] 👌 Enhancement (improving an existing functionality)
- [ ] ✨ New feature (a non-breaking change that adds functionality)
- [x] 🧹 Chore (updates to the build process or auxiliary tools and libraries)
- [ ] ⚠️ Breaking change (fix or feature that would cause existing functionality to change)

### 📚 Description

This PR fixes #1129 and updates existing vitest example tests to v3.

Some minor linitng issues are fixed as well :)
<!-- Describe your changes in detail. Why is this change required? What problem does it solve? -->

<!----------------------------------------------------------------------
Before creating the pull request, please make sure you do the following:

- Check that there isn't already a PR that solves the problem the same way. If you find a duplicate, please help us reviewing it.
- Read the contribution docs at https://nuxt.com/docs/community/contribution
- Ensure that PR title follows conventional commits (https://www.conventionalcommits.org)
- Update the corresponding documentation if needed.
- Include relevant tests that fail without this PR but pass with it.

Thank you for contributing to Nuxt!
----------------------------------------------------------------------->


Patch:
diff --git a/eslint.config.js b/eslint.config.js
index 351592ee..4aa66de3 100644
--- a/eslint.config.js
+++ b/eslint.config.js
@@ -21,5 +21,6 @@ export default createConfigForNuxt({
 }).append({
   rules: {
     '@typescript-eslint/no-invalid-void-type': 'off',
+    'vue/multi-word-component-names': 'off',
   },
 })
diff --git a/src/module/plugins/mock.ts b/src/module/plugins/mock.ts
index ff53fe65..9e8d95c6 100644
--- a/src/module/plugins/mock.ts
+++ b/src/module/plugins/mock.ts
@@ -228,7 +228,7 @@ export const createMockPlugin = (ctx: MockPluginContext) => createUnplugin(() =>
 
     if (!mockLines.length) return
 
-    s.prepend(`vi.hoisted(() => { 
+    s.appendLeft(insertionPoint, `\nvi.hoisted(() => { 
         if(!globalThis.${HELPER_MOCK_HOIST}){
           vi.stubGlobal(${JSON.stringify(HELPER_MOCK_HOIST)}, {})
         }
@@ -236,7 +236,7 @@ export const createMockPlugin = (ctx: MockPluginContext) => createUnplugin(() =>
 
     if (!hasViImport) s.prepend(`import {vi} from "vitest";\n`)
 
-    s.appendLeft(insertionPoint, mockLines.join('\n') + '\n')
+    s.appendLeft(insertionPoint, '\n' + mockLines.join('\n') + '\n')
 
     // do an import to trick vite to keep it
     // if not, the module won't be mocked


Test patch:
diff --git a/examples/app-vitest-full/components/WrapperTests.vue b/examples/app-vitest-full/components/WrapperTests.vue
index d648481e..c06f5c16 100644
--- a/examples/app-vitest-full/components/WrapperTests.vue
+++ b/examples/app-vitest-full/components/WrapperTests.vue
@@ -10,7 +10,7 @@ function testExpose() {
 
 const someRef = ref('thing')
 
-const modelValue = defineModel({ default: false })
+const modelValue = defineModel({ type: Boolean, default: false })
 
 defineExpose({
   testExpose,
diff --git a/test/unit/mock-transform.spec.ts b/test/unit/mock-transform.spec.ts
index 2439ca4a..e18ad11d 100644
--- a/test/unit/mock-transform.spec.ts
+++ b/test/unit/mock-transform.spec.ts
@@ -49,11 +49,13 @@ describe('mocking', () => {
         })
       `)).toMatchInlineSnapshot(`
         "import {vi} from "vitest";
+
         vi.hoisted(() => { 
                 if(!globalThis.__NUXT_VITEST_MOCKS){
                   vi.stubGlobal("__NUXT_VITEST_MOCKS", {})
                 }
               });
+
         vi.mock("bob", async (importOriginal) => {
           const mocks = globalThis.__NUXT_VITEST_MOCKS
           if (!mocks["bob"]) {
@@ -77,8 +79,38 @@ describe('mocking', () => {
         from: 'bob',
       }]
       const code = await getResult(`
-        import { expect, vi } from 'vitest'
+        import { expect, vi, it } from 'vitest'
         mockNuxtImport('useSomeExport', () => 'bob')
+        
+        it('test', () => {
+          const a = vi.fn()
+        })
+      `)
+      expect(code).toMatchInlineSnapshot(`
+        "
+                import { expect, vi, it } from 'vitest'
+        vi.hoisted(() => { 
+                if(!globalThis.__NUXT_VITEST_MOCKS){
+                  vi.stubGlobal("__NUXT_VITEST_MOCKS", {})
+                }
+              });
+
+        vi.mock("bob", async (importOriginal) => {
+          const mocks = globalThis.__NUXT_VITEST_MOCKS
+          if (!mocks["bob"]) {
+            mocks["bob"] = { ...await importOriginal("bob") }
+          }
+          mocks["bob"]["useSomeExport"] = await (() => 'bob')();
+          return mocks["bob"] 
+        });
+
+                
+                
+                it('test', () => {
+                  const a = vi.fn()
+                })
+              
+         import "bob";"
       `)
       expect(code).not.toContain('import {vi} from "vitest";')
     })
@@ -101,11 +133,13 @@ describe('mocking', () => {
         mockComponent('MyComponent', () => import('./MockComponent.vue'))
       `)).toMatchInlineSnapshot(`
         "import {vi} from "vitest";
+
         vi.hoisted(() => { 
                 if(!globalThis.__NUXT_VITEST_MOCKS){
                   vi.stubGlobal("__NUXT_VITEST_MOCKS", {})
                 }
               });
+
         vi.mock("MyComponent", async () => {
           const factory = (() => import('./MockComponent.vue'));
           const result = typeof factory === 'function' ? await factory() : await factory