Testing a Nuxt application with different profiles

Hello community! I’m new to Nuxt, and I’m currently trying to create a good testing approach for a project I’m working on. I’m using Nuxt (currently 3.11.2), Vitest (3.0.2), @vue/test-utils (2.4.6) and @nuxt/test-utils (3.15.4). To manage roles and permissions, I’m also using a smaller library: nuxt-permissions (0.2.4), which is to add as a module to the nuxt.config.ts like so:
export default defineNuxtConfig({
modules: [
'nuxt-permissions'
// ...
]
})
export default defineNuxtConfig({
modules: [
'nuxt-permissions'
// ...
]
})
https://github.com/dystcz/nuxt-permissions I want to run tests with different user profiles. I’m not currently doing true E2E tests, as I am: * mocking my auth middleware to do… nothing * mocking my endpoint response to get a User Then, when a test is running, it goes through all my plugins, and I extended nuxt-permissions with a plugin. I want to test my pages through visiting routes like so:
import { mountSuspended, registerEndpoint } from '@nuxt/test-utils/runtime'
import { flushPromises } from '@vue/test-utils'
import { describe, expect, it } from 'vitest'
import App from '~/app.vue'
import mockedCustomerEndpoints from '../mocks/endpoints/customer'

registerEndpoint('customers', () => (
   mockedCustomerEndpoints.customers()
))

describe('customers page', async () => {
   it('returns a table with values', async () => {
       const wrapper = await mountSuspended(App, { route: '/customers' })

       await flushPromises()

       expect(wrapper.find('table').exists()).toBe(true)
       expect(wrapper.text()).toContain('John')
[…]
   })
})
import { mountSuspended, registerEndpoint } from '@nuxt/test-utils/runtime'
import { flushPromises } from '@vue/test-utils'
import { describe, expect, it } from 'vitest'
import App from '~/app.vue'
import mockedCustomerEndpoints from '../mocks/endpoints/customer'

registerEndpoint('customers', () => (
   mockedCustomerEndpoints.customers()
))

describe('customers page', async () => {
   it('returns a table with values', async () => {
       const wrapper = await mountSuspended(App, { route: '/customers' })

       await flushPromises()

       expect(wrapper.find('table').exists()).toBe(true)
       expect(wrapper.text()).toContain('John')
[…]
   })
})
This is working. But what I want to achieve now, is to be able to change my User profile inside my test file, like so:
const nuxtApp = useNuxtApp()
nuxtApp.provide('authUser', { name: 'user2', role: 'admin' })
const nuxtApp = useNuxtApp()
nuxtApp.provide('authUser', { name: 'user2', role: 'admin' })
I can achieve that, but the bad thing is that the code always go through plugins during initialization phase, so when I provide another authUser, it is too late. Am I in the good direction?
GitHub
GitHub - dystcz/nuxt-permissions: Nuxt module for permission manage...
Nuxt module for permission management. Contribute to dystcz/nuxt-permissions development by creating an account on GitHub.
3 Replies
kapa.ai
kapa.ai3w ago
Hi @Guillaume – (p)repair. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave: ---------------------- Based on the knowledge sources provided and your question, I can offer some insights and suggestions for testing a Nuxt application with different user profiles. However, it's important to note that the knowledge sources don't contain specific information about the nuxt-permissions module or changing user profiles during tests. Nevertheless, I can provide some general guidance based on Nuxt testing practices. You're on the right track with your approach to testing, using @nuxt/test-utils and @vue/test-utils. Here are some suggestions and considerations: 1. Mocking Auth and Endpoints: Your approach of mocking the auth middleware and endpoint responses is a good practice for unit and integration testing. This allows you to control the test environment and focus on specific components or pages. 2. Using mountSuspended: Your use of mountSuspended from @nuxt/test-utils/runtime is correct. This method allows you to mount components within the Nuxt environment, including async setup and access to Nuxt plugins Docs > Getting-started > Testing > Unit Testing > 🛠️ Helpers. 3. Changing User Profiles: The challenge you're facing with changing user profiles after the initialization phase is a common one. Nuxt plugins run during the app initialization, which happens before your tests. To address this, you might consider the following approaches: a. Mock the nuxt-permissions module: Instead of using the actual module, you could create a mock version that allows you to change the user profile dynamically. You can use mockNuxtImport to achieve this:
import { mockNuxtImport } from '@nuxt/test-utils/runtime'
mockNuxtImport('nuxt-permissions', () => {
return {
// Implement a mock version of the module that allows changing user profiles
}
})

