diff --git a/app/angular/src/client/preview/angular-beta/StorybookModule.test.ts b/app/angular/src/client/preview/angular-beta/StorybookModule.test.ts index cceba5cfe89b..ef7e664e07aa 100644 --- a/app/angular/src/client/preview/angular-beta/StorybookModule.test.ts +++ b/app/angular/src/client/preview/angular-beta/StorybookModule.test.ts @@ -14,6 +14,7 @@ describe('StorybookModule', () => { template: `

{{ input }}

{{ localPropertyName }}

+

{{ setterCallNb }}

{{ localProperty }}

{{ localFunction() }}

@@ -27,6 +28,11 @@ describe('StorybookModule', () => { @Input('inputBindingPropertyName') public localPropertyName: string; + @Input() + public set setter(value: string) { + this.setterCallNb += 1; + } + @Output() public output = new EventEmitter(); @@ -36,6 +42,8 @@ describe('StorybookModule', () => { public localProperty: string; public localFunction = () => ''; + + public setterCallNb = 0; } it('should initialize inputs', async () => { @@ -104,6 +112,7 @@ describe('StorybookModule', () => { it('should change inputs if storyProps$ Subject emit', async () => { const initialProps = { input: 'input', + inputBindingPropertyName: '', }; const storyProps$ = new BehaviorSubject(initialProps); @@ -150,6 +159,7 @@ describe('StorybookModule', () => { let expectedOutputValue; let expectedOutputBindingValue; const initialProps = { + input: '', output: (value: string) => { expectedOutputValue = value; }, @@ -225,6 +235,34 @@ describe('StorybookModule', () => { expect(fixture.nativeElement.querySelector('p').style.color).toEqual('black'); expect(fixture.nativeElement.querySelector('p#input').innerHTML).toEqual(newProps.input); }); + + it('should call the Input() setter the right number of times', async () => { + const initialProps = { + setter: 'init', + }; + const storyProps$ = new BehaviorSubject(initialProps); + + const ngModule = getStorybookModuleMetadata( + { + storyFnAngular: { props: initialProps }, + component: FooComponent, + targetSelector: 'my-selector', + }, + storyProps$ + ); + const { fixture } = await configureTestingModule(ngModule); + fixture.detectChanges(); + + expect(fixture.nativeElement.querySelector('p#setterCallNb').innerHTML).toEqual('1'); + + const newProps = { + setter: 'new setter value', + }; + storyProps$.next(newProps); + fixture.detectChanges(); + + expect(fixture.nativeElement.querySelector('p#setterCallNb').innerHTML).toEqual('2'); + }); }); describe('with component without selector', () => { diff --git a/app/angular/src/client/preview/angular-beta/StorybookWrapperComponent.ts b/app/angular/src/client/preview/angular-beta/StorybookWrapperComponent.ts index 9192f213f059..d3017dc5e784 100644 --- a/app/angular/src/client/preview/angular-beta/StorybookWrapperComponent.ts +++ b/app/angular/src/client/preview/angular-beta/StorybookWrapperComponent.ts @@ -98,39 +98,13 @@ export const createStorybookWrapperComponent = ( this.storyComponentViewContainerRef.injector.get(ChangeDetectorRef).markForCheck(); this.changeDetectorRef.detectChanges(); - // Once target component has been initialized, the storyProps$ observable keeps target component inputs up to date + // Once target component has been initialized, the storyProps$ observable keeps target component properties than are not Input|Output up to date this.storyComponentPropsSubscription = this.storyProps$ .pipe( skip(1), map((props) => { - // removes component output in props - const outputsKeyToRemove = ngComponentInputsOutputs.outputs.map( - (o) => o.templateName - ); - return Object.entries(props).reduce( - (prev, [key, value]) => ({ - ...prev, - ...(!outputsKeyToRemove.includes(key) && { - [key]: value, - }), - }), - {} as ICollection - ); - }), - map((props) => { - // In case a component uses an input with `bindingPropertyName` (ex: @Input('name')) - // find the value of the local propName in the component Inputs - // otherwise use the input key - return Object.entries(props).reduce((prev, [propKey, value]) => { - const input = ngComponentInputsOutputs.inputs.find( - (o) => o.templateName === propKey - ); - - return { - ...prev, - ...(input ? { [input.propName]: value } : { [propKey]: value }), - }; - }, {} as ICollection); + const propsKeyToKeep = getNonInputsOutputsProps(ngComponentInputsOutputs, props); + return propsKeyToKeep.reduce((acc, p) => ({ ...acc, [p]: props[p] }), {}); }) ) .subscribe((props) => {