diff --git a/libs/ng-mocks/src/lib/mock-helper/mock-helper.stub-member.ts b/libs/ng-mocks/src/lib/mock-helper/mock-helper.stub-member.ts index f16565df8a..1ce0c8c3fb 100644 --- a/libs/ng-mocks/src/lib/mock-helper/mock-helper.stub-member.ts +++ b/libs/ng-mocks/src/lib/mock-helper/mock-helper.stub-member.ts @@ -1,5 +1,18 @@ -export default (instance: T, key: any, value: any, encapsulation?: 'get' | 'set'): any => { - const def = Object.getOwnPropertyDescriptor(instance, key) || {}; +import helperExtractPropertyDescriptor from '../mock-service/helper.extract-property-descriptor'; + +export default ( + instance: T & { __ngMocks__source?: object }, + key: any, + value: any, + encapsulation?: 'get' | 'set', +): any => { + const def = helperExtractPropertyDescriptor(instance, key) ?? {}; + + if (!encapsulation && def.set && (def.set as any).__ngMocksProxy) { + def.set(value); + + return value; + } const descriptor: PropertyDescriptor = { configurable: true, diff --git a/libs/ng-mocks/src/lib/mock-render/func.install-prop-reader.ts b/libs/ng-mocks/src/lib/mock-render/func.install-prop-reader.ts index 1a566b29ce..cc899538b2 100644 --- a/libs/ng-mocks/src/lib/mock-render/func.install-prop-reader.ts +++ b/libs/ng-mocks/src/lib/mock-render/func.install-prop-reader.ts @@ -2,8 +2,8 @@ import coreDefineProperty from '../common/core.define-property'; import helperDefinePropertyDescriptor from '../mock-service/helper.define-property-descriptor'; import helperMockService from '../mock-service/helper.mock-service'; -const createPropertyGet = - (key: keyof any & string, reader: Record, source: Record) => () => { +const createPropertyGet = (key: keyof any & string, reader: Record, source: Record) => { + const handler = () => { if (typeof source[key] === 'function') { if (reader[`__ngMocks_${key}__origin`] !== source[key]) { const clone = helperMockService.createClone(source[key], reader, source); @@ -16,9 +16,13 @@ const createPropertyGet = return source[key]; }; + coreDefineProperty(handler, '__ngMocksProxy', true, false); -const createPropertySet = - (key: keyof any & string, reader: Record, source: Record) => (newValue: any) => { + return handler; +}; + +const createPropertySet = (key: keyof any & string, reader: Record, source: Record) => { + const handler = (newValue: any) => { if (reader[`__ngMocks_${key}`]) { reader[`__ngMocks_${key}`] = undefined; } @@ -27,6 +31,10 @@ const createPropertySet = } source[key] = newValue; }; + coreDefineProperty(handler, '__ngMocksProxy', true, false); + + return handler; +}; const extractAllKeys = (instance: object) => [ ...helperMockService.extractPropertiesFromPrototype(Object.getPrototypeOf(instance)), @@ -45,6 +53,7 @@ export default ( if (!source) { return; } + coreDefineProperty(reader, '__ngMocks__source', source, false); const exists = extractOwnKeys(reader); const fields = [...extractAllKeys(source), ...extra]; for (const key of fields) { diff --git a/tests/issue-1165/test.spec.ts b/tests/issue-1165/test.spec.ts new file mode 100644 index 0000000000..ecd9e34bc5 --- /dev/null +++ b/tests/issue-1165/test.spec.ts @@ -0,0 +1,44 @@ +import { Component } from '@angular/core'; +import { MockBuilder, MockRender, ngMocks } from 'ng-mocks'; + +@Component({ + selector: 'target', + template: `{{ value }}`, +}) +class TargetComponent { + private valueOrigin = 0; + + public get value(): number { + return this.valueOrigin; + } + + public set value(value: number) { + this.valueOrigin = value; + } +} + +// @see https://github.com/ike18t/ng-mocks/issues/1165 +describe('issue-1165', () => { + beforeEach(() => MockBuilder(TargetComponent)); + + it('sets values via proxy', () => { + const fixture = MockRender(TargetComponent); + expect(ngMocks.formatText(fixture)).toEqual('0'); + + fixture.componentInstance.value = 1; + fixture.detectChanges(); + expect(ngMocks.formatText(fixture)).toEqual('1'); + + fixture.point.componentInstance.value = 2; + fixture.detectChanges(); + expect(ngMocks.formatText(fixture)).toEqual('2'); + + ngMocks.stubMember(fixture.componentInstance, 'value', 3); + fixture.detectChanges(); + expect(ngMocks.formatText(fixture)).toEqual('3'); + + ngMocks.stubMember(fixture.point.componentInstance, 'value', 4); + fixture.detectChanges(); + expect(ngMocks.formatText(fixture)).toEqual('4'); + }); +});