Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I spy on a function from setup in vuejs3?

I have a function in my component inside of setup():

export default defineComponent({
  setup() {
    const handleResume = async () => {
      msg.value = {}
      try {
      } catch (err) {
      }
    }
    return { handleResume }
  }
})

Now in my test, I want to create a spy function like this:

import App from '@/views/Frame'
jest.spyOn(App, 'handleResume')

But I am getting this error:

Cannot spy the handleResume property because it is not a function; undefined given instead
like image 465
signup Avatar asked Sep 16 '25 00:09

signup


2 Answers

This requires Vue 3.2.31 (released yesterday), which adds support for mocking Proxy methods, enabling spies on the wrapper.vm from @vue/test-utils.

You can expose methods (or other data) from setup() with the expose property from the context argument. For example, this component exposes handleResume only in tests:

<!-- MyComponent.vue -->
<script>
import { defineComponent } from 'vue'

export default defineComponent({
                   👇
  setup(props, { expose }) {
    const handleResume = async () => true

    if (process.env.NODE_ENV === 'test') {
        👇
      expose({ handleResume })
    }

    return { handleResume }
  }
})
</script>

<template>
  <button @click="handleResume">Click</button>
</template>

If you have <script setup> instead, use the defineExpose() macro:

<!-- MyComponent.vue -->
<script setup>
const handleResume = async () => true

if (process.env.NODE_ENV === 'test') {
       👇
  defineExpose({ handleResume })
}
</script>

Then spy on the exposed handleResume from the wrapper.vm:

// MyComponent.spec.js
import { shallowMount } from '@vue/test-utils'
import MyComponent from '@/components/MyComponent.vue'

describe('MyComponent', () => {
  it('handles resume', async () => {
    const wrapper = shallowMount(MyComponent)
                                         👇
    const handleResume = jest.spyOn(wrapper.vm, 'handleResume')

    await wrapper.find('button').trigger('click')
    expect(handleResume).toHaveBeenCalled()
  })
})

demo

like image 184
tony19 Avatar answered Sep 18 '25 17:09

tony19


you have to switch setup from object to function which return object. So your setup should looks like this:

setup() {
  const handleResume = async () => {
        msg.value = {}
        try {
          
        } catch (err) {
         
        }
      }
      
  return { handleResume }
}
     

After this you have two options, you can use @vue/test-utils, mount component as wrapper in test file and you should get access to your function by wrapper.vm.handleResume. Other solution, you can export your setup to composable and import composable into test instead of mounting component.

like image 29
Witold Avatar answered Sep 18 '25 17:09

Witold