import { mockNuxtImport } from '@nuxt/test-utils/runtime'
mockNuxtImport('nuxt-permissions', () => {
return {
// Implement a mock version of the module that allows changing user profiles
}
})

b. Use Vitest's beforeEach hook: You could set up the desired user profile in a beforeEach hook, which runs before each test:
import { beforeEach } from 'vitest'

beforeEach(() => {
// Set up the desired user profile here
})

import { beforeEach } from 'vitest'

beforeEach(() => {
// Set up the desired user profile here
})

4. Consider End-to-End Testing: While your current approach is good for unit and integration testing, for testing different user profiles and permissions, end-to-end (E2E) testing might be more suitable. Nuxt provides support for E2E testing using Playwright Docs > Getting-started > Testing > End-To-End Testing > Testing in a Browser. 5. Use setup for E2E Tests: If you decide to move towards E2E testing, you can use the setup function from @nuxt/test-utils/e2e to configure your test environment, including setting up different user profiles Docs > Getting-started > Testing > End-To-End Testing > Setup. In conclusion, while your current approach is a good start, you might need to explore mocking the nuxt-permissions module or consider moving towards E2E testing for more comprehensive testing of different user profiles and permissions. The exact implementation will depend on the specifics of your application and the nuxt-permissions module. Remember that testing in Nuxt is an evolving field, and the best practices may change with new versions. Always refer to the latest Nuxt documentation for the most up-to-date information on testing strategies. ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai3w ago
<@949039984852222002> Kapa.ai is still learning and improving, please let me know how I did by reacting below.
Guillaume – (p)repair
Thank you for you answers. I would like to design my test suite like so:
Project
|—— test
| |—— unit
| | |—— setup.ts
| | |—— role-admin.ts
| | |—— role-user.ts
| | |—— pages
| | | |—— customers.admin.test.ts
| | | |—— customers.user.test.ts
| | | | ...
| |—— e2e
| | |—— setup.ts
| | |—— pages
| | | |—— customers.test.ts
| | | | ...
|—— vitest.config.ts
Project
|—— test
| |—— unit
| | |—— setup.ts
| | |—— role-admin.ts
| | |—— role-user.ts
| | |—— pages
| | | |—— customers.admin.test.ts
| | | |—— customers.user.test.ts
| | | | ...
| |—— e2e
| | |—— setup.ts
| | |—— pages
| | | |—— customers.test.ts
| | | | ...
|—— vitest.config.ts
I tried to achieve it with Vitest worskpace feature, like so:
import { defineVitestConfig } from '@nuxt/test-utils/config'

export default defineVitestConfig({
test: {
globals: true,
environment: 'nuxt',
setupFiles: ['test/unit/setup.ts'],
environmentOptions: {
nuxt: {
overrides: {
plugins: ['~/test/unit/mocks/plugins/01.mockedAuth'],
},
},
},
workspace: [
{
extends: true, // Inherits from global config
test: {
name: 'Admin Tests',
include: ['test/unit/**/*.admin.test.{ts,js}'],
setupFiles: ['test/unit/role-admin.ts'],
},
},
{
extends: true, // Inherits from global config
test: {
name: 'User Tests',
include: ['test/unit/**/*.user.test.{ts,js}'],
setupFiles: ['test/unit/role-user.ts'],
},
},
],
},
})
import { defineVitestConfig } from '@nuxt/test-utils/config'

