Vue-test-utils: False attribute are not rendered between props in snapshot

Created on 1 Aug 2018  ·  9Comments  ·  Source: vuejs/vue-test-utils

Version

1.0.0-beta.22

Reproduction link

https://codesandbox.io/s/4r0ozl6ky7

Steps to reproduce

When I set some attributes set to false, I cannot see them in the generated snapshot

<template>
  <div :false-attribute="false" :true-attribute="true">
</template>

What is expected?

<div
  false-attribute="false"
  true-attribute="true"
/>   

What is actually happening?

<div
  true-attribute="true"
/>   

Most helpful comment

I did some testing. If the props is true, my html shows like this:

<div id="app" msg="new message"><img alt="Vue logo" src="./assets/logo.png">
  <helloworld-stub msg="Welcome to Your Vue.js App" someprop="true"></helloworld-stub>
</div>

if false

<div id="app" msg="new message"><img alt="Vue logo" src="./assets/logo.png">
  <helloworld-stub msg="Welcome to Your Vue.js App"></helloworld-stub>
</div>

So in your case, the loading props is not undefined, the loading attribute is.

attributes (code here) just calls the attributes function on a DOM element; which will not return something not present in the rendered HTML (DOM behavior). So that's why it's undefined when a property is false; it doesn't appear in the DOM. This isn't something we can change, it's how the DOM works.

If you really want to assert against the prop, you can hackily access it like this: wrapper.find('helloworld-stub').vm._props.someProp). I would advise against this; both Vue's API and VTU's API may change for Vue 3, and this might no longer work. It's also bad practice - you aren't actually testing anything.

So, your options:

  • use vm._props.isLoading.
  • using mount here. It might not be a "true unit test", but the goal is to make sure your components work, not to isolate everything.

Hopefully this helps.

All 9 comments

This also happens when using Vue in a real browser environment. I think this is to because <div false-attribute="false"> is not actually correct HTML (or rather, is has no meaning in a browser, even if you write it), so JSDOM does not render it (thus it does not appear in the snapshot). This is intentional behavior of Vue/JSDOM/HTML.

Yes, since this is DOM behavior we won't change it in this library.

But I need to pass a prop that is "false" to my ChildComponent.
the prop can be "true", "'myString'", "8", "{ some: 'object' }", "[ 'some', 'array']" or "false"

I understand why it is not rendered. But I don't understand why Snapshots won't contain prop set false

The snapshot is generated by JSDOM. A snapshot it just a comparsion between two wrapper.html that are saved, which is just innerHTML. Since JSDOM y removed the element when you save the snapshot, it will not appear in the snapshot.

But, what about when is a prop? I can't check the prop passed to a stubbed component when is false

    context('when is loading', () => {
      it('renders card with loading prop true', () => {
        isFetching.returns(true);
        const wrapper = buildWrapper({ useShallow: true });
        const subject = wrapper.find('Card-stub').attributes('loading'); // this returns 'true'

        expect(subject).to.eq('true');
      });
    });

    context('when is not loading', () => {
      it('renders card with loading prop false', () => {
        isFetching.returns(false);
        const wrapper = buildWrapper({ useShallow: true });
        const subject = wrapper.find('Card-stub').attributes('loading'); // this returns undefined

        expect(subject).to.eq('false');
      });
    });

And my Component:

```vue

You are just testing that your isFetching mock works correctly in that example . The test doesn't actually prove the component is doing what is should be when isFetching is true/false.

Would using mount and making an assertions against the rendered DOM (eg, does some <div id="loading" /> element appear) be an option?

Partially I agree, for this case, I wouldn't like to test if Card component it works, I'd like to see if the isFetching is applied to loading prop of this Card component, btw, using mount it might work, but, it looks that I'm scaping from unit tests

Anyway, what I'm trying to understand is: when the isFetching is false, why the loading prop returns undefined

I did some testing. If the props is true, my html shows like this:

<div id="app" msg="new message"><img alt="Vue logo" src="./assets/logo.png">
  <helloworld-stub msg="Welcome to Your Vue.js App" someprop="true"></helloworld-stub>
</div>

if false

<div id="app" msg="new message"><img alt="Vue logo" src="./assets/logo.png">
  <helloworld-stub msg="Welcome to Your Vue.js App"></helloworld-stub>
</div>

So in your case, the loading props is not undefined, the loading attribute is.

attributes (code here) just calls the attributes function on a DOM element; which will not return something not present in the rendered HTML (DOM behavior). So that's why it's undefined when a property is false; it doesn't appear in the DOM. This isn't something we can change, it's how the DOM works.

If you really want to assert against the prop, you can hackily access it like this: wrapper.find('helloworld-stub').vm._props.someProp). I would advise against this; both Vue's API and VTU's API may change for Vue 3, and this might no longer work. It's also bad practice - you aren't actually testing anything.

So, your options:

  • use vm._props.isLoading.
  • using mount here. It might not be a "true unit test", but the goal is to make sure your components work, not to isolate everything.

Hopefully this helps.

Thanks @lmiller1990, u're right, we write tests to make sure that the code works =)
About the .attributes method, I was using because of .props it was returning an empty object.

I'm gonna use mount, it looks better, thank you again

Was this page helpful?
0 / 5 - 0 ratings