Skip to content

new slot syntax template can't be accessed in shallowMount #1261

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

Closed
manonrichou opened this issue Jun 19, 2019 · 21 comments
Closed

new slot syntax template can't be accessed in shallowMount #1261

manonrichou opened this issue Jun 19, 2019 · 21 comments
Assignees
Labels

Comments

@manonrichou
Copy link

Version

1.0.0-beta.29

Reproduction link

https://codesandbox.io/embed/vue-template-dr6i7?fontsize=14&previewwindow=tests

Steps to reproduce

Run the two tests in the link. The one pointing to the old syntax's slot will pass, the one pointing to the new slot's syntax won't.

What is expected?

Template with v-slot syntax can be accessed in the test when using shallow mount.

What is actually happening?

The test pointing to the template using the new slot syntax fails, whereas the one with the soon-to-be deprecated syntax passes.

@runarberg
Copy link

Are there any workarounds (other then using the deprecated syntax)?

@kspackman
Copy link

Very interested in this issue, so that we can upgrade our syntax and still be able to test our components.

@Stoom
Copy link
Contributor

Stoom commented Nov 11, 2019

Are there any workarounds (other then using the deprecated syntax)?

What I've found is you need to provide your own stub for the component with slots. If you do that and add the named slots you care about then they will render in the shallowMount.

wrapper = shallowMount(Appbar, {
    store, router, localVue, vuetify, stubs: {
        VTooltip: '<v-tooltip-stub><slot></slot><slot name="activator"></slot></v-tooltip-stub>',
    },
});

@runarberg
Copy link

@Stoom That does not help if you need to test something that is inside a higher order component that uses scoped slots. E.g. in the following example, anything inside <SomeHigherOrderComponent> will be stubbed out:

<SomeHigherOrderComponent v-slot="scope">
  <p>
    We can use <code>scope</code> here,
    but <code>shallowMount</code> will stub this out.
    So we have to use <code>mount</code> to test it.
  </p>
</SomeHigherOrderComponent>

@runarberg
Copy link

Perhaps this is relevant, but vuese is experiencing a similar issue of not being able to access content inside slots that use the new v-slot syntax.

vuese/vuese#119

@Stoom
Copy link
Contributor

Stoom commented Dec 1, 2019

@runarberg When I was testing VHover from vuetify I just did the following and it worked enough for me....

        wrapper = shallowMount(Settings, {
            propsData, localVue, vuetify, store, stubs: {
                VHover: `<slot></slot>`,
            },
        });

@runarberg
Copy link

runarberg commented Dec 10, 2019

@Stoom That doesn’t work for me. What I need to test is a child of the component using the v-slot:

<MyParent>
  <p>This is OK</p>

  <template v-slot="scope">
    <p>
      <strong>I need to test this.</strong>
      And I don’t know how to use <var>shallowMount</var>
      without it stubbing this out.
    </p>
  </template>
</MyParent>

Here <MyParent> has a slot scope on the default slot. I would need to stub the entire component to get it render, and then I might as well not write the unit test.

@lmiller1990 lmiller1990 self-assigned this Dec 20, 2019
@lmiller1990
Copy link
Member

Good slot support is something we will address before moving from beta to 1.0 - I'll try my best to fix this in the near future.

@lmiller1990
Copy link
Member

lmiller1990 commented Dec 22, 2019

Tried reproducing but failed to do so here: https://github.com/vuejs/vue-test-utils/pull/1383/files

I'll try pulling the reproduction repo.

@lmiller1990
Copy link
Member

Progress! I got it working in #1383

Need to clean the code up and cover some edge cases (and support dynamic slots). Hopefully get this merged in soon!

@lmiller1990
Copy link
Member

Merged in... this will go out in beta-31.

@mtwolak
Copy link

mtwolak commented Feb 11, 2020

Why this issue has been closed? It seems issue has not been fixed, it still fails with provided link on version beta-31. Tests with new slot syntax in our production code also fails when updated to beta-31.

@lmiller1990
Copy link
Member

I thought this had been fixed - at least, we have unit tests merged in using the new v-slot syntax, here.

You are right - the provided repo fails. This is the source component:

<template>
  <Foo>
    <template v-slot:newSyntax>
      <p class="new-example">text not rendered</p>
    </template>
    <template slot="oldSyntax">
      <p class="old-example">text rendered</p>
    </template>
  </Foo>
</template>

This is the source test

test("render old syntax slot", () => {
  const wrapper = shallowMount(App);
  expect(wrapper.find(Foo).exists()).toBe(true);
  expect(wrapper.find(".old-example").exists()).toBe(true);
});

test("render new syntax slot", () => {
  const wrapper = shallowMount(App);
  expect(wrapper.find(Foo).exists()).toBe(true);
  console.log(wrapper.html())
  expect(wrapper.find(".new-example").exists()).toBe(true);
});

Removing the template with v-slot:newSyntax lets the first test pass:

