From 191c61c4d3c8174b5f1359cc83749907bd9bf791 Mon Sep 17 00:00:00 2001 From: Adam Berecz Date: Tue, 30 Sep 2025 14:41:01 +0200 Subject: [PATCH 1/4] fix: created exposeProxy from exposed when not available --- src/vueWrapper.ts | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/vueWrapper.ts b/src/vueWrapper.ts index 61c5edd20..3cc794fda 100644 --- a/src/vueWrapper.ts +++ b/src/vueWrapper.ts @@ -26,14 +26,18 @@ function createVMProxy( ): T { return new Proxy(vm, { get(vm, key, receiver) { - if (vm.$.exposed && vm.$.exposeProxy && key in vm.$.exposeProxy) { + 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) { // first if the key is exposed - return Reflect.get(vm.$.exposeProxy, key, receiver) + return Reflect.get(proxyRefs(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, From eb826a7fdaeab86a2c4de91ff27f82cb85a53c9f Mon Sep 17 00:00:00 2001 From: Adam Berecz Date: Tue, 30 Sep 2025 14:41:26 +0200 Subject: [PATCH 2/4] fix: typo fix --- src/vueWrapper.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vueWrapper.ts b/src/vueWrapper.ts index 3cc794fda..8c429addf 100644 --- a/src/vueWrapper.ts +++ b/src/vueWrapper.ts @@ -31,7 +31,7 @@ function createVMProxy( return Reflect.get(vm.$.exposeProxy, key, receiver); } else if (vm.$.exposed && key in vm.$.exposed) { - // first if the key is exposed + // second if the key is exposed return Reflect.get(proxyRefs(vm.$.exposed), key, receiver); } else if (key in setupState) { // third if the key is acccessible from the setupState From a6536a4a70a91fda5b021ebfa801afd14ff05d54 Mon Sep 17 00:00:00 2001 From: Adam Berecz Date: Wed, 25 Mar 2026 11:47:18 +0100 Subject: [PATCH 3/4] refact: use unref instead of proxyRefs --- src/vueWrapper.ts | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/vueWrapper.ts b/src/vueWrapper.ts index 8c429addf..6d4834a0c 100644 --- a/src/vueWrapper.ts +++ b/src/vueWrapper.ts @@ -1,4 +1,11 @@ -import { nextTick, App, ComponentPublicInstance, VNode, proxyRefs } from 'vue' +import { + nextTick, + App, + ComponentPublicInstance, + VNode, + proxyRefs, + unref +} from 'vue' import { config } from './config' import domEvents from './constants/dom-events' @@ -28,11 +35,10 @@ function createVMProxy( get(vm, key, receiver) { 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) { + return Reflect.get(vm.$.exposeProxy, key, receiver) + } else if (vm.$.exposed && key in vm.$.exposed) { // second if the key is exposed - return Reflect.get(proxyRefs(vm.$.exposed), key, receiver); + return unref(Reflect.get(vm.$.exposed, key, receiver)) } else if (key in setupState) { // third if the key is acccessible from the setupState return Reflect.get(setupState, key, receiver) From 7afafc45ae8408a1eb2137d79b2b87edbf114c71 Mon Sep 17 00:00:00 2001 From: Adam Berecz Date: Wed, 25 Mar 2026 11:47:49 +0100 Subject: [PATCH 4/4] test: add tests for handling null exposeProxy in various component setups --- tests/expose.spec.ts | 84 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) diff --git a/tests/expose.spec.ts b/tests/expose.spec.ts index 28484e2fb..77285a20e 100644 --- a/tests/expose.spec.ts +++ b/tests/expose.spec.ts @@ -156,4 +156,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