4
votes

I am about to test some behaviour in a Vue component which only occurs on props change. The Vue component looks similar to this component, the relevant logic for the test happens in the watcher.

<script>
export default {
  components: {
  },
  props: {
    examleProp: {
      type: Boolean,
      required: false,
      default: false,
    }
  },
  watch: {
    exampleProp: function(newVal, oldVal) {
        // logic which needs to be tested
    },
  }
};
</script>

<template>
  <h1>hello world</h1>
</template>

The test logic is running fine when following the below approach.

it('example test', done => {
    let wrapper = mount(exampleComponent, {
        propsData: {
        },
        template: `
        <example-component >
        </example-component>
    `
    });

    wrapper.setProps({
        isSubmitting: true
    });
});

The watcher is called and ready to be tested, all good.

Since the test is supposed to be integrated in a testsuite, there are some limitations. The component is not mounted but the instance of it like this:

it('example test', done => {
     let wrapper = new Vue({
      components: {
        exampleComponent,
      },
      template: `
        <example-component></example-component>
      `,
    }).$mount();

    // how to update props now?
    // wrapper.setProps  && wrapper.$setProps are both undefined
});

So what i am trying to achieve is a way to update the props of the instance of an component to trigger the watcher to run, any Ideas on this?

1
this might help vuejs.org/v2/guide/…Ja9ad335h
not really :( it shows how to set up props initally und how to update component data, but how to update props dynamically seems to be missing.Jannik Lehmann
Can you clarify why you need to instantiate the Vue instance for your test suite? Why can't mount()/shallowMount() be used in that case?tony19
Where are you passing any props to example-component?Constantin Groß
@ConstantinGroß in both examples using the setProps method, to be precise it's the comment in the second exampleJannik Lehmann

1 Answers

1
votes

If you absolutely must use an actual Vue instance in the test-suite instead of the test-utils wrapper, you can do this:

  1. Update the prop by making it dependent on an arbitrary data property of the Vue instance itself (i.e., vm.unchanged).
  2. Insert a vm.$set call into the vm.mounted() lifecycle hook that changes vm.unchanged, thus triggering the watch on exampleComponent.exampleProp.

const exampleComponent = {
  components: {
  },
  template: `<div>
<h1 style="color: green">ExamleProp unchanged: {{ exampleProp }}</h1>
<h1 style="color: red">Updated: {{ updated }}</h1>
</div>`,
  props: {
    exampleProp: {
      type: Boolean,
      required: false,
      default: false,
    }
  },
  data() {
    return {
      updated: false,
    };
  },
  watch: {
    exampleProp: function(newVal, oldVal) {
        this.updated = true;
    },
  }
};

const vm = new Vue({
      el: '#app',
      components: {
        exampleComponent,
      },
      data: {
        unchanged: true,
      },
      template: `
        <example-component :example-prop="unchanged"></example-component>
      `,
      mounted() {
        this.$set(this, 'unchanged', false);
      } 
    }).$mount();
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app"></div>

Hope that helps!