export default defineVitestConfig({
test: {
globals: true,
environment: 'nuxt',
setupFiles: ['test/unit/setup.ts'],
environmentOptions: {
nuxt: {
overrides: {
plugins: ['~/test/unit/mocks/plugins/01.mockedAuth'],
},
},
},
workspace: [
{
extends: true, // Inherits from global config
test: {
name: 'Admin Tests',
include: ['test/unit/**/*.admin.test.{ts,js}'],
setupFiles: ['test/unit/role-admin.ts'],
},
},
{
extends: true, // Inherits from global config
test: {
name: 'User Tests',
include: ['test/unit/**/*.user.test.{ts,js}'],
setupFiles: ['test/unit/role-user.ts'],
},
},
],
},
})
But with this configuration, I get a conflict error:
failed to load config from …/vitest.config.ts

⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Startup Error ⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯
Error: Context conflict
failed to load config from …/vitest.config.ts

⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Startup Error ⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯
Error: Context conflict
Here is the full error message:
failed to load config from …/vitest.config.ts

⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Startup Error ⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯
Error: Context conflict
at checkConflict (file:///…/node_modules/@nuxt/test-utils/node_modules/unctx/dist/index.mjs:6:13)
at Object.set (file:///…/node_modules/@nuxt/test-utils/node_modules/unctx/dist/index.mjs:40:9)
at initNuxt (file:///…/node_modules/nuxt/dist/index.mjs:4202:11)
at Object.ready (file:///…/node_modules/nuxt/dist/index.mjs:4104:18)
at loadNuxt (file:///…/node_modules/nuxt/dist/index.mjs:4660:16)
at async loadNuxt (file:///…/node_modules/@nuxt/test-utils/node_modules/@nuxt/kit/dist/index.mjs:2642:19)
at async startNuxtAndGetViteConfig (file:///…/node_modules/@nuxt/test-utils/dist/config.mjs:40:16)
at async getVitestConfigFromNuxt (file:///…/node_modules/@nuxt/test-utils/dist/config.mjs:90:15)
at async file:///…/node_modules/@nuxt/test-utils/dist/config.mjs:204:7
at async loadConfigFromFile (file:///…/node_modules/vitest/node_modules/vite/dist/node/chunks/dep-Beq30MX9.js:53810:20)
failed to load config from …/vitest.config.ts

⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Startup Error ⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯
Error: Context conflict
at checkConflict (file:///…/node_modules/@nuxt/test-utils/node_modules/unctx/dist/index.mjs:6:13)
at Object.set (file:///…/node_modules/@nuxt/test-utils/node_modules/unctx/dist/index.mjs:40:9)
at initNuxt (file:///…/node_modules/nuxt/dist/index.mjs:4202:11)
at Object.ready (file:///…/node_modules/nuxt/dist/index.mjs:4104:18)
at loadNuxt (file:///…/node_modules/nuxt/dist/index.mjs:4660:16)
at async loadNuxt (file:///…/node_modules/@nuxt/test-utils/node_modules/@nuxt/kit/dist/index.mjs:2642:19)
at async startNuxtAndGetViteConfig (file:///…/node_modules/@nuxt/test-utils/dist/config.mjs:40:16)
at async getVitestConfigFromNuxt (file:///…/node_modules/@nuxt/test-utils/dist/config.mjs:90:15)
at async file:///…/node_modules/@nuxt/test-utils/dist/config.mjs:204:7
at async loadConfigFromFile (file:///…/node_modules/vitest/node_modules/vite/dist/node/chunks/dep-Beq30MX9.js:53810:20)
And if I comment the // extends: true, // Inherits from global config of my second workspace ('User Tests), it works. Well, it my tests for that workspace will not work because the environment is not setup to 'nuxt' etc… Is there a way within defineVitestConfig from @nuxt/test-utils/config to ensure 2 workspace will run in the same nuxt environment (not trying to create another which conflics), while keeping a custom setupFile for specific needs on certain tests?

Did you find this page helpful?