1- import { Component , input , output , inputBinding , outputBinding } from '@angular/core' ;
1+ import { Component , input , output , inputBinding , outputBinding , twoWayBinding , signal , model } from '@angular/core' ;
22import { render , screen , aliasedInput } from '../src/public_api' ;
33
44describe ( 'ATL Bindings API Support' , ( ) => {
@@ -17,6 +17,23 @@ describe('ATL Bindings API Support', () => {
1717 clicked = output < string > ( ) ;
1818 }
1919
20+ @Component ( {
21+ selector : 'atl-two-way-test' ,
22+ template : `
23+ <div data-testid="name-display">{{ name() }}</div>
24+ <input data-testid="name-input" [value]="name()" (input)="name.set($any($event.target).value)" />
25+ <button data-testid="update-button" (click)="updateName()">Update</button>
26+ ` ,
27+ standalone : true ,
28+ } )
29+ class TwoWayBindingTestComponent {
30+ name = model < string > ( 'default' ) ;
31+
32+ updateName ( ) {
33+ this . name . set ( 'updated from component' ) ;
34+ }
35+ }
36+
2037 it ( 'should support inputBinding for regular inputs' , async ( ) => {
2138 await render ( BindingsTestComponent , {
2239 bindings : [ inputBinding ( 'value' , ( ) => 'test-value' ) , inputBinding ( 'greet' , ( ) => 'hi there' ) ] ,
@@ -39,6 +56,49 @@ describe('ATL Bindings API Support', () => {
3956 expect ( clickHandler ) . toHaveBeenCalledWith ( 'clicked: bound-value' ) ;
4057 } ) ;
4158
59+ it ( 'should support inputBinding with writable signal for re-rendering scenario' , async ( ) => {
60+ const valueSignal = signal ( 'initial-value' ) ;
61+
62+ await render ( BindingsTestComponent , {
63+ bindings : [ inputBinding ( 'value' , valueSignal ) , inputBinding ( 'greet' , ( ) => 'hi there' ) ] ,
64+ } ) ;
65+
66+ expect ( screen . getByTestId ( 'value' ) ) . toHaveTextContent ( 'initial-value' ) ;
67+ expect ( screen . getByTestId ( 'greeting' ) ) . toHaveTextContent ( 'hi there' ) ;
68+
69+ // Update the signal and verify it reflects in the component
70+ valueSignal . set ( 'updated-value' ) ;
71+
72+ // The binding should automatically update the component
73+ expect ( await screen . findByText ( 'updated-value' ) ) . toBeInTheDocument ( ) ;
74+ } ) ;
75+
76+ it ( 'should support twoWayBinding for model signals' , async ( ) => {
77+ const nameSignal = signal ( 'initial name' ) ;
78+
79+ await render ( TwoWayBindingTestComponent , {
80+ bindings : [ twoWayBinding ( 'name' , nameSignal ) ] ,
81+ } ) ;
82+
83+ // Verify initial value
84+ expect ( screen . getByTestId ( 'name-display' ) ) . toHaveTextContent ( 'initial name' ) ;
85+ expect ( screen . getByTestId ( 'name-input' ) ) . toHaveValue ( 'initial name' ) ;
86+
87+ // Update from outside (signal change)
88+ nameSignal . set ( 'updated from signal' ) ;
89+ expect ( await screen . findByDisplayValue ( 'updated from signal' ) ) . toBeInTheDocument ( ) ;
90+ expect ( screen . getByTestId ( 'name-display' ) ) . toHaveTextContent ( 'updated from signal' ) ;
91+
92+ // Update from component - let's trigger change detection after the click
93+ const updateButton = screen . getByTestId ( 'update-button' ) ;
94+ updateButton . click ( ) ;
95+
96+ // Give Angular a chance to process the update and check both the signal and display
97+ // The twoWayBinding should update the external signal
98+ expect ( await screen . findByText ( 'updated from component' ) ) . toBeInTheDocument ( ) ;
99+ expect ( nameSignal ( ) ) . toBe ( 'updated from component' ) ;
100+ } ) ;
101+
42102 it ( 'should warn when mixing bindings with traditional inputs but still work' , async ( ) => {
43103 const consoleSpy = jest . spyOn ( console , 'warn' ) . mockImplementation ( ) ;
44104 const clickHandler = jest . fn ( ) ;
0 commit comments