Skip to content
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

The expose methods cannot be got on the vm #683

Closed
zouhangwithsweet opened this issue Jun 22, 2021 · 9 comments
Closed

The expose methods cannot be got on the vm #683

zouhangwithsweet opened this issue Jun 22, 2021 · 9 comments
Labels
bug Something isn't working

Comments

@zouhangwithsweet
Copy link

zouhangwithsweet commented Jun 22, 2021

<script lang="ts">
export default {
  setup(props, { expose }) {
    const alert = () => { console.log('message')}

    expose({
      alert,
    })

    return () = h('div', { class: 'box' }, ['message'])
  }
}
</script>

The vm doesnot have the alert methods.

@cexbrayat
Copy link
Member

@zouhangwithsweet Thank you for opening an issue. Which version of VTU are you using?

If it is version 2.0.0-rc.8, it might be related to #663

Try with 2.0.0-rc.6 and let us know if you also have the issue.

@zouhangwithsweet
Copy link
Author

OK, sir.

@zouhangwithsweet
Copy link
Author

There is still have the issue with rc.6.

Reproduction

test.vue

<script lang="ts">
import { h } from 'vue'
export default {
  name: 'Test',
  setup(props: any, { expose }: any) {
    const alert = () => {
      console.log('message')
    }

    expose({
      alert,
    })

    return () => h('div', { class: 'box' }, ['message'])
  },
}
</script>

spec.ts

test('test', () => {
  const wrapper = mount(() => h(Test, {}, []), {
    props: {},
  })
  console.log(wrapper.findComponent({ name: 'Test' }).vm) // empty {}
})

@lmiller1990
Copy link
Member

lmiller1990 commented Jun 23, 2021

As soon as I saw this I thought it might be related to #663 as well. But it looks like it isn't.

Does this code work outside of Test Utils? Even after reading the expose RFC, it's still a little confusing to me.

@lmiller1990
Copy link
Member

lmiller1990 commented Jun 23, 2021

Seems we have a bug somewhere. I made this example:

  const Comp = defineComponent({
    setup(props, { expose }) {
      const bar = () => {}
      expose({ bar })
      return () => h('div')
    }
  })
  const app = createApp(Comp)
  const $app = app.mount(document.createElement('div'))

I was able to do console.log($app.$) and search for expose. It has an object like exposed: { bar: [Function] }.

Doing mount with mount(() => h(Test)) also seems to do something strange. I couldn't find the exposed property. This was working, however:

test('test', () => {
  const Comp = defineComponent({
    setup(props, { expose }) {
      const bar = () => {}
      expose({ bar })
      return () => h('div')
    }
  })
  const wrapper = mount(Comp)
  console.log(wrapper.vm) // contains `bar`
})

And was able to expose something on the top level. Unrelated, but I am not clear on the mount(() => h(Test)) syntax is - I am kind of surprised this works at all. What does (() => do here? Why is that required?

I think we need to dive into expose and figure out how it works. We might need to start by figuring out why #663 causes problems with emitting events.

As an aside, what is your use case? Why do you want to expose alert (and then access it with findComponent?)

@lmiller1990 lmiller1990 added the bug Something isn't working label Jun 23, 2021
@zouhangwithsweet
Copy link
Author

zouhangwithsweet commented Jun 24, 2021

I think expose just like assign some methods into getcurrentinstance().proxy. The methods should be got from vm. Actually,I have no idea for this problem

@lmiller1990
Copy link
Member

Something is weird with expose in Test Utils, I don't know what, but I am going to find out. I'll spend a bit more time on this over the weekend. expose is still experimental but it sure would be nice to support it.

@xanf
Copy link
Collaborator

xanf commented Aug 2, 2021

@lmiller1990
Status update here: it seems everything is pretty working as expected both with current state and reverting #663
My test follows

Original component (normal setup):

<script lang="ts">
import { h } from 'vue'
export default {
  name: 'Test',
  setup(props: any, { expose }: any) {
    const alert = () => {
      console.log('message')
    }

    expose({
      alert
    })

    return () => h('div', { class: 'box' }, ['message'])
  }
}
</script>

Component with script setup:

<script setup lang="ts">
function alert() {
  console.log('message')
}

defineExpose({
  alert
})

</script>
<template><div>hello</div></template>

test:

it('works', () => {
  const wrapper = mount(ExposeInSetup);
  expect(wrapper.vm.alert).toBeDefined()
})

And for both cases it works as expected.

When we mount something like mount(() => h(Foo) we are creating wrapper functional component, so it is ok that nothing is exposed on top-level wrapper

it('works', () => {
    const wrapper = mount(() => h(ExposeInSetup))
    expect(wrapper.findComponent(ExposeInSetup).vm.alert).toBeDefined()
  })

This works as expected :)

@lmiller1990
Copy link
Member

Oh, ok! I am guessing there was just some bug in an earlier version of Vue 3, or we had incompatible versions. Good to know this is working now.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

4 participants