-
Notifications
You must be signed in to change notification settings - Fork 668
Component stubs should render default slots #658
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
Can you add a reproduction on CodeSandBox—https://codesandbox.io/s/m4qk02vjoy? |
Yes : https://codesandbox.io/s/vvk1pw1w3l But I am not using Vuex inside this component |
I don't think this is a bug, @trollepierre . I was able to get your test passing using this code: import { createLocalVue, mount } from '@vue/test-utils'
import TestComponent from "./TestComponent";
import Vuetify from 'vuetify'
describe('components | Component', () => {
// let localVue
beforeEach(() => {
localVue = createLocalVue()
localVue.use(Vuetify)
//localVue.use(Vuex)
})
describe('template', () => {
it('should match snapshot', () => {
// When
const wrapper = mount(TestComponent)
// Then
expect(wrapper.vm.$el).toMatchSnapshot()
})
})
}) What I did
Vuex does not appear to have any relationship to this test and doing |
Actually wrapper.element should be the same as vm. $el. If it's not then
that's a bug
…On Mon, 4 Jun 2018, 14:16 Lachlan, ***@***.***> wrote:
I don't think this is a bug, @trollepierre
<https://github.com/trollepierre> . I was able to get your test passing
using this code:
import { createLocalVue, mount } from ***@***.***/test-utils'import TestComponent from "./TestComponent";import Vuetify from 'vuetify'
describe('components | Component', () => {
// let localVue
beforeEach(() => {
localVue = createLocalVue()
localVue.use(Vuetify)
//localVue.use(Vuex)
})
describe('template', () => {
it('should match snapshot', () => {
// When
const wrapper = mount(TestComponent)
// Then
expect(wrapper.vm.$el).toMatchSnapshot()
})
})
})
What I did
1.
wrapper.element is not valid. For snapshot, you should can use
wrapper.vm.$el or wrapper.htmI()). I recommend wrapper.html(), it
gives a nicer output. In your case, I had to write wrapper.vm.$el to
match the snapshot.
2.
Use mount instead of shallowMount. I think you should almost always
use mount for snapshots, otherwise you end up stubbing everything out.
Since you were using shallowMount, the <v-layout> component was
stubbed out, so vm.$el was empty.
Vuex does not appear to have any relationship to this test and doing
localVue.use(Vuex) should not have any impact on the test. You can
include it or not, and the test still passes if you make the above changes.
—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
<#658 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AMlbWwcs1_kHq7MTDZj33qnDbKWFBlUGks5t5TMxgaJpZM4UOYwV>
.
|
I checked. wrapper.element is the same as vm.$el. => I don't want to @lmiller1990 : it looks like Vuex makes a change in the test. I don't know why. That is why I opened this bug. I supposed this bug depends on Vuetify and VueTestUtils, but I don't see how. |
If you use Re @eddyerburgh , @trollepierre Vuex does not make a change in the test from what I can see - how did you come to this conclusion? Using I forked your repo and commented out all the Vuex related stuff, and it seems to be passing: https://codesandbox.io/s/m7xw536p9j Something odd is going on, having a closer look. Edit, this seems okay too: Edit, this appears to be fine, too: import { shallowMount } from '@vue/test-utils'
import TestComponent from "./TestComponent";
import Vuetify from 'vuetify'
//import Vuex from 'vuex'
describe('components | Component', () => {
describe('template', () => {
it('should match snapshot', () => {
// When
const wrapper = shallowMount(TestComponent)
// Then
expect(wrapper.element).toMatchSnapshot()
})
})
}) Edit again: this passes:
and this seems to fail for me:
Replacing |
Hey so the problem is that shallow stubs components and doesn't render slots by default. Thinking about it, I think we should add this. There have been a few other people who have been stung by this, and the slot content really is part of the component you're testing.
For now, you can fix it by using a custom stub: const VLayoutStub = {
render: function(h) {
return h("div", { class: "layout" }, this.$slots.default);
}
};
const wrapper = shallowMount(TestComponent, {
localVue,
stubs: {
"v-layout": VCardStub
}
}); Or by using |
Your suggested workaround (passing
This could be then used by users, and/or internally as well to handle this case. Any idea why adding |
Yes, please 👍 Using |
#658 (comment) shows // XXX: Create a general stub with its default slot
// https://github.com/vuejs/vue-test-utils/issues/658
const createSlotStub = (name) => {
// Prevent 'Unknown custom element: ...'
const config = require('vue').config;
if (!config.ignoredElements) {
config.ignoredElements = [];
}
config.ignoredElements.push(name);
// Return functional component
return {
render: function(h) {
return h(name, {}, this.$slots.default);
},
};
}; Then const wrapper = shallowMount(TestComponent, {
localVue,
stubs: {
"v-layout": createSlotStub('layout-stub'),
}
}); |
beta.21 will render default slots 👍 |
@eddyerburgh I know that this was closed quite a while ago, but we're still wondering about
vs.
We run exactly the same test case (besides changing the order of the use commands) shallowMounting a simple Vue component looking like this:
This is what
This is what
Shouldn't this be the same? And will the changes solve this problem? |
That's odd. It looks like the first output is rendered with createLocalVue seems to be doing something strange, maybe. createLocalVue or createInstance could be suspect. |
@lmiller1990 Yes! I thought you found out the same as you stated this in one of your posts above? That's why I added it here and didn't create a new bug report. I can upload the minimal example to my GitHub account and link it here if that would help. |
Hm. Eddy mentioned this above:
It looks like when you call Do you have an actual example of what you are testing? Sometimes lots of dependencies can make unit tests tricky. What is your actual goal of the test you are writing? PS: this is still a bug, I think, and needs to be addressed. I think |
@lmiller1990 Here is a repo for you to play around: https://github.com/miriamgreis/vue-test-utils-vuetify-and-vuex We use Vuetify for our layout and Vuex to store our data. So why shouldn't we use both of them in our tests? We need to mock the store in order to test our components. |
Thanks for the repo. Sure, you can use both if you need it for your unit test. The test you posted above doesn't have |
I really just created a quick and easy example because the real code is from a customer project with quite complex data stored with Vuex. We do use it in these tests, but the problem happens anyway, so it's not really relevant here, I guess. |
Since you are just testing the component, the complexity of the store shouldn't be too much trouble. I used to have trouble writing tests for the same reason. I learned this from my experience and wrote about it here.
const wrapper = shallowMount(Foo, {
computed: {
myGetter() => 'whatever value you want'
}
}) This gives you control over the state. You can easily test edges cases. The component is simply a function of the current state of the app, regardless of whether it is local state, Vuex, or from props. Use the
The other thing you often do with Vuex is commit or dispatch something. In this case, what you are really testing is:
In that case, you can use mock functions and a mock store (or a real store, with mock mutations and action). The man himself, Edd, wrote about it in the documentation's guides section here. Since I learned to use mocks and stubs and minimize dependencies, my unit tests became more simple and easier to write. Hopefully that can help you. PS, I still think that this is a problem and am investigating. People should be able to write more end to end like unit tests if they want, and in some cases those tests are more useful. I am trying to collect my experience in a series of articles here to help others learn more about testing Vue (I am still learning myself). It's a WIP but maybe that can help you as well. I'll post if I make some progress on this. I would like to be able to use any Vue plugin without problems in tests. |
@lmiller1990 Thanks for providing all the help and the links, but what you describe in your article is exactly what we already do in our tests. ;-) We use mocks and stubs for almost everything. Nevertheless, it requires us to have: Vue.use(Vuex). |
@miriamgreis sure, no problem. If possible it would be great to get a full reproduction of your problem, after all. After trying some stuff out now, I am not having the same problem you appear to be.
One problem I encountered on the way, and I suspect a lot of people encounter is Vuetify appears to require a import { createLocalVue, mount, shallowMount } from '@vue/test-utils'
import HelloWorld from '@/components/HelloWorld.vue'
import Vuex from "vuex"
import Vuetify from "vuetify"
import RootApp from "@/components/RootApp.vue"
const VAppRoot = (Child) => ({
components: { Child, RootApp },
template: "<root-app><child /></root-app>"
})
describe('HelloWorld.vue', () => {
const localVue = createLocalVue()
localVue.use(Vuetify)
localVue.use(Vuex)
it('shallowMounts', () => {
const comp = VAppRoot(HelloWorld)
const wrapper = shallowMount(comp, {
localVue
})
console.log(wrapper.html())
})
it('mounts', () => {
const comp = VAppRoot(HelloWorld)
const wrapper = mount(comp, {
localVue
})
console.log(wrapper.html())
})
}) Here is <template>
<v-app class="outer">
<slot />
</v-app>
</template>
<script>
export default {
}
</script> HelloWorld.vue: <template>
<div class="hello--world">
<v-container>
<v-layout
<v-flex>
<h1>hello</h1>
<v-btn color="success">Success</v-btn>
</v-flex>
</v-layout>
</v-container>
</div>
</template>
<script>
export default {
name: 'HelloWorld',
props: {
msg: String
}
}
</script>
Makes sense, it just stubbed out the
<div data-app="true" class="application outer theme--light" id="app">
<div class="application--wrap">
<div class="hello--world">
<div class="container">
<div class="flex"><h1>hello</h1>
<button type="button" class="v-btn success">
<div class="v-btn__content">Success</div>
</button>
</div>
</div>
</div>
</div>
</div> Looks good, I think. Maybe that can help. Did you have a |
Thanks for taking so much time to try to solve the problem. Your example obviously works because you put your own component around the Vuetify components. Our example has a Vuetify component as a root component as you can see in the provided example. You find the reproduction code in the repository I linked above: https://github.com/miriamgreis/vue-test-utils-vuetify-and-vuex There is also another solution to the v-app problem which doesn't blow up the test code as it doesn't require extra components in your test: vuetifyjs/vuetify#1210 |
Hm, did you link the right repro? It doesn't have Vue or Vuetify (or maybe I misunderstood something). Thanks for the link to the Vuetify issue, I can use it to repro the issue more accurately. Not sure if I can help more, I still want to look more into the potential |
@lmiller1990 Sorry, it's my fault that I didn't doublecheck the repository. Looks like I pushed to the wrong one yesterday. :-( You will find the right code in there now. Maybe it's a language issue, but just to state this more clear: I don't need any of your explanation. I really appreciate that you provided these explanations on how to use Vuex and Vuetify in test, but I already now all of this. We already use Vuex and Vuetify successfully in our unit tests. So you don't need to explain anything else, just look into the potential Vue.use issue, because this is what we are interested in. ;-) |
Ok, thanks for the repo. I tried it and can repro the problem locally. I'll use this to find the problem. Thanks for clarifying. |
Okay, I isolated the problem. The problem is any plugin that calls Basically const myPlugin = {
install: function (Vue, opts) {
Vue.mixin({
// doing Vue.mixin breaks it
})
}
} I think this causes the problem in this issue, too: #819 . I'll keep working on it this week, and let you know if/when I solve it 👍 |
Thanks very much. :-) |
@lmiller1990 I have a test case that requires me to make full mount and it crashed without encasing it in v-app, so I used method you shown here and got test to run with full mount. How can I access child component's instance tho? |
@Mourdraug I am not sure if I understood correctly or not but can you do something like:
|
I was sure I tried |
Version
1.0.0-beta.16
Reproduction link
http://google.com
Steps to reproduce
When I comment
localVue.use(Vuex)
, it shouldn't affect my snapshot, because I am not using any store in my componentWhat is expected?
Green test
What is actually happening?
Jest Snapshot result:
could you provide a template of CodePen, CodeSandbox if you want a link, please?
The text was updated successfully, but these errors were encountered: