-
Notifications
You must be signed in to change notification settings - Fork 93
Add support for Angular bindings API with twoWayBinding #547
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
Co-authored-by: timdeschryver <28659384+timdeschryver@users.noreply.github.com>
Co-authored-by: timdeschryver <28659384+timdeschryver@users.noreply.github.com>
export * from './lib/testing-library'; | ||
|
||
// Re-export Angular's binding functions for convenience | ||
export { inputBinding, outputBinding, twoWayBinding, type Binding } from '@angular/core'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@copilot don't do this
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed the re-exports. Users now import inputBinding
, outputBinding
, and twoWayBinding
directly from @angular/core
as requested. Commit ec079c2
// Only use traditional input/output setting if no bindings are provided | ||
// When bindings are used, they handle inputs and outputs natively | ||
if (!bindings || bindings.length === 0) { | ||
setComponentProperties(createdFixture, properties); | ||
setComponentInputs(createdFixture, inputs); | ||
setComponentOutputs(createdFixture, outputs); | ||
subscribedOutputs = subscribeToComponentOutputs(createdFixture, subscribeTo); | ||
} else { | ||
// With bindings, we still need to handle componentProperties for non-input properties | ||
setComponentProperties(createdFixture, properties); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@copilot is it possible to use the current syntax together with bindings? If a binding is used with the same name as an input/output/property then the binding should take preference, ideally we can log a warning when this happens.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Implemented mixed usage support with warnings. Angular doesn't allow mixing setInput()
with inputBinding()
, so bindings take full precedence for inputs (with warning). Traditional output listeners work alongside outputBinding()
. Added comprehensive test coverage for this behavior. Commit ec079c2
* An array of bindings to apply to the component using Angular v20+'s native bindings API. | ||
* This provides a more direct way to bind inputs and outputs compared to the `inputs` and `on` options. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@copilot remove the mention of v20
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed version references. Documentation now refers to "Angular's native bindings API" without specific version mentions. Commit ec079c2
@copilot please look at my review comments |
…arnings, remove v20 references Co-authored-by: timdeschryver <28659384+timdeschryver@users.noreply.github.com>
Just as a heads up, I was blocked by some firewall rules while working on your feedback. Expand below for details. Warning Firewall rules blocked me from connecting to one or more addresses (expand for details)I tried to connect to the following addresses, but was blocked by firewall rules:
If you need me to access, download, or install something from one of these locations, you can either:
|
@lacolaco is this what you had in mind? |
@timdeschryver Thanks. I'm gonna review in this week. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Basically, this is definitely what I wanted! I left some comments and suggestions on the implementation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing apps/example-app/src/app/examples/23-bindings-api.component.spec.ts
. It should explain the bindings
usage.
clicked = output<string>(); | ||
} | ||
|
||
it('should support inputBinding for regular inputs', async () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be better to add a case for a re-rendering scenario which uses inputBinding
with a writable signal.
const valueSignal = signal('test-value');
await render(BindingsTestComponent, {
bindings: [inputBinding('value', valueSignal), inputBinding('greet', () => 'hi there')],
});
// <= assert 'test-value' is rendered.
valueSignal.set('updated-value');
// <= assert 'updated-value' is rendered
|
||
expect(clickHandler).toHaveBeenCalledWith('clicked: bound-value'); | ||
}); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
twoWayBinding
scenario also should be tested.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the review and input @lacolaco ! Let's see how copilot will handle this 👀
README.md
Outdated
|
||
```typescript | ||
import { render, screen } from '@testing-library/angular'; | ||
import { inputBinding, outputBinding } from '@angular/core'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
twoWayBinding
too.
@copilot also add the functionality for Example: const checkboxValue = signal('');
createComponent(MyCheckbox, {
bindings: [
twoWayBinding('value', checkboxValue),
],
}); And resolve this comment:
|
Co-authored-by: timdeschryver <28659384+timdeschryver@users.noreply.github.com>
Added Warning Firewall rules blocked me from connecting to one or more addresses (expand for details)I tried to connect to the following addresses, but was blocked by firewall rules:
If you need me to access, download, or install something from one of these locations, you can either:
|
expect(await screen.findByText('updated-value')).toBeInTheDocument(); | ||
}); | ||
|
||
it('should support twoWayBinding for model signals', async () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
looks perfect
Overview
This PR implements support for Angular's native bindings API in Angular Testing Library, addressing the suggestion in #526 that ATL's current input/output interfaces may be unnecessary with Angular's new approach.
What's New
Angular introduced a native bindings API that allows direct binding of inputs and outputs when creating components with
TestBed.createComponent()
:This PR adds seamless support for this pattern in ATL while maintaining full backward compatibility.
Usage Examples
New Bindings API
Traditional API (Still Supported)
Mixed Usage
Benefits
Implementation Details
bindings?: Binding[]
option toRenderComponentOptions
createComponent()
to useTestBed.createComponent(component, { bindings })
when bindings are provided@angular/core
Binding Types Supported
inputBinding()
- Bind input values, including with writable signals for dynamic updatesoutputBinding()
- Listen to component outputstwoWayBinding()
- Bidirectional data binding with writable signalsMixed Usage Behavior
Due to Angular's limitations, inputs and outputs behave differently when mixing approaches:
setInput()
withinputBinding()
, so bindings take complete precedence (with warning)outputBinding()
and traditionalon
listeners work togetherMigration Path
Users can gradually adopt the new bindings API:
inputs
/on
APIs - no changes requiredbindings
for new tests while keeping existing tests unchangedThis provides a smooth transition path while giving users access to Angular's modern testing capabilities.
Fixes #546
Fixes #546
💬 Share your feedback on Copilot coding agent for the chance to win a $200 gift card! Click here to start the survey.