1.0.0-beta.12
https://gitlab.com/bugreports/vue-test-utils-beta.12-problems
Run the tests as detailed in the README.
No errors or warnings when running unit tests.
Getting errros like:
console.error node_modules/vue/dist/vue.common.js:580
[Vue warn]: Unknown custom element: <v-btn> - did you register the component correctly? For recursive components, make sure to provide the "name" option.
(found in <Root>)
I had no troubles with older versions of vue-test-utils. These warnings and errors started when I upgraded to vue-test-utils.1.0.0-beta.12. No code changed anywhere. Just upgraded vue-test-utils and ran the tests again.
It may be related to this change: https://github.com/vuejs/vue-test-utils/commit/9381736
I also have this in my repository and finally tracked it down to it being caused in version -beta.12. I learned a lot about npm's version ranges along the way...
If in my package.json I change
"@vue/test-utils": "^1.0.0-beta.11", // still matches 1.0.0-beta.12
to
"@vue/test-utils": "<=1.0.0-beta.11 || >1.0.0-beta.12",
then the warnings disappear. That is the only change I made and it reliably made the warnings appear/disappear.
@FernandoBasso pointed to a change that says it enforces the use of a local Vue instance. That is consistent with my perception of the problem. The Vuetify components and custom filters that the warnings are about are registered on the global Vue instance using Vue.use(). If a local Vue instance is passed to the tests, it will lack those additions.
vue-test-utils supports injecting a localVue instance; so create localVue, called localVue.use(Vuetify) and then pass in that localVue instance. Might be sensible to do this as part of beforeEach block or something, just to ensure no pollution of namespaces between tests.
@robcresswell That would be quite some overhead, since I think I would have to do that for each test file. I expected the tests to run with the same Vue instance that I use normally, unless explicitly overwritten.
So while this would theoretically work, I find it quite impractical generally. Is there a way to use the regular Vue instance?
You could change the isUnknownElement test function before you run your tests*:
import Vue from 'vue'
Vue.config.isUnknownElement = () => {}
* You can run a file before tests with --require in mocha: mocha --require some-file.js, and setupTestFrameworkScriptFile in Jest.
@Y0hy0h It's not quite that much, only on the tests where you call mount I think, which shouldn't be that many; at least in experience so far, the vast majority of my tests are shallow with the occasional stubs.
This is also a bit of a niche case because you're using a framework globally, rather than importing just the elements you're using.
The reason for using localvue I believe is to stop polluting the global namespace or causing issues between tests, like for example if you have multiple components that affect navigation through vue-router, the order of the tests could affect the state of the Vue instance.
@eddyerburgh Thanks for pointing me to the setup hooks! I might look into whether I can setup all needed dependencies there, otherwhise I'll try your suggestion.
@robcresswell I've come to the conclusion that mocks should be only used when necessary. Therefore I always test using mount, unless I run into issues.
Your saying that it'd be better to import the components rather than registering them globally is interesting. I will look into that.
I understand the need for a local Vue instance. And I have to admit that I don't fully understand how Vue/vue-test-utils is using the global namespace. I would just like to argue in favor of the old behavior, where it would 'just work', but still be overwritable by a local Vue instance.
@Y0hy0h The problem with using mount rather than shallow and mocks is that you're moving from the realms of a unit test to an integration test. If you're relying on a 3rd party library and rendering that component as part of your unit tests, then you are unit testing your own library, and then also testing the third party library at the same time. Similarly, a change in the 3rd party lib could break your unit tests, which should never happen.
Obviously, this is an "ideal" scenario and in the real world we do not always have time to mock everything; however, for common components like buttons, you should consider maintaining a series of mock objects with simple click handlers or similar. In the long term, this should also save your CI time on test runs too, as you need only stub and render one or two components, rather than the entire tree.
@robcresswell This is something that is not directly related to the issue, so I'll keep it short. ;)
I have now adopted the view that you should test what you actually have. You actually have a component that depends on third parties. So if something from that third party breaks, so does your component, and you want to know. Therefore no need to mock for me here.
That being said, if third party changes frequently break tests, I would worry that the broken test are too implementation-specific. I really try to prioritize blackbox testing.
I understand your point of view. I just adopted a different one which now makes more sense to me.
I had problems when using custom directive and filter
console.error node_modules/vue/dist/vue.runtime.common.js:589
[Vue warn]: Failed to resolve filter: markdown
(found in <FileUpload>)
console.error node_modules/vue/dist/vue.runtime.common.js:589
[Vue warn]: Failed to resolve directive: md
Neither registering using localVue and plugin work
localVue.directive('md', directives.md)
localVue.filter('markdown', filters.markdown)
// or
localVue.use(MarkdownPlugin)
I think something weird happened because #450 was resolved
@Y0hy0h Yeah I understand that, I'm just saying that isn't a unit test any more if you're chaining together multiple libraries like that; I don't know if vue-test-utils is supposed to go beyond the scope of unit testing. That's why I was mentioning it in the first place; I don't know whether that support is in scope of the library basically. That said, this is all my opinion, so please continue to test as you see fit 馃槃
@DrSensor It may be easier to open a separate issue to track this, it sounds different to the current discussed issue.
@robcresswell That's an interesting point. I still think that a default global Vue (or equivalent) with the option for a local override is a good compromise, but I now understand what you were getting at. ;) I definitely do not seem to be registering the components in a clean way, which I will have a look at.
However, I still believe that using the same Vue instance as the app is a good way to go by default, if you have the option of overriding it with a local instance when you need to. This would make it easy to test initially, and once you need to get your hands dirty because of some implementation details, you can.
I don't see the harm, but I would like to hear where I might be wrong and learn. :)
I just upgraded to beta.13 and it breaks
console.error node_modules/vue/dist/vue.runtime.common.js:1739
TypeError: Cannot read property '$options' of undefined
also can any core contributor on this project take a peek at vue discord channel
vue-testing?
@drsensor See my previous comment :smile:
@DrSensor please open a new issue with a minimal reproduction so we can take a look
I don't think we should hide warnings about unregistered components. I understand it adds a lot of noise, but it could also be a source of bugs in tests. It would be more annoying to spends time debugging a test, only to realize the warning about an unregistered component was being swallowed by vue test utils.
@eddyerburgh Does that mean that in the previous version, the components were actually not there, but I only didn't know they were missing? I definitely agree that this has to be signified.
If this was the behaviour all along, then the warnings are a great addition. I would just like to have a mechanism to automatically use the "original" Vue instance that my real app runs with.
For now, @eddyerburgh's test framework setup suggestion is the best option I've learned of.
@Y0hy0h I don't really know how vue-test-utils would know what your default view instance is, since you're setting that up in your App.vue (or equivalent). I think Jest has functionality for doing global test setup, so you define your localVue there perhaps.
Ah wait, this is what edd mentioned already :)
@robcresswell But you're right, unless the "real" Vue instance is always in the main.js, vue-test-utils can't know easily.
Thanks a lot for your patience with me. ;) I sure learned a few key things and I now know how to tackle the issue using your suggestions.
@Y0hy0h Yes, I believe so.
I can't pinpoint the change that started logging warnings (or was suppressing them), but they are valid warnings caused by unregistered components.
I'm going to close this as the desired behavior. If people have issues with the localVue, you can create a new issue with a minimal reproduction. Thanks.
Most helpful comment
I just upgraded to beta.13 and it breaks