<template>
  <Foo>
    <template slot="oldSyntax">
      <p class="old-example">text rendered</p>
    </template>
  </Foo>
</template>

// test
test("render old syntax slot", () => {
  const wrapper = shallowMount(App);
  expect(wrapper.find(Foo).exists()).toBe(true);
  expect(wrapper.find(".old-example").exists()).toBe(true);
});

And the same applies for the new syntax and new syntax test. I wonder if mixing the syntaxes is messing things up?

After thinking about this a bit more, does this even make sense? If we are using shallowMount...

<template>
  <Foo>
    <template slot="oldSyntax">
      <p class="old-example">text rendered</p>
    </template>
  </Foo>
</template>

We are stubbing out Foo entirely - so shouldn't none on the content be rendered at all? Eg, should be:

<foo-stub></foo-stub

no?

@mtwolak can you provide a simple version of your failing production test? I am assuming you do not combine the new and old syntax.

@lmiller1990 lmiller1990 reopened this Feb 11, 2020
@mtwolak
Copy link

mtwolak commented Feb 11, 2020

We're using vuetify v-tooltip: https://codesandbox.io/s/stoic-cookies-ovlv0. I didn't include vuetify library in codesand because of readability.
ShallowMount does not render component's child. I don't understand, why with text is not rendered since it's not separate component.

@lmiller1990
Copy link
Member

lmiller1990 commented Feb 11, 2020

I played with this and no luck. It could be related to Vuetify; it looks like it uses requestAnimationFrame and transitions to handle the tooltip, which are both things we have struggled with in the jsdom environment.

I'm surprised the first case with the old slot syntax works at all; that seems like a bug to me, in shallowMount. What do you think? Here's why I think it is a bug in shallowMount

shallowMount is supposed to stub out all child components. In your example:

<template>
  <v-tooltip bottom>
    <template v-slot:activator="{ on }">
      <div v-on="on">
        <span class="grey--text">Text to be checked</span>
      </div>Some text for tooltip
    </template>
  </v-tooltip>
</template>

In this component (you called in NewTooltip.vue in your demo), child components in this markup are v-tooltip, so it should be stubbed to v-tooltip-stub. All the inner markup and lifecycle hooks are also stubbed. Why should the content of a stubbed child component render in shallowMount at all? This seems like the wrong behavior to me, from the start.

If you were mounting a VTooltip, then I would expect the inner markup to render. But you are mounting a NewTooltip.vue, so all components (including VTooltip) getting stubbed seems correct.

I am trying to figure out exactly what shallowMount should and should not do; everyone seems to have different expectations. Should it render the children here? Why? I'm guessing mount is not an option in your case.

@mtwolak
Copy link

mtwolak commented Feb 12, 2020

I thought only things from components will be stubbed in case of shallowMount. It's little suprising to me, because right now I will have to use mount on tooltip component, even if it's not using other components. But from the other hand, maybe it's expected (I don't know, I have small experience with Vue). Anyway, could you tell me, why mount is not an option in my case? I thought mount should render whole content (including template's content) but it seems it generated the same content as shallowMount did.

@lmiller1990
Copy link
Member

lmiller1990 commented Feb 12, 2020

mount is an option - mount is always and option (and likely should be your go-to method).

The idea of shallowMount is to stub out all other components (not render their HTML, or run any of their JS code) to test your current one "in isolation". Turns out this probably wasn't a great design decision, it's confusing to a lot of users, so we are thinking of a better alternative(s) for v1 (and Vue 3 compat).

You should be able to use mount find, I believe. Can you try that and let me know how it goes? Vuetify still has a lot of edge cases, relating to requestAnimationFrame, so if you get some weird output post back here and I can help.

@mtwolak
Copy link

mtwolak commented Feb 13, 2020

It works with mount: https://codesandbox.io/s/gracious-satoshi-1zh8m.
Thank you very much for your support. Since shallowMount correctly stubs all its children this issue can be closed.

@mtwolak
Copy link

mtwolak commented Feb 13, 2020

However it seems it's strictly related to Vuetify, some of its components does not generate inner content anyway, for instance: https://codesandbox.io/s/gracious-satoshi-1zh8m

@lmiller1990
Copy link
Member

@mtwolak no bug, just looked it up - Vuetify's menu is closed by default. The test passes if you add a :value="true" prop:

 <v-menu offset-y :value="true">
    <v-list>
      <v-list-item key="ab">
        <v-list-item-title>
          <span>This text should be displayed</span>
        </v-list-item-title>
      </v-list-item>
    </v-list>
  </v-menu>

Everything should work correctly using mount, since it just renders all the elements like a regular browser.

Did you find any other problems with Vuetify and mount?

@mtwolak
Copy link

mtwolak commented Feb 17, 2020

@lmiller1990 everything works as expected. I tried with more complex templates and adding value set to true resolves all problems. Thanks for help, completely missed out property "value" - I was searching for property called "visible" or "expand" or sth like that and it turned out value was exactly what I was searching for.

This issue should be closed, everything is correctly rendered.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

6 participants