admin管理员组

文章数量:1026620

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?

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?

Share Improve this question asked Sep 6, 2018 at 20:21 Michael VezzaniMichael Vezzani 931 gold badge1 silver badge5 bronze badges
Add a comment  | 

2 Answers 2

Reset to default 22

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')

ComponentA is a component definition with update as a child of the methods attribute so update will not be found on ComponentA or ComponentB. spyOn should be applied on the instance of the component instead.

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

// create a spy on the instance method
const spyUpdate = jest.spyOn(wrapper.vm, 'update')

// replace the instance method with the spy
wrapper.setMethods({ update: spyUpdate });

// your tests ...

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

// remove the spy
spyUpdate.mockReset();

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?

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?

Share Improve this question asked Sep 6, 2018 at 20:21 Michael VezzaniMichael Vezzani 931 gold badge1 silver badge5 bronze badges
Add a comment  | 

2 Answers 2

Reset to default 22

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')

ComponentA is a component definition with update as a child of the methods attribute so update will not be found on ComponentA or ComponentB. spyOn should be applied on the instance of the component instead.

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

// create a spy on the instance method
const spyUpdate = jest.spyOn(wrapper.vm, 'update')

// replace the instance method with the spy
wrapper.setMethods({ update: spyUpdate });

// your tests ...

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

// remove the spy
spyUpdate.mockReset();

本文标签: