components
components copied to clipboard
use components discovery with tests
Describe the bug
Tried this library first time, dynamic imports
are working great!
About auto scan
feature, I found it saves many lines of codes but some tests are getting error:
[Vue warn]: Unknown custom element: <MyComponentB> - did you register the component correctly? ...
this is the case where I have MyComponentA
and MyComponentB
defined under /components
folder and MyComponentA
is using MyComponentB
.
If I resurrect lines of codes that imports MyComponentB
in MyComponentA
, the test are working back ok but I wonder if I am missing something?
Additional context [email protected] @nuxt/[email protected] @vue/[email protected]
I think it would be possible to create something that auto imports components at test level. Otherwise @nuxt/components
only is usable at pages/layouts level (typically tested via e2e rather than unit) rather than within components.
Yes, please implement auto imports at test level.
As a workaround, I'm registering all components as global Vue components in my jest setup file:
[
'app/components/MyComponentA.vue',
'app/components/MyComponentB.vue',
'ui-kit/components/ComponentA.vue',
'ui-kit/components/ComponentB.vue',
'ui-kit/components/ComponentC.vue',
].forEach((path) => {
const name = path.match(/(\w*)\.vue$/)[1];
const prefix = path.startsWith('ui-kit/') ? 'Ui' : '';
Vue.component(`${prefix}${name}`, require(path).default);
});
I could automate this by pulling in the configuration/using globs, but I don't feel the need to make it more complicated than this, especially that I'm working on the project alone.
I've spent the past couple of days messing with my project configuration. Not sure if it's been worth all the trouble, but I hope this helps somebody!
As a workaround, I'm registering all components as global Vue components in my jest setup file:
[ 'app/components/MyComponentA.vue', 'app/components/MyComponentB.vue', 'ui-kit/components/ComponentA.vue', 'ui-kit/components/ComponentB.vue', 'ui-kit/components/ComponentC.vue', ].forEach((path) => { const name = path.match(/(\w*)\.vue$/)[1]; const prefix = path.startsWith('ui-kit/') ? 'Ui' : ''; Vue.component(`${prefix}${name}`, require(path).default); });
I could automate this by pulling in the configuration/using globs, but I don't feel the need to make it more complicated than this, especially that I'm working on the project alone.
I've spent the past couple of days messing with my project configuration. Not sure if it's been worth all the trouble, but I hope this helps somebody!
@Merott Can you show your jest config file, please?
@harrytran998 are you running into a particular issue? I don't have anything special for auto-scanning components in my jest config file:
// jest.config.js
const path = require('path');
module.exports = {
moduleNameMapper: {
'^@@?/(.*)$': '<rootDir>/$1',
'^~~?/(.*)$': '<rootDir>/$1',
'^vue$': 'vue/dist/vue.common.js',
},
moduleFileExtensions: ['ts', 'js', 'vue', 'json'],
transform: {
'^.+\\.ts$': 'ts-jest',
'^.+\\.js$': 'babel-jest',
'.*\\.(vue)$': 'vue-jest',
},
testPathIgnorePatterns: ['<rootDir>/(.vscode|node_modules|cypress)/'],
setupFilesAfterEnv: [path.resolve(__dirname, 'jest.setup.ts')],
snapshotSerializers: ['jest-serializer-vue'],
};
Thanks @Merott, I ended up doing:
// test/setupTest.js (jest setup)
const components = [
'../components/MyComponentA.vue',
'../components/MyComponentB.vue',
]
components.forEach((path) => {
const name = path.match(/(\w*)\.vue$/)[1];
Vue.component(`${name}`, require(path).default);
});
then could use auto scan
feature freely. Happy for now.
Thanks, I have tried this solution which works. But the duration of my tests went from 20ms to 40ms. Normal, because we load all components before each test suites. I have failed to improve it. Code lines VS unit tests duration, I vote to keep unit test duration low. I hope for a good solution at the end.
This solution is great, but it fails when some component is contained within auto-scanning components.
The following code can automatically register components.
// jest.setup.js
import path from 'path'
import glob from 'glob'
import Vue from 'vue'
glob.sync(path.join(__dirname, './src/components/**/*.vue')).forEach(file => {
const name = file.match(/(\w*)\.vue$/)[1]
Vue.component(name, require(file).default)
})
global.Vue = Vue
I hope someone will give it a clean solution. Just register all the components in the folder is not enough because I use font-awasom-icon component inside the tested component, and I get error:
[Vue warn]: Unknown custom element: <font-awesome-icon>
I can use stubs:
const wrapper = mount(MyComponent, { stubs: ['font-awesome-icon'] })
But it's not clean.
I don't know if it's truly not affecting to any configuration that running on test system..
But i found this configuration working to me, and these setting helps me prevents warning @bob-lee mentions. https://dev.to/bawa_geek/how-to-setup-jest-testing-in-nuxt-js-project-5c84
By adding code in ./test/jest.setup.js
import Vue from 'vue'
import { config } from '@vue/test-utils'
Vue.config.silent = true
// Vue.config.ignoredElements = ['nuxt-link']
// Mock Nuxt components
config.stubs.nuxt = { template: '<div />' }
config.stubs['nuxt-link'] = { template: '<a><slot /></a>' }
config.stubs['no-ssr'] = { template: '<span><slot /></span>' }
and add these lines in config file ./jest.config.js
setupFilesAfterEnv: ['./test/jest.setup.js']
// test/setupTest.js (jest setup) const components = [ '../components/MyComponentA.vue', '../components/MyComponentB.vue', ] components.forEach((path) => { const name = path.match(/(\w*)\.vue$/)[1]; Vue.component(`${name}`, require(path).default); });
@danielroe Is there something that could be implemented to include auto-scanning? This solution here works, but I can't get @ryoju-ohata 's solution working.
There are actually two solutions to polyfill components in test environment:
- Importing
.nuxt/components/plugin.js
(auto registers to globalVue
) - Importing
.nuxt/components/index.js
and register manually
For both, we need a nuxt build
step. (an upcoming nuxt dryrun
would make it faster to only generate templates)
@pi0 So what is the official way to setup our tests to take advantage of auto import feature? Could there be some documentation added to Nuxt to demonstrate this?
Very difficult to take advantage of the auto import feature with our code if our tests don't work.
That's a nice idea @nmackey. I'm currently a little bit overwhelmed by tasks but PR definitely welcome for adding examples or docs. /cc @danielroe @ricardogobbosouza if you are interested to help on this.
Hello, I wouldn't mind writing the documentation, but I'm unsure what are the steps to actually make it work. :thinking:
I got one definitely working solution, based on this comment:
There are actually two solutions to polyfill components in test environment:
Importing .nuxt/components/plugin.js (auto registers to global Vue) Importing .nuxt/components/index.js and register manually For both, we need a nuxt build step. (an upcoming nuxt dryrun would make it faster to only generate templates)
The steps I actually took:
- I added
setupFiles: ["./.nuxt/components/plugin.js"],
to myjest.config.js
- I changed my
package.json["scripts"]["test"]
from justjest
tonuxt build && jest
This worked, but it's a significant slowdown for running tests. If I know I have an up-to-date-build, I can delete the nuxt build &&
(or create a new script without it, e.g. retest
, in package.json
), but I'm not aware of any automated solution to that.
This specific implementation is to my mind too slow and hacky to enshrine in the official documentation, honestly, even though the programatically-generated .nuxt/components/plugin.js
is exactly what the test env needs 😞. I'd love any suggestions on how to improve it.
Hi! So what would be the official way to solve this issue?
BTW, the setup I'm using right now that's completely automated (but not efficient) is to have this in my jest.config.js
module.exports = {
preset: '@nuxt/test-utils',
moduleFileExtensions: [
'js',
'json',
'vue'
],
transform: {
'.*\\.(vue)$': '@vue/vue2-jest',
'.*\\.(js)$': 'babel-jest'
},
moduleNameMapper: {
'^@/(.*)$': '<rootDir>/$1',
'^~/(.*)$': '<rootDir>/$1',
'^vue$': 'vue/dist/vue.common.js',
'~/([a-zA-Z0-9/.\\-_]*)': '<rootDir>/$1',
'/^~/(.*)$/': './$1',
'^.+\\.(css)$': '<rootDir>/test/__mocks__/css.js'
},
testEnvironment: 'jsdom',
setupFilesAfterEnv: ['./jest.setup.js']
}
And in jest.setup.js
const path = require('path')
const glob = require('glob')
const Vue = require('vue')
glob.sync(path.join(__dirname, './components/**/*.vue')).forEach((file) => {
const name = file.match(/(\w*)\.vue$/)[1]
Vue.component(name, require(file).default)
})
global.Vue = Vue
PS: And do you know if this will still be an issue with Nuxt 3 and Vitest?
I got one definitely working solution, based on this comment:
There are actually two solutions to polyfill components in test environment: Importing .nuxt/components/plugin.js (auto registers to global Vue) Importing .nuxt/components/index.js and register manually For both, we need a nuxt build step. (an upcoming nuxt dryrun would make it faster to only generate templates)
The steps I actually took:
- I added
setupFiles: ["./.nuxt/components/plugin.js"],
to myjest.config.js
- I changed my
package.json["scripts"]["test"]
from justjest
tonuxt build && jest
This worked, but it's a significant slowdown for running tests. If I know I have an up-to-date-build, I can delete the
nuxt build &&
(or create a new script without it, e.g.retest
, inpackage.json
), but I'm not aware of any automated solution to that.This specific implementation is to my mind too slow and hacky to enshrine in the official documentation, honestly, even though the programatically-generated
.nuxt/components/plugin.js
is exactly what the test env needs 😞. I'd love any suggestions on how to improve it.
@ambirdsall-gogo Just having setupFiles: ["./.nuxt/components/plugin.js"]
in jest.config.js
and run npm run jest
is working. Is there any possible issue that I don't see?