Skip to content

Setup and defineProps #862

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
mgibas opened this issue Aug 12, 2021 · 12 comments
Closed

Setup and defineProps #862

mgibas opened this issue Aug 12, 2021 · 12 comments

Comments

@mgibas
Copy link

mgibas commented Aug 12, 2021

I have a hard time testing components that use setup method (either in <script> or <script setup>) like that:

<script setup>
import { reactive } from 'vue'

defineProps({
  msg: String
})

const state = reactive({ count: 0 })
</script>

test:

import { mount } from '@vue/test-utils'
import HelloWorld from '@/components/hello-world.vue'

test("hellow world", () => {
  const wrapper = mount(HelloWorld, {
    props: {
      msg: 'Hello world'
    }   
  })  

  expect(wrapper.vm.msg).toEqual('Hello world')
  expect(wrapper.vm.state.count).toEqual(0)
})

Component seems to be mounted properly, though there is no vm.state.count or vm.msg on it :( All of this works when I move these declarations outside of the setup:

<script>
export default {
  props: {
    msg: String
  },
  data () {
    return {
      count: 0
    }
  }
}
</script>

Am I missing something, like some extra call, await or something ?

Versions:

"vue": "^3.2.2"
"@vue/test-utils": "^2.0.0-rc.12"
"@vue/compiler-sfc": "^3.2.2"
@standbyoneself
Copy link
Contributor

standbyoneself commented Aug 12, 2021

May be you need to rethink your testing approach. There is no need to test that props/state have some value, you need to test things closer to user interaction.

For example, pass some prop, find an element and assert that text value of this element equals to prop value. Or if you have a function, that makes some modal visible, just emit the click event, find the modal and assert that it is visible.

Make some input and test the output.

Something like this.

@mgibas
Copy link
Author

mgibas commented Aug 13, 2021

Thanks @standbyoneself!
Do you know if lack of support for Composition API is documented somewhere ?

Suggested advice is a big no-no for me (nonetheless thank you, really appreciate your time and effort to help) - I'm using vue-test-utils for my unit tests, and most of the time I want to assert that my code controls state properly, not really interested in markups and all that integrational nature of it (I use cypress on that level, if needed). Now I wonder - is this a new direction that this tool is taking or just your personal opinion ? Again, hard time finding anything about that in docs (release candidate yet, so its probably understandable).

@standbyoneself
Copy link
Contributor

standbyoneself commented Aug 13, 2021

Okay, understand you. May be you want to use defineExpose() method that is included in @vue/compiler-sfc and requires no import inside <script setup>. Check out the example:

HelloWorld.vue

<template>
  <div class="hello-world"></div>
</template>

<script setup>
const someData = 'data';

const someMethod = () => console.log('something cool');

defineExpose({ someData, someMethod });
</script>

HelloWorld.spec.js

import { shallowMount } from '@vue/test-utils';
import HelloWorld from '@/components/HelloWorld.vue';

describe('HelloWorld.vue', () => {
  it('does something cool', () => {
    const wrapper = shallowMount(HelloWorld);

    console.log(wrapper.vm);
  });
});

Outputs:

  HelloWorld.vue
    ✓ does something cool (8ms)

  console.log tests/unit/HelloWorld.spec.js:8
    {
      someData: 'data',
      someMethod: [Function: someMethod],
      hasOwnProperty: [Function (anonymous)]
    }

Here the link to the docs: https://v3.vuejs.org/api/sfc-script-setup.html#defineexpose

@mgibas
Copy link
Author

mgibas commented Aug 13, 2021

@standbyoneself thanks a lot for that link (and even more for example!) - it makes much more sense now. I wasn’t aware that components defined with <script setup> are closed by design which would explain why vue-test-utils have no access to them.

Thanks again kind stranger!

@mgibas mgibas closed this as completed Aug 13, 2021
@cexbrayat
Copy link
Member

Thanks @standbyoneself for helping here!

I just want to correct one statement if someone ends up here:

When you use Options API, you can access your data and methods. Otherwise, when you use Composition API, e.g. ref, reactive, some functions defined inside setup(), you can't access these directly from wrapper.vm.

You can access everything on wrapper.vm when using the Composition API (a lot of us are using this every day). But you can't if the component is using script setup, as the component is closed by design. You indeed have to expose what you want in that case 👍

@standbyoneself
Copy link
Contributor

@cexbrayat Hey there! Am I really wrong?

Hello.vue:

<template></template>

<script>
import { reactive, ref } from '@vue/reactivity';

export default {
  name: 'HelloWorld',
  setup() {
    const number = ref(123);

    const array = reactive([1, 2, 3]);

    const method = () => {};
  },
}
</script>

HelloWorld.spec.js:

import { shallowMount } from '@vue/test-utils'
import HelloWorld from '@/components/HelloWorld.vue'

describe('HelloWorld.vue', () => {
  it('', () => {
    const wrapper = shallowMount(HelloWorld);

    console.log(wrapper.vm);
  });
});

Stdout:

HelloWorld.vue
  ✓  (8ms)

console.log tests/unit/HelloWorld.spec.js:8
  { hasOwnProperty: [Function (anonymous)] }

@cexbrayat
Copy link
Member

The vm represents the view model. So if they are returned to be used in the template (as it was the case in your previous example #862 (comment)), they are accessible on wrapper.vm yes 🙂

@standbyoneself
Copy link
Contributor

standbyoneself commented Aug 23, 2021

@cexbrayat Really. My bad. Fixed my previous comment. Thanks!

@axe-me
Copy link

axe-me commented Aug 24, 2021

I knew the setup scirpt is closed by default and we need to use defineExpose macro to expose instance properties. But if I expose everything just for testing, it kinda defeats the purpose of the setup script that does not need to write the long return statement.

Just wondering if there is any workaround for VTU to expose everything by default just within testing scope.

@cexbrayat
Copy link
Member

@axe-me Agreed. Now that script setup is stable, we'll be able to take a look

@mgibas
Copy link
Author

mgibas commented Aug 27, 2021

Reopening this issue - this + #806 renders script setup components untestable which either should be taken care by vue-test-utils or explicitly mentioned in <script setup> docs.

@mgibas mgibas reopened this Aug 27, 2021
@cexbrayat
Copy link
Member

I may have a solution for the exposition problem: see PR #931

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants