-
Notifications
You must be signed in to change notification settings - Fork 3.2k
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
Setting input signals with Angular component tests not supported #29264
Comments
When mounting a template, it looks like the componentProperty type is assumed to be correct and inferred, rather than sourced from the mounted component. When you mount According to your test component, its properties are:
When mounting this component, you are passing a |
Hi @cacieprins, Thank you for the response. I would like to point out, however, that passing the types Furthermore, the solution provided does not address the issue with outputSpy. Given Angular's increasing emphasis on the use of signals, it's probable that more people will have similar challenges shortly. |
I have the exact same issue with input signals using mount, configuring the component with non-signal data throws the ctx error and using signal inputs as component property throws the Inject context error. Relying to the inline template method is currently the only way to make it work with latest version, it’s not ideal. |
@cacieprins I am not sure why you closed this issue so soon, because this is very much a big issue for Angular component testing. I think you misunderstood the issue. This is very important: In Angular, signal inputs are of type
This is how input signals work in Angular, and this is currently not supported in Cypress. @jennifer-shehane can this issue be reopened? |
Dmytro Mezhenskyi from Decoded Frontend suggested a solution with a TestHost Component that sets the inputs, which works with Cypress: |
@denisyilmaz IMHO it's very poor DevX to have to create a wrapper component just to be able to test components with signal inputs. This should be natively supported by Cypress. |
@Waterstraal absolutely! I mentioned this as a workaround for the time being until this is natively supported by Cypress. |
I am sorry for closing this prematurely. Angular is not my area of expertise, and I did not fully understand the issue at hand. |
Having to wrap every input and output in a test component is pretty painful. @cacieprins, when do you think you'll be able to provide an ETA on a fix for this? I converted my entire project to using |
@jennifer-shehane could I kindly ask for an update on this issue? I think this issue is very important to fix because Angular apps are swiftly migrating to using signals, and this issue is making it hard to test those components and apps. Note that a Playwright release that supports Angular Component testing with signal inputs is close to being released. Thank you! |
UpdatesHey all. Sorry for the delay on the issue update here. The good news is we are getting pretty close to supporting signals for Angular version Since signals introduced new methods/types to the API, we need to introduce a new test harness to Cypress in order to support signals. Right now we are calling it If any of you want to try the new testing harness, it is available on this commit. Give it an import { mount } from 'cypress/angular-signals' @FrankVerbeek I created a PR against your sample issue with the new testing harness. Let me know what you think and if it solves your needs. Documentation / BehaviorI am currently starting work to get Typings issueMentioned in the issue is the following:
This is because in our standard componentProperties?: Partial<{ [P in keyof T]: T[P] }> In our new componentProperties?: Partial<{ [P in keyof T]: T[P] extends InputSignal<infer V> ? InputSignal<V> | WritableSignal<V> | V : T[P]}> This way, specifying a Input Signal BehaviorGetting
cy.mount(TestComponentComponent, {
componentProperties: {
title: 'Test Component',
},
}); is really cy.mount(TestComponentComponent, {
componentProperties: {
title: signal('Test Component'),
},
}); This allows us to make a signal and avoid the Change spy for inputsSince the prop in question is an cy.mount(TestComponentComponent, {
componentProperties: {
title: 'Test Component',
// @ts-expect-error
titleChange: createOutputSpy('titleChange')
},
});
// some action that changes the title...
// this assertion will NEVER be true, even if you make `title` a signal. we will NEVER emit change events for props that are type `input()`
cy.get('@titleChange').should('have.been.called'); Which brings up the question, how can I change or assert on input updates/changes?
Since const myTitleSignal = signal('Test Component')
cy.mount(TestComponentComponent, {
componentProperties: {
title: myTitleSignal
},
});
cy.get('the-title-element').should('have.text', 'Test Component')
cy.then(() => {
// now set the input() through a signal to update the one-way binding
myTitleSignal.set('FooBar')
})
// works
cy.get('the-title-element').should('have.text', 'FooBar') Model Signal BehaviorSince
cy.mount(TestComponentComponent, {
componentProperties: {
count: 1
},
});
cy.get('the-count-element').should('have.text', '1') Change spy for modelsSince the prop in question is an cy.mount(TestComponentComponent, {
componentProperties: {
count: 4,
// @ts-expect-error
countChange: createOutputSpy('countChange')
},
});
// some action that changes the count...
// this assertion will be true
cy.get('@countChange').should('have.been.called'); However, since let count = 5
cy.mount(TestComponentComponent, {
componentProperties: {
count,
// @ts-expect-error
countChange: createOutputSpy('countChange')
},
});
// some action that changes the count to 7 inside the component
cy.then(() => {
// this assertion will never be true. Count will be 5
expect(count).to.be(7)
})
// However, the change spy WILL be called since the change occurred inside the component let count = 5
cy.mount(TestComponentComponent, {
componentProperties: {
count,
// @ts-expect-error
countChange: createOutputSpy('countChange')
},
});
cy.then(() => {
count = 8
})
// this assertion will never be true. Count will be 5
cy.get('the-count-element`).should('have.text`, '8')
// the change spy will also NOT be called Which brings up the question, how can I have two-way data-binding set up?
let count = signal(5)
cy.mount(TestComponentComponent, {
componentProperties: {
count
},
});
// some action that changes the count to 7 inside the component
cy.then(() => {
// this assertion will be true
expect(count()).to.be(7)
})
// Additionally, if registered, the change spy will also be called let count = signal(5)
cy.mount(TestComponentComponent, {
componentProperties: {
count
},
});
cy.then(() => {
count.set(8)
})
// this assertion will be true
cy.get('the-count-element').should('have.text', '8')
// the change spy will also be called
// later in the test , some action that changes the count to 14 inside the component
// this assertion will be true
cy.get('the-count-element').should('have.text', '14') I am not an expert on |
Released in This comment thread has been locked. If you are still experiencing this issue after upgrading to |
Current behavior
With Angular versions 17.1 and 17.2, signal and model inputs were added, respectively. As we transition to using signals more frequently in our components, we have encountered several problems while setting up our component tests. It appears that setting input signals in Cypress component tests is not supported, despite the documentation stating that Cypress version 13.5.0 and onwards supports Angular 17.
When attempting to set up a component test by mounting the Component directly, it fails to set the signal/model inputs through the componentProperties and gives incorrect type assertions on componentProperties. Additionally, the outputSpy does not capture the change event from the model input either.
However, mounting the component with input signals through a template does work. I view this as a workaround, though.
Example code can be found here:
https://github.com/FrankVerbeek/angular-signal-component-test/blob/main/angular-signal-component-test/src/app/test-component/test-component.component.cy.ts
type assertion error:
not working example (mounting component):
working example (template):
Desired behavior
We want to be able to set input signals and model inputs directly through the componentProperties when mounting an Angular component using these kind of inputs.
Test code to reproduce
I have created a repo with an example. In the test-component.component.cy.ts file I created two tests, one which mounts the Component directly. This one doesn't work with setting the signal inputs. The second test uses a template and does work, kind of a workaround for now.
https://github.com/FrankVerbeek/angular-signal-component-test
The first test will throw the exception: "TypeError: ctx.title is not a function"
Cypress Version
13.7.2
Node version
20.11.1
Operating System
Windows 11
Debug Logs
No response
Other
No response
The text was updated successfully, but these errors were encountered: