diff --git a/src/vueWrapper.ts b/src/vueWrapper.ts index 59be68aaed..88e640dde3 100644 --- a/src/vueWrapper.ts +++ b/src/vueWrapper.ts @@ -36,12 +36,20 @@ export class VueWrapper this.__app = app // root is null on functional components this.rootVM = vm?.$root - // vm.$.proxy is what the template has access to + // `vm.$.proxy` is what the template has access to // so even if the component is closed (as they are by default for `script setup`) // a test will still be able to do something like // `expect(wrapper.vm.count).toBe(1)` - // (note that vm can be null for functional components, hence the condition) - this.componentVM = vm ? (vm.$.proxy as T) : (vm as T) + // if we return it as `vm` + // This does not work for functional components though (as they have no vm) + // or for components with a setup that returns a render function (as they have an empty proxy) + // in both cases, we return `vm` directly instead + this.componentVM = + vm && + // a component with a setup that returns a render function will have no `devtoolsRawSetupState` + (vm.$ as unknown as { devtoolsRawSetupState: any }).devtoolsRawSetupState + ? ((vm.$ as any).proxy as T) + : (vm as T) this.__setProps = setProps this.attachNativeEventListener() diff --git a/tests/components/DefineExposeWithRenderFunction.vue b/tests/components/DefineExposeWithRenderFunction.vue new file mode 100644 index 0000000000..490fc6104f --- /dev/null +++ b/tests/components/DefineExposeWithRenderFunction.vue @@ -0,0 +1,14 @@ + diff --git a/tests/expose.spec.ts b/tests/expose.spec.ts index c4bcc40368..38f0991c17 100644 --- a/tests/expose.spec.ts +++ b/tests/expose.spec.ts @@ -1,6 +1,7 @@ import { mount } from '../src' import Hello from './components/Hello.vue' import DefineExpose from './components/DefineExpose.vue' +import DefineExposeWithRenderFunction from './components/DefineExposeWithRenderFunction.vue' import ScriptSetupExpose from './components/ScriptSetup_Expose.vue' import ScriptSetup from './components/ScriptSetup.vue' @@ -20,6 +21,16 @@ describe('expose', () => { expect(wrapper.vm.msg).toBe('Hello world') }) + it('access vm on simple components with custom `expose` and a setup returning a render function', async () => { + const wrapper = mount(DefineExposeWithRenderFunction) + + // other is exposed vie `expose` + expect(wrapper.vm.other).toBe('other') + // can't access `msg` as it is not exposed + // and we are in a component with a setup returning a render function + expect(wrapper.vm.msg).toBeUndefined() + }) + it('access vm with