The Wayback Machine - https://web.archive.org/web/20201212162932/https://github.com/vuejs/vue-test-utils/issues/1579
Skip to content
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

Using 'Mount', Class and Style properties are inconsistent in this.$attrs #1579

Open
patrick-tolosa opened this issue Jun 14, 2020 · 10 comments
Open

Comments

@patrick-tolosa
Copy link

@patrick-tolosa patrick-tolosa commented Jun 14, 2020

Using mount(), 'class' is treated differently depending on context

When rendering a component in a test using 'mount()', you have two ways to do so.

  1. mount the component itself
  2. mount the component using a template that renders the component

the prop 'class' is treated differently in the two ways mentioned above.

    const wrap = mount(MyComp, {
      propsData: {
         class='abc'
      },
    });

vs.

    const wrapper = mount(
      {
        template: `
          <my-comp
            class='abc'
          />
        `
      },
      {
        components: { MyComp }
      }
    );

in the first example this.$attrs is populated with 'class', while in the second example this.$attrs is empty.

Expected behavior

I'd expected both forms of rendering to behave the same way(either way is good, just be consistent)

Actual behavior

In the first example this.$attrs is populated with 'class' and 'style',
while in the second example this.$attrs is empty.

Possible Solution

I'm guessing that the root cause is how Vue is handling the prop 'class' in the context of a template vs directly pushing the prop in an object.
The 'mount' implementation doesn't deal with the special merging Vue does for style and class
(while writing the above line I realized this probably happens with style as well, and after testing it, it indeed behaves like class)

@lmiller1990
Copy link
Member

@lmiller1990 lmiller1990 commented Jun 15, 2020

You are right, this is related to Vue's implementation details. I am a little confused about "both forms of rendering to behave the same way" - is wrapper.html() different?

I am not sure if there is a problem or bug here.

@patrick-tolosa
Copy link
Author

@patrick-tolosa patrick-tolosa commented Jun 15, 2020

@lmiller1990 - Thanks for at least confirming I'm not crazy.

Regarding your comment on my remark:

You can image that my component has some logic that does things on the $attrs object, the content of $attrs is different depending on how I render the component.

In one instance my component has access to $attrs.class, and on the other it does not.

I'm fine with one of the two being right, but it's a bit confusing when they behave differently.

@lmiller1990
Copy link
Member

@lmiller1990 lmiller1990 commented Jun 16, 2020

This won't just be a problem in VTU though right - this is coming from Vue core.

Do you have an example test where this is a problem?

@patrick-tolosa
Copy link
Author

@patrick-tolosa patrick-tolosa commented Jun 16, 2020

I think this is problem unique to VTU and unrelated to Vue(kind of)

Vue treats class and style as a special case, but VTU does not.
I think this inconsistency is a problem, as at the very least it's unexpected.

In our test case, we have a component that passes down all the $attrs it receives to a child component.

On top of all other $attrs we expected, both style and class were also cascaded down to the inner html, but this did not happen when we rendered with Vue.

It took some fiddling to find out that it's the way we write our tests that creates this effect.
If we run our tests in a template, everything works as expected.

rendering the component

   mount(MyComp, {
      propsData: {
         class='abc'
      },
    });

would result in this:

    <span class="abc"><span>
</div>

however this form:

mount(
      {
        template: `
          <my-comp
            class='abc'
          />
        \`
      },
      {
        components: { MyComp }
      }
    );

would result in this output

<div class="abc">
    <span><span>
</div>
@dobromir-hristov
Copy link
Collaborator

@dobromir-hristov dobromir-hristov commented Jun 16, 2020

Create a minimal repro, where we can assert what exactly you are doing. I think it may be a mix of vtu and user error

@patrick-tolosa
Copy link
Author

@patrick-tolosa patrick-tolosa commented Jun 29, 2020

@dobromir-hristov Is there any chance to confirm whether it's a user error or a VTU issue?

@lmiller1990
Copy link
Member

@lmiller1990 lmiller1990 commented Jul 13, 2020

Had a think about this. I think the current behavior is correct. According to the Vue docs, $attrs does not include class and style, so that is why it is not appearing in the wrapperOfTemplateComponent example.

Let me know if I am missing something and we can reopen this.

@patrick-tolosa
Copy link
Author

@patrick-tolosa patrick-tolosa commented Jul 13, 2020

@lmiller1990 my only concern, as a developer and tester, is that the two cases are not identical.

Now that I know that there's some difference between the two, I will always use the option closest to Vue.

Our test was working perfectly using mount(MyComp) but failing in production, as a person who loves automation and trusts it, this made me feel extremely uneasy. (If we can't trust our tests, what can we trust?)

this error was spotted by chance, and we could've missed it.

@lmiller1990
Copy link
Member

@lmiller1990 lmiller1990 commented Jul 13, 2020

I didn’t realise this was working differently in prod. Maybe we need to investigate more.

@lmiller1990 lmiller1990 reopened this Jul 13, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
3 participants
You can’t perform that action at this time.