From 4f55febdade37117844826ebe65fb9a5a4c911ca Mon Sep 17 00:00:00 2001 From: lidlanca <8693091+lidlanca@users.noreply.github.com> Date: Sat, 12 Feb 2022 18:08:09 -0500 Subject: [PATCH] fix(runtime-core): allow spying on proxy methods regression #5415 #4216 --- .../__tests__/componentPublicInstance.spec.ts | 38 +++++++++++++++++-- .../src/componentPublicInstance.ts | 2 +- 2 files changed, 36 insertions(+), 4 deletions(-) diff --git a/packages/runtime-core/__tests__/componentPublicInstance.spec.ts b/packages/runtime-core/__tests__/componentPublicInstance.spec.ts index fe588115d31..5bcfc91e76c 100644 --- a/packages/runtime-core/__tests__/componentPublicInstance.spec.ts +++ b/packages/runtime-core/__tests__/componentPublicInstance.spec.ts @@ -257,13 +257,13 @@ describe('component: proxy', () => { expect(instanceProxy.isDisplayed).toBe(true) }) - test('allow spying on proxy methods', () => { + test('allow jest spying on proxy methods with Object.defineProperty', () => { let instanceProxy: any const Comp = { render() {}, setup() { return { - toggle() {} + toggle() { return 'a'} } }, mounted() { @@ -274,10 +274,42 @@ describe('component: proxy', () => { const app = createApp(Comp) app.mount(nodeOps.createElement('div')) + + // access 'toggle' to ensure key is cached + let v1 = instanceProxy.toggle() + + // reconfigure "toggle" to be getter based. + let getCalledTimes = 0 + Object.defineProperty(instanceProxy, 'toggle', { + get(){ + getCalledTimes++ + return ()=> 'b' + } + }) - const spy = jest.spyOn(instanceProxy, 'toggle') + // getter should not be evaluated on definition + expect(getCalledTimes).toEqual(0) + + // invoke "toggle" after "defineProperty" + let v2 = instanceProxy.toggle() + expect(getCalledTimes).toEqual(1) + // expect toggle getter not to be cached. it can't be instanceProxy.toggle() + expect(getCalledTimes).toEqual(2) + + // attaching jest spy, triggers the getter once, cache it and override the property. + // also uses Object.defineProperty + const spy = jest.spyOn(instanceProxy, 'toggle') + expect(getCalledTimes).toEqual(3) + + // toggle getter is not going to be evaluated due to jest wrapper caching it result + let v3 = instanceProxy.toggle() + expect(getCalledTimes).toEqual(3) + + expect(v1).toEqual('a') + expect(v2).toEqual('b') + expect(v3).toEqual('b') expect(spy).toHaveBeenCalled() }) diff --git a/packages/runtime-core/src/componentPublicInstance.ts b/packages/runtime-core/src/componentPublicInstance.ts index 0413730032c..53e85ef066d 100644 --- a/packages/runtime-core/src/componentPublicInstance.ts +++ b/packages/runtime-core/src/componentPublicInstance.ts @@ -455,7 +455,7 @@ export const PublicInstanceProxyHandlers: ProxyHandler = { descriptor: PropertyDescriptor ) { if (descriptor.get != null) { - this.set!(target, key, descriptor.get(), null) + target.$.accessCache[key] = 0; } else if (descriptor.value != null) { this.set!(target, key, descriptor.value, null) }