-
Notifications
You must be signed in to change notification settings - Fork 244
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
Helpers: Suspense (and others?) #108
Comments
I was thinking about such helpers too. It is super convenient to have them at your disposal, officially. I also made a similar one for testing stub scoped and named slots. Maybe we can add all of these to the |
We could just include them in core. If people will basically install the package every time, why not? Kind of like Can you share your helpers here? |
Should work for named slots too, right? Would this help with #2 I am starting to link the idea of including helpers - if we are going to mention them in the guide, we may as well.
|
This works for any type of slot, but its only to generate a minimal stub, that renders and provides just enough for you to test your slot content. It will not help with testing slots properly on the mounted component. That is what I will be doing next day or so. I have started a branch locally with cases :) I agree, we will have some edge cases that may need some some helpers :) |
Great, sounds good. I will work on my suspense helper a bit too. |
I wonder, how are we going to test suspense content? Finding things inside Suspense, while its loading/errored? I could not make |
Seems to work with find. No reason why it wouldn't - you just need That's what I am using the |
So while writing the ScopesSlots PR I realized this is a pretty nifty way of testing scoped slot params. Deff one I would have loved to have available, a while back. I think its a great addition to the utilities. const assertScopedSlotData = () => {
let assertion = ref(null)
const slot = (params) => {
assertion.value = params
return ''
}
return [assertion, slot]
}
const [params, slot] = assertScopedSlotData()
const wrapper = mount(ComponentWithSlots, {
slots: {
scoped: slot,
}
})
expect(params.value).toEqual({
boolean: true,
string: 'string',
object: { foo: 'foo' }
}) |
Interesting! The more I think about it, the more I like the idea of including these utilities. Let's do it. |
Should Also, how does |
So how I invisioned using it was as just an external function, that you use as I have shown in the example: const [namedParams, named] = assertScopedSlotData()
const [defaultParams, default] = assertScopedSlotData()
const wrapper = mount(Comp, { slots: { named, default } })
expect(namedParams).toEqual({})
expect(defaultParams).toEqual({}) This way I think its much easier to name the exported objects, then to destructure and object and re-assign names. But then again, in most cases you test only one slot at a time.... But overall I did not intend this to be in the |
Oh, I see. I was confused by returning This is very cool - what an interesting way to use Vue's reactivity. I am starting to see this decoupled reactivity is actually a huge improvement to Vue overall. Don't have a strong opinion for/against including this. I personally would still make my assertions against the DOM as opposed the the props the slot receives... this still seems like a fancy way to test an implementation detail (what props are passed) instead of a behavior (what the component actually does with the props). That said, I think you encounter much more complex uses of slots in your day to day usage - would this make an improvement to the code-bases you work on? Do you think other people would also find this useful? If you think so, I don't have a strong opinion against including this - people who want to use it can, people who don't need not. |
Lets decide where/how do we add these extra bits? Do we make a |
I think anything that can be done via a plugin is fine to leave out. These helpers (slots, suspense) can be in core, imo - doesn't hurt. Did you want to make a branch with your slot helpers? Happy to review and push my suspense helper (can't find it, might just remake it it :) ) |
Could they be implemented as plugins? If so, we could have some "official" plugins, meaning plugins that we've developed or that we consider valuable, so they earn the "official" umbrella.
These are important questions – I'd stick to testing against the DOM so I can't really say anything meaningful here. Maybe we could check against other people that manage tests on large codebases?
Agree. Yet we need to be careful – we know people might not need this, but newcomers always have a hard time trying to grasp what they need and what they can ignore for a while. I think I'm just saying that we need to be extra careful when adding new stuff to the API, and make sure docs are in sync 👍 |
The main one I'm thinking about is a Suspense helper. Happy to let this sit and add things as people ask for them. |
Can we get an official helper function to stub out a component, while still showing its slot content. For example, I have a component like this: <div class="parent-component">
<BaseTable :data="data">
<template v-if="thing">
<label for="thing">Thing</label>
<input type="checkbox" id="thing">
</template>
</BaseTable>
</div> All I care about is testing the logic being passed into the slot. Currently if I did a snapshot of the component 99% of it would be cruft that I don't care about: <div class="parent-component">
<div class="base-table-wrapper">
<!-- ...80 lines of code... -->
<div class="custom-table-filters-slot">
<label for="thing">Thing</label>
<input type="checkbox" id="thing">
</div>
<!-- ...3000 lines of code, mostly from a 3rd party table component displaying data... -->
</div>
</div> But if we stubbed out the child component, while still rendering its slots, we'd get a much better snapshot. Something closer to this: <div class="parent-component">
<div stub="base-table">
<div class="custom-table-filters-slot">
<label for="thing">Thing</label>
<input type="checkbox" id="thing">
</div>
</div>
</div> This is a huge improvement, I shouldn't have to load 3000 lines of code in a giant DOM tree just to test a checkbox. See: #69 for how this is done in VTU 1 + Vue 2. |
I think we have have something like this @TheJaredWilcurt (docs for VTU Next are still a WIP...) but as a (global) config, we could reuse that logic. If this was a mounting option, would that solve your problem? This feels like something you would want on a global config, not test by test (correct me if I am wrong, I don't use shallow or snapshots often). For example: shallowMount(Foo, {
renderDefaultSlot: true
}) |
Having both would be good (a global defaulting to true that can be overridden on a per-test basis). But if I could only choose one I'd want the per-test control. |
Yes, I agree, we should add this as a global config too. |
This (renderStubDefaultSlot mounting option) will go out with #212. As for helpers, I think we can revisit them when/if there is more demand. So far no-one issues really - we will document how to test things like |
Hey @lmiller1990 the |
it's already there :) #102 |
@afontcu Brilliant, thanks! |
Is there a plan to extend the render to named slots rather than just default? I have a similarly scenario to @TheJaredWilcurt were I use named slots and the default slot to compose a component together. Whilst doing a full render would solve this I really only want to focus on the component functionality at this level. Assuming other unit tests cover other components. |
What about checking if the setup function is async like (not sure if there is a better way without calling the function first): And then return something like the It seems to me that a lot of people will run into this. As far as i know there is no off-the-shelf way to test this right now while this a common task. |
@rikbrowning Might be worth making a new issue if you have a feature proposal. Not 100% clear on what you want, but I think I understand and I think the reason we don't have that is a technical blocker (could be wrong, would need to see a more fleshed out example of your proposal). @sand4rt I think including some helpers is a good idea, if you want to make an issue with a proposal we could go over it. If there's no technical blocker/edge cases, we could add it. What I've generally been doing is just something like this which seems okay. What do you think? |
@lmiller1990 I put together the feature I am talking about in this commit rikbrowning@d9309d4 |
My two cents goes towards including a helper function in this library. I've been struggling to get this to work with components that need props and react to changes to those props. I think I finally have a solution, but I'm still not sure if it's the right way. You probably know better. This is my current solution in case it could help someone: /**
* Creates a Wrapper that contains the mounted and rendered Vue component.
*
* @param component The asynchronous component to mount using suspense.
* @param options The mount options.
*
* @returns The mounted component wrapper.
*/
async function mountWithSuspense<Component extends ComponentPublicInstance, Props>(
component: new () => Component,
options: MountingOptions<Props>
): Promise<VueWrapper<ComponentPublicInstance>> {
const wrapper = defineComponent({
'components': { [component.name]: component },
'props': Object.keys(options.props ?? {}),
'template': `<suspense><${component.name} v-bind="$props" /></suspense>`
});
const result = mount(wrapper, options);
await flushPromises();
return result;
} |
Neat helper. Personally I like to keep the scope of this library small, and encourage building helpers/integrations, mainly to keep maintenance easy. No doubt this helper is great for you, but someone else might need to tweak it - then we end up with a helper with many different options. We could have. a page in the docs with some snippets/helpers - kind of like recipes - what do you think? Alternatively, if you have a blog, you could write about how it works and we could backlink to you from the docs - good traffic/publicity for your content. |
I think it's worth considering.
We have a lot of packages that depend on each other, and trying to encapsulate this in some sort of package hasn't been easy. For example, recently, it had a problem with the This makes me think that it's actually a variation of It would be even better if this could be autodetected by |
@alejandroclaro first things first, thank you for your contribution here; it's been extraordinarily helpful. That said, I'm running into a problem trying to access elements of the component itself after it has mounted. With a synchronous component I can simply call I've provided a minimal example here: https://stackblitz.com/~/github.com/jeffpohlmeyer/vue-testing-async where I try to call the |
Can this issue be reopened? I tried to find a solution for testing a simple Component with async setup code and was unable to find a solution. In my opinion async/await should be easy to use. |
I have found a workaround to access
|
@Bo-Yang-PDL try to do it like this:
|
#105 had some great discussion around helpers - the example raised there was for components with
async setup
functions (used in<Suspense>
). Testing those alone won't work, since if you have aasync setup
, Vue expected a<Suspense>
wrapper.We could provide a helper (this works)
Some thoughts:
flushPromises
for the user. Any possible side-effects/unexpected behavior?shallowMountSuspense
? Someone will almost certainly ask for this.shallowMount
as a stand-alone function (which I think we should) and instead have ashallow: true
mounting option, this would not be a problem.The text was updated successfully, but these errors were encountered: