From ae57cff9d94040b575d549b7e9e65fa1ab83cbc0 Mon Sep 17 00:00:00 2001 From: Gleb Irovich Date: Wed, 24 Mar 2021 20:19:07 +0100 Subject: [PATCH 1/5] test: add tests to the demo app --- .../app/examples/16-input-setter.spec.ts | 9 +++++++++ apps/example-app/app/examples/16-input-setter.ts | 13 +++++++++++++ 2 files changed, 22 insertions(+) create mode 100644 apps/example-app/app/examples/16-input-setter.spec.ts create mode 100644 apps/example-app/app/examples/16-input-setter.ts diff --git a/apps/example-app/app/examples/16-input-setter.spec.ts b/apps/example-app/app/examples/16-input-setter.spec.ts new file mode 100644 index 00000000..45b1d4e0 --- /dev/null +++ b/apps/example-app/app/examples/16-input-setter.spec.ts @@ -0,0 +1,9 @@ +import { render, screen } from '@testing-library/angular'; +import { InputSetterComponet } from './16-input-setter'; + +test('should run logic in the input setter', async () => { + await render(InputSetterComponet, { componentProperties: { value: 1 } }); + const valueControl = screen.getByTestId('value'); + + expect(valueControl.textContent).toBe('Value is 1'); +}); diff --git a/apps/example-app/app/examples/16-input-setter.ts b/apps/example-app/app/examples/16-input-setter.ts new file mode 100644 index 00000000..1f185363 --- /dev/null +++ b/apps/example-app/app/examples/16-input-setter.ts @@ -0,0 +1,13 @@ +import { Component, Input } from '@angular/core'; + +@Component({ + selector: 'app-fixture', + template: ` {{ modifiedValue }} `, +}) +export class InputSetterComponet { + @Input() set value(value: number) { + this.modifiedValue = `Value is ${value}`; + } + + modifiedValue: string; +} From 315009131839f6955e74fcd9b3c0d768dc185a67 Mon Sep 17 00:00:00 2001 From: Gleb Irovich Date: Wed, 24 Mar 2021 21:52:43 +0100 Subject: [PATCH 2/5] fix: make sure to invoke existing setter if it exists --- .../src/lib/testing-library.ts | 20 ++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/projects/testing-library/src/lib/testing-library.ts b/projects/testing-library/src/lib/testing-library.ts index 55c4d275..ecf25425 100644 --- a/projects/testing-library/src/lib/testing-library.ts +++ b/projects/testing-library/src/lib/testing-library.ts @@ -205,14 +205,24 @@ function setComponentProperties( { componentProperties = {} }: Pick, 'componentProperties'>, ) { for (const key of Object.keys(componentProperties)) { + const descriptor: PropertyDescriptor = Object.getOwnPropertyDescriptor( + fixture.componentInstance.constructor.prototype, + key, + ); let _value = componentProperties[key]; + const defaultGetter = () => _value; + const extendedSetter = (value) => { + _value = value; + descriptor?.set.call(fixture.componentInstance, _value); + fixture.detectChanges(); + }; + Object.defineProperty(fixture.componentInstance, key, { - get: () => _value, - set: (value) => { - _value = value; - fixture.detectChanges(); - }, + get: descriptor?.get || defaultGetter, + set: extendedSetter, }); + + descriptor?.set.call(fixture.componentInstance, _value); } return fixture; } From 3131130821a49f8cc803734a926de31abe0b2084 Mon Sep 17 00:00:00 2001 From: Gleb Irovich Date: Wed, 24 Mar 2021 22:03:37 +0100 Subject: [PATCH 3/5] test: add a test example for getter --- .../examples/16-input-getter-setter.spec.ts | 11 ++++++++++ .../app/examples/16-input-getter-setter.ts | 22 +++++++++++++++++++ .../app/examples/16-input-setter.spec.ts | 9 -------- .../app/examples/16-input-setter.ts | 13 ----------- 4 files changed, 33 insertions(+), 22 deletions(-) create mode 100644 apps/example-app/app/examples/16-input-getter-setter.spec.ts create mode 100644 apps/example-app/app/examples/16-input-getter-setter.ts delete mode 100644 apps/example-app/app/examples/16-input-setter.spec.ts delete mode 100644 apps/example-app/app/examples/16-input-setter.ts diff --git a/apps/example-app/app/examples/16-input-getter-setter.spec.ts b/apps/example-app/app/examples/16-input-getter-setter.spec.ts new file mode 100644 index 00000000..357fe38f --- /dev/null +++ b/apps/example-app/app/examples/16-input-getter-setter.spec.ts @@ -0,0 +1,11 @@ +import { render, screen } from '@testing-library/angular'; +import { InputGetterSetter } from './16-input-getter-setter'; + +test('should run logic in the input setter and getter', async () => { + await render(InputGetterSetter, { componentProperties: { value: 'Angular' } }); + const valueControl = screen.getByTestId('value'); + const getterValueControl = screen.getByTestId('value-getter'); + + expect(valueControl.textContent).toBe('I am value from setter Angular'); + expect(getterValueControl.textContent).toBe('I am value from getter Angular'); +}); diff --git a/apps/example-app/app/examples/16-input-getter-setter.ts b/apps/example-app/app/examples/16-input-getter-setter.ts new file mode 100644 index 00000000..d79f4fb9 --- /dev/null +++ b/apps/example-app/app/examples/16-input-getter-setter.ts @@ -0,0 +1,22 @@ +import { Component, Input } from '@angular/core'; + +@Component({ + selector: 'app-fixture', + template: ` + {{ derivedValue }} + {{ value }} + `, +}) +export class InputGetterSetter { + @Input() set value(value: string) { + this.originalValue = value; + this.derivedValue = 'I am value from setter ' + value; + } + + get value() { + return 'I am value from getter ' + this.originalValue; + } + + private originalValue: string; + derivedValue: string; +} diff --git a/apps/example-app/app/examples/16-input-setter.spec.ts b/apps/example-app/app/examples/16-input-setter.spec.ts deleted file mode 100644 index 45b1d4e0..00000000 --- a/apps/example-app/app/examples/16-input-setter.spec.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { render, screen } from '@testing-library/angular'; -import { InputSetterComponet } from './16-input-setter'; - -test('should run logic in the input setter', async () => { - await render(InputSetterComponet, { componentProperties: { value: 1 } }); - const valueControl = screen.getByTestId('value'); - - expect(valueControl.textContent).toBe('Value is 1'); -}); diff --git a/apps/example-app/app/examples/16-input-setter.ts b/apps/example-app/app/examples/16-input-setter.ts deleted file mode 100644 index 1f185363..00000000 --- a/apps/example-app/app/examples/16-input-setter.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { Component, Input } from '@angular/core'; - -@Component({ - selector: 'app-fixture', - template: ` {{ modifiedValue }} `, -}) -export class InputSetterComponet { - @Input() set value(value: number) { - this.modifiedValue = `Value is ${value}`; - } - - modifiedValue: string; -} From e8894fa2bad8799d375c3377dd18b210187abc71 Mon Sep 17 00:00:00 2001 From: Gleb Irovich Date: Wed, 24 Mar 2021 22:16:33 +0100 Subject: [PATCH 4/5] test: add a test to cover re-rendering scenario --- .../app/examples/16-input-getter-setter.spec.ts | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/apps/example-app/app/examples/16-input-getter-setter.spec.ts b/apps/example-app/app/examples/16-input-getter-setter.spec.ts index 357fe38f..10e0e276 100644 --- a/apps/example-app/app/examples/16-input-getter-setter.spec.ts +++ b/apps/example-app/app/examples/16-input-getter-setter.spec.ts @@ -9,3 +9,17 @@ test('should run logic in the input setter and getter', async () => { expect(valueControl.textContent).toBe('I am value from setter Angular'); expect(getterValueControl.textContent).toBe('I am value from getter Angular'); }); + +test('should run logic in the input setter and getter while re-rendering', async () => { + const component = await render(InputGetterSetter, { componentProperties: { value: 'Angular' } }); + const valueControl = screen.getByTestId('value'); + const getterValueControl = screen.getByTestId('value-getter'); + + expect(valueControl.textContent).toBe('I am value from setter Angular'); + expect(getterValueControl.textContent).toBe('I am value from getter Angular'); + + await component.rerender({ value: 'React' }); + + expect(valueControl.textContent).toBe('I am value from setter React'); + expect(getterValueControl.textContent).toBe('I am value from getter React'); +}); From a9592c2957e0b3e4684a15b7f5e557f4ab3cf559 Mon Sep 17 00:00:00 2001 From: Gleb Irovich Date: Wed, 24 Mar 2021 22:30:05 +0100 Subject: [PATCH 5/5] fix: account for possibly missing setter --- projects/testing-library/src/lib/testing-library.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/projects/testing-library/src/lib/testing-library.ts b/projects/testing-library/src/lib/testing-library.ts index ecf25425..642b86c7 100644 --- a/projects/testing-library/src/lib/testing-library.ts +++ b/projects/testing-library/src/lib/testing-library.ts @@ -213,7 +213,7 @@ function setComponentProperties( const defaultGetter = () => _value; const extendedSetter = (value) => { _value = value; - descriptor?.set.call(fixture.componentInstance, _value); + descriptor?.set?.call(fixture.componentInstance, _value); fixture.detectChanges(); }; @@ -222,7 +222,7 @@ function setComponentProperties( set: extendedSetter, }); - descriptor?.set.call(fixture.componentInstance, _value); + descriptor?.set?.call(fixture.componentInstance, _value); } return fixture; }