Can't access method in Vue Single File Component with Jest when using <script setup>

1.7k Views Asked by At

I'd like to test specific methods in my Vue Single File Components using Jest. I'm using Vue 3 with the Composition API, and I would like to use the <script setup> approach but it appears to prevent this.

This works:

Component:

<script>
export default {
  setup() {
    const testMethod = function(input) {
      return input + 1;
    };
    return { testMethod };
  },
};
</script>

Test:

test('should be 2', () => {
  expect(TestComponent.setup().testMethod(1)).toBe(2); // success
});

This doesn't work:

Component:

<script setup>
const testMethod = function(input) {
  return input + 1;
};
</script>

Test:

test('should be 2', () => {
  expect(TestComponent.setup().testMethod(1)).toBe(2); // TypeError: Cannot destructure property 'expose' of 'undefined' as it is undefined.
  expect(TestComponent.testMethod(1)).toBe(2); // TypeError: _testComponent.default.testMethod is not a function
});

Is there another way to accomplish this, or is accessing the methods within the component not possible with the <script setup> approach?

Edit: Specifically looking for solutions that don't require mounting the gadget with something like vue-test-utils.

3

There are 3 best solutions below

0
On

I am also facing the same issue. below ways can help us to resolve this

  1. (wrapper.vm as any)._setupProxy.someMethod

    not sure using _setupProxy is the proper way or not.

  2. import {shallowMount,createLocalVue} from '@vue/test-utils';
    import VueCompositionApi from '@vue/composition-api';
    
    const localVue = createLocalVue()
    localVue.use(VueCompositionApi)
    shallowMount(require('./component.vue').default, {
      localVue,
    });
    
2
On

The bindings declared in <script setup> are hidden by default, but you can expose any of them to the component instance with defineExpose():

// MyComponent.vue
<script setup>
const testMethod = function(input) {
  return input + 1;
};

defineExpose({
  testMethod
})
</script>

Then in your test, access the exposed bindings via wrapper.vm (the component instance from the @vue/test-utils wrapper):

// MyComponent.spec.js
import MyComponent from '@/components/MyComponent.vue'

test('should be 2', () => {
  const wrapper = shallowMount(MyComponent)
  expect(wrapper.vm.testMethod(1)).toBe(2)
})

demo

0
On

if you use the wrapper of the mount method from vue test @vue/test-utils. Then just call the methods using (wrapper.vm as any) it works. Only the typescript compiler is unable to recognize and raise the error as property does not exist but when you try using something like below it works.

Eg: (wrapper.vm as any).someMethod()