Open Nojusle opened 3 months ago
Hey @Nojusle! I'm a bot that can help you solve bugs, answer questions, and become a contributor. I'm here to help you while waiting for a human maintainer.
To resolve the issue of the $style
attribute being undefined
when testing components that use CSS Modules in your Nuxt 3 project, you need to ensure that the @nuxt/test-utils/module
is properly loaded and configured in your nuxt.config
file.
Here are the key steps:
@nuxt/test-utils/module
is added to the modules
array in your nuxt.config
file:// nuxt.config.js
export default {
modules: [
'@nuxt/test-utils/module',
// other modules
],
// other configurations
}
startNuxtAndGetViteConfig
function to start Nuxt and get the Vite configuration, which includes the necessary setup for handling CSS Modules:import { startNuxtAndGetViteConfig } from './path/to/config';
async function setup() {
const { nuxt, viteConfig } = await startNuxtAndGetViteConfig();
// additional setup if needed
}
setup();
By ensuring that the @nuxt/test-utils/module
is properly loaded and configured, the $style
attribute should be correctly defined when testing components that use CSS Modules [1].
Additionally, you can mock the $style
attribute in your tests to avoid it being undefined
. Here is an example of how to mock a component with CSS Modules:
import { mockComponent } from '@nuxt/test-utils/runtime'
// Mock the component and its styles
mockComponent('MyComponent', {
props: {
value: String
},
setup(props) {
return {
$style: {
myClass: 'mocked-class'
}
}
}
})
// Now you can write your tests
import { mountSuspended } from '@nuxt/test-utils/runtime'
import { it, expect } from 'vitest'
import MyComponent from '~/components/MyComponent.vue'
it('renders with mocked styles', async () => {
const component = await mountSuspended(MyComponent)
expect(component.vm.$style.myClass).toBe('mocked-class')
})
In this example, the $style
attribute is mocked to return a predefined class name, ensuring that it is not undefined
during the tests [2].
To continue talking to Dosu, mention @dosu.
Well, I'm not convinced it's the proper fix solution, but you can get the correct values passed through by modifying this line from...
setup: setup ? (props: Record<string, unknown>) => wrappedSetup(props, setupContext) : undefined,
....to...
setup: setup ? (props: Record<string, unknown>) => wrappedSetup({ ...props, ...component.__cssModules }, setupContext) : undefined,
I say that I don't think its the correct fix, as this then only solve the issue for components with a setup script, but I couldn't expose this via the render context.
OK, so not a fix, but a temporary workaround for anyone else stumbling on this, a small function which wraps mountSuspended
and should work as a drop-in replacement to make for easy removal if/when the core bug is fixed.
import { mountSuspended } from '@nuxt/test-utils/runtime'
export const mountWithNuxt: typeof mountSuspended = async (component, options) => {
return mountSuspended(component, {
...options,
// @ts-expect-error Vue's TS doesn't like us specifying $style as an external prop
props: {
...options?.props,
$style: {},
},
attrs: {
...options?.attrs,
$style: undefined,
},
})
}
Great, the workaround works for me. That's all I needed, thank you!
Thanks @robm-masabi for the workaround.
I've been playing around with this locally for the last hour or so and I've noticed that this only seems to occur if you use $style
to pass the module class in the template. If you declare or pass the style via <script setup>
in the component being tested, the tests should run as expected:
<script setup lang="ts">
// works with no changes in the template
const $style = useCssModules();
// ...or use :class="elementStyle" in the template
const styles = useCssModules();
const elementStyle = styles.elementClass;
</script>
Environment
Reproduction
https://codesandbox.io/p/devbox/nuxt-test-with-css-modules-sz2wlg?file=%2Fsandbox.config.json%3A4%2C25-4%2C37
Describe the bug
When running tests on components that uses CSS Modules, the $style attribute is consistently set to undefined, causing the tests to fail.
Additional context
There are no examples in the Nuxt test examples folder that include CSS modules. I've read the documentation for @nuxt/test-utils, and it doesn't mention how to use it with CSS modules. I tried googling it, but I couldn't find any information on how to test Vue components with CSS modules. I only found an unanswered question regarding the same issue, e.g., https://github.com/nuxt/test-utils/discussions/804. Since CSS modules work with Nuxt 'out of the box,' I believe testing components that use CSS modules should also work seamlessly.
Logs