Open rikbrowning opened 3 years ago
It's little hard to understand. I really couldn't see <slot name="test" />
. Please reproduce all the used components: HelloWorld, FakeComponent, TestComponent or it would be better to create a repository
https://github.com/rikbrowning/test-utils-slot-bug
In this repository both snapshots should be the same. The only thing that is different is the slot syntax which is causing a break in snapshots.
@rikbrowning,
Check out my PR
What actually happened?
<FakeComponent />
has a default slot and in the <Working />
are passed this content into the slot:
<TestComponent :msg="msg" slot="test">
<div>
default slot of test component
</div>
</TestComponent>
<div>
default slot of fake component
</div>
In the <Broken />
you are close tag too early:
<template v-slot:test>
<TestComponent :msg="msg">
<div>
default slot of test component
</div>
</TestComponent>
</template>
<div>
default slot of fake component
</div>
Move it under the last <div>
tag and snapshots will match
Also I'll recommend you to read the docs about slots again because the default content of the slot sets up directly inside the slot.
Hey I read the docs and found this example (taken from https://vuejs.org/v2/guide/components-slots.html)
<base-layout>
<template v-slot:header>
<h1>Here might be a page title</h1>
</template>
<p>A paragraph for the main content.</p>
<p>And another one.</p>
<template v-slot:footer>
<p>Here's some contact info</p>
</template>
</base-layout>
The code changes you have made would put my default content inside the test slot, which is not what I want. The issue being that semantically both Working and Broken are the same but yet result in different snapshots.
Broken.vue
<template>
<FakeComponent>
<template v-slot:test>
<TestComponent :msg="msg">
<div>
default slot of test component
</div>
</TestComponent>
</template>
<template v-slot:default>
<div>
default slot of fake component
</div>
</template>
</FakeComponent>
</template>
What about to manually set the template that falls down into the default slot of the <FakeComponent>
?
I did some more investigating. The change you suggested did work for Broken.vue. However when I add a root level div the slots stop rendering again. I have updated the repo with the new Broken.vue, if you run the unit test you will see that the snapshot no longer renders out the slots.
I read through this and have some questions. Is this bug only snapshots? I'd say a shallow mount + snapshot bug is not that big a deal - realistically, these tests are very brittle and fairly useless when it comes to actually verifying your product is working correctly.
If there's a bug relating to actual slots and the v-slot
syntax, we should fix it. Is this the case?
I am also not able to find
any of the elements in the slots either so it is not simply snapshot related.
Did some further digging.
Issue seems to be in createStubFromComponent
. When we add in the div.test-wrapper
around the FakeComponent, the check for slots (ctx.$options.parent._vnode.data.scopedSlots
) when rendering FakeComponent is actually checking the div.test-wrapper
for scopedSlots. That means no slots are getting rendered.
Without the div.test-wrapper
the check ctx.$options.parent._vnode.data.scopedSlots
returns the correct data.
I noticed the following comment:
// In Vue 2.6+ a new v-slot syntax was introduced
// scopedSlots are now saved in parent._vnode.data.scopedSlots
I presume there is good reason for this change but I found that using ctx.$vnode.data.scopedSlots
worked for both cases.
Stubs are super messy - if you found a fix, make it and create a PR and see if CI fails :) I can't really remember what each and every line does there, but there should be tests around it all.
@lmiller1990 hey I have submitted a PR but seems to be failing on the CI even though the only thing added was tests. Any idea how to fix that?
Just took a look: https://app.circleci.com/pipelines/github/vuejs/vue-test-utils/570/workflows/29f090d2-6a16-4bcc-993d-63e09c4559d2/jobs/16342
Can you try running yarn format:check
and fixing any problems? I think yarn format
should auto fix most of the linting problems.
I am surprised your fix doesn't break things. Anyway, try fixing the linting and pushing again, see what happens. Thanks!
Hey was able to get the formatting sorted but can't seem to get flow check to pass: Not quite sure what I need to do to get the flow to work. Able to get test:unit to pass no issue, just failing on test.
Can you push what you have? I can't see that error in CI. I can take a look, need more context to provide guidance. Where are you doing that import? It should work like that - we have that same line in many places. π€
Hey, pushed my latest changes to https://github.com/rikbrowning/vue-test-utils
Any news on this issue?
I've started removing all the old deprecated slot syntax from our app & a bunch of tests are failing.
Some tests kind of work, if you explicitly set a default
slot. But this doesn't solve every case & in reality, I'd like to keep all our tests as they are.
The most simple example I have is:
<my-button>
<template v-slot="prepend">
<span>Hello</span>
</template>
<div>World!</div>
</my-button>
What I receive:
<my-button-stub>
<div>World!</div>
</my-button-stub>
What I expect:
<my-button-stub>
<span>Hello</span>
<div>World!</div>
</my-button-stub>
Could you try building https://github.com/vuejs/vue-test-utils/pull/1877/files locally and see if it solves your problem?
Sorry for the lack of activity here ... I have mostly been focused on VTU next, for Vue 3. I am also really hesitant to make major changes to the slots part of the code base, although we have decent test coverage, every time we change that part of the code base, it breaks a bunch of people's test suites.
If you can confirm this works, we could probably run the branch against some large OSS code bases and see if it breaks anything (namely GitLab, they have a huge suite using VTU).
@lmiller1990
So I tried to quick route & just added the changes in the PR to our project's node_modules
directly. π
It doesn't however solve my problem. π
The first issue is this.$options._renderChildren
is populated here so I never even get inside getScopedSlotRenderFunctions
.
And then secondly, even when removing this condition for testing, the proposed change doesn't work.
I checked out the proposed PR to see if I could make the tests fail & I can! π
By adding a default slot & some content, the named slot no longer renders.
So the test for .new-example
existing in the DOM fails.
However, explicitly setting a default slot by name, correctly passes all slots (which is what I had seen above βοΈ ). So the tests do fail, but they fail for the reason I'd expect.
You can see my fork here with the failing test when passing a default slot: https://github.com/andrewbrennanfr/vue-test-utils/commit/3c30a68e587a1abd0a101b77248917014fc0036b
And also with the default slot being explicitly named, the test above βοΈ no longer fails: https://github.com/andrewbrennanfr/vue-test-utils/commit/f07f218c4ffe2defe07800e985fa6e09bcc7b5bb
Edit:
I've played around with the tests & it looks like we aren't well handling the default slot case when not explicitly named as #default
. And for me it's the this.$options._renderChildren ||
.
I think the proposed fix works to make named slots render correctly. But when paired with default slots, they are still omitted.
Something like this: https://github.com/andrewbrennanfr/vue-test-utils/commit/e03cb4c4786f73583609f6a87b126553fa53824f fixes the issue for me (also including the proposed changes from @rikbrowning )
Although I'm completely unsure of the impact of this change. π
But all tests are green, and the two broken use cases for me look to be fixed too.
Apparently this is the intended behavior in vue though π€·ββοΈ
https://vuejs.org/v2/guide/components-slots.html#Abbreviated-Syntax-for-Lone-Default-Slots
Note that the abbreviated syntax for default slot cannot be mixed with named slots, as it would lead to scope ambiguity
@andrewbrennanfr those repo links you posted 404 for me now. I'm hitting this same issue and I'd love to see how you fixed it!
I think this falls into https://github.com/vuejs/vue-test-utils/issues/1564#issuecomment-1424857260 @lmiller1990 , right?
Yeah, I'd say so - anything around shallowMount and stubs is pretty risky/messy to change at this point. If there's a quick/easy fix, that'd be fine. I won't be able to work on this right now, though.
I'm new on vue
but I think I found a temporary solution that can help someone struggling with this issue. Its based on this reference:
wrapper = mount(TestedComponent, {
attachToDocument: true,
stubs: {
InnerComponent: mockSlots([['slotName', '']]),
},
});
And this the mockSlots
function:
function mockSlots(scopedSlots) {
return {
render(h) {
return h(
'div',
scopedSlots.map(([name, slotProps]) => this.$scopedSlots[name](slotProps))
);
},
};
}
If someone could validate it or even improve that would be great :)
Subject of the issue
I recently switched a project from the old slot syntax to the new v-slot syntax and my snapshot started failing. Some of the slots are not getting rendered at all.
Steps to reproduce
I have a simplified example that showcases the issue.
My component is as follows:
It is populating the test and default slot FakeComponent. According to the vue2 docs you can but do not have to specify the default slot in a template. My test is as follows:
Expected behaviour
I would expect the test slot to be rendered in the snap shot as it is with the old syntax.
NOTE: to get the result above I simply changed the component to this:
Actual behaviour