diff --git a/src/vueWrapper.ts b/src/vueWrapper.ts index 8969386c7..164c7b501 100644 --- a/src/vueWrapper.ts +++ b/src/vueWrapper.ts @@ -1,5 +1,5 @@ import type { App, ComponentPublicInstance, VNode } from 'vue' -import { nextTick, proxyRefs } from 'vue' +import { nextTick, proxyRefs, unref } from 'vue' import { config } from './config' import domEvents from './constants/dom-events' @@ -27,14 +27,17 @@ function createVMProxy( ): T { return new Proxy(vm, { get(vm, key, receiver) { - if (vm.$.exposed && vm.$.exposeProxy && key in vm.$.exposeProxy) { - // first if the key is exposed + if (vm.$.exposeProxy && key in vm.$.exposeProxy) { + // first if the key is exposed in exposeProxy return Reflect.get(vm.$.exposeProxy, key, receiver) + } else if (vm.$.exposed && key in vm.$.exposed) { + // second if the key is exposed + return unref(Reflect.get(vm.$.exposed, key, receiver)) } else if (key in setupState) { - // second if the key is acccessible from the setupState + // third if the key is acccessible from the setupState return Reflect.get(setupState, key, receiver) } else if (key in vm.$.appContext.config.globalProperties) { - // third if the key is a global property + // fourth if the key is a global property return Reflect.get( vm.$.appContext.config.globalProperties, key, diff --git a/tests/expose.spec.ts b/tests/expose.spec.ts index 1cb0a0ca7..011d4b75e 100644 --- a/tests/expose.spec.ts +++ b/tests/expose.spec.ts @@ -155,4 +155,88 @@ describe('expose', () => { expect(spiedIncrement).toHaveBeenCalled() expect(wrapper.html()).toContain('-1') }) + + describe('when exposeProxy is null', () => { + const nullifyExposeProxy = (vm: any) => { + vm.$.exposeProxy = null + } + + it('access vm on simple components with custom `expose`', async () => { + const wrapper = mount(DefineExpose) + const vm = wrapper.vm + + nullifyExposeProxy(vm) + commonTests(vm) + + // returned state shuold be accessible + expect(vm.returnedState).toBe('returnedState') + + // non-exposed and non-returned state should not be accessible + expect( + (vm as unknown as { stateNonExposedAndNonReturned: undefined }) + .stateNonExposedAndNonReturned + ).toBe(undefined) + }) + + it('access vm on simple components with custom `expose` and a setup returning a render function', async () => { + const wrapper = mount(DefineExposeWithRenderFunction) + const vm = wrapper.vm + + nullifyExposeProxy(vm) + commonTests(vm) + + // can't access `refUseByRenderFnButNotExposed` as it is not exposed + // and we are in a component with a setup returning a render function + expect( + (vm as unknown as { refUseByRenderFnButNotExposed: undefined }) + .refUseByRenderFnButNotExposed + ).toBeUndefined() + }) + + it('access vm with