Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using Jest, how do I spyon an extended component's method when unit testing a single file component in vue.js

I'm currently trying to get a single file component (ComponentB) unit tested using Jest and vue-test-utils. ComponentB extends ComponentA, which has a method update(product) defined in it.

/* -------- Component B -------- */
<script>
import ComponentA from './ComponentA'
export default {
  extends: ComponentA,
  props: [...],
  data: () => {
    productData: {foo: 'bar', baz: 'shiz'}
  },
  methods: {
    updateProduct() {
      this.update(this.productData)
    }
  }
}
</script>

/* -------- Component A -------- */
<script>
export default {
  props: [...],
  data: () => {...},
  methods: {
    update(productData) {
      ...
    }
  }
}
</script>

I then attempt a unit test in which I shallowMount() my ComponentB and try to jest.spyOn that update(productData) method that is defined in ComponentA. The test looks like this:

it('calls update with data when input is added to the field', () => {
  const spy = jest.spyOn(ComponentA, 'update);
  const wrapper = shallowMount(ComponentB, { propsData: { ... } });
  const contractIdInput = wrapper.find('#contract-id-input > b-form-input');    

  contractIdInput.element.value = 'foobar';
  contractIdInput.trigger('input')

  expect(spy).toHaveBeenCalledWith(...someDataHere...)
});

When I run this test, I get a Cannot spy the update property because it is not a function; undefined given instead.

I'm not entirely sure why this isn't working, though I do have some ideas.

First, because I am shallowMount()ing my ComponentB, it isn't going to know anything about its parent component, and thus not have access to the update(productData) method that is defined on ComponentA.

Second, perhaps I'm not calling jest.spyOn() at the right time, and should instead call it after I create the wrapper object of ComponentB. However, I tried changing this around and didn't have any success or different behavior.

So my question is, how do I spy on a method that is provided by an extended component when I am shallow mounting the component under test?

like image 244
Michael Vezzani Avatar asked Sep 06 '18 20:09

Michael Vezzani


People also ask

How do you test a method in Jest?

To test method implementation using spies with Jest we use the jest. spyOn() function. jest. spyOn() is called with two required parameters - the object and the object method identifier we're spying on.

Does VUE test utils use Jest?

If you are using the Vue CLI to build your project, you can use the plugin cli-plugin-unit-jest to run Jest tests. The plugin pulls all required dependencies (including jest), creates a jest.

What is createLocalVue?

createLocalVue returns a Vue class for you to add components, mixins and install plugins without polluting the global Vue class. The errorHandler option can be used to handle uncaught errors during component render function and watchers.


1 Answers

Just to add to the answer above of @user2718281, SetMethods it's deprecated, so you better define the spyOn pointing to the ComponentB before instantiating like this:

// create a spy before the instance is created
const spySomeMethod = jest.spyOn(ComponentB.methods, 'someMethod')

const spyUpdate = jest.spyOn(ComponentB.methods, 'update')

const wrapper = shallowMount(ComponentB, { propsData: { ... } });

// your tests ...

// verify the spy was called
expect(spyUpdate).toHaveBeenCalled();

// remove the spy
spyUpdate.mockReset();

And about the question maybe you are forgetting to add the ComponentA.methods like this:

const spySomeMethod = jest.spyOn(ComponentB.methods, 'someMethod')

but if you want to test some lifecycle method event like mounted or created remove the .methods like this:

const spySomeMethod = jest.spyOn(ComponentB, 'created')
like image 97
David Torroija Avatar answered Oct 04 '22 21:10

David Torroija