Skip to content

Commit a00f7fb

Browse files
chore: Cypress 13.13.0 Release (#5855)
* feat: first pass at adding angular signals documentation (#5841) * feat: first pass at adding angular signals documentation * take suggestions from code review * remove info from mount overview for angular-signals * use contraction for does not * overhaul the angular signals documentation to be more user friendly on usage and not so technical * empty commit to kick off ci * changelog for 13.13.0 --------- Co-authored-by: Cacie Prins <cacie@cypress.io>
1 parent 4e03ffa commit a00f7fb

File tree

3 files changed

+195
-1
lines changed

3 files changed

+195
-1
lines changed

docs/guides/component-testing/angular/api.mdx

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,12 @@ sidebar_position: 40
1111
import { mount } from 'cypress/angular'
1212
```
1313

14+
Be sure to use the `cypress/angular-signals` package if using Angular `17.2` and up and wishing to test `signal()`s within your component tests.
15+
16+
```js
17+
import { mount } from 'cypress/angular-signals'
18+
```
19+
1420
<table class="api-table">
1521
<tr>
1622
<td>Description</td>
@@ -153,7 +159,7 @@ providers, declarations, imports and even component @Inputs()
153159
<tr>
154160
<td>componentProperties</td>
155161
<td>Partial&lt;&lbrace;[P in keyof T]: T[P];&rbrace;&gt; (optional)</td>
156-
<td></td>
162+
<td> If using the `cypress/angular-signals` test harness, this type is adapted to `Partial<{[P in keyof T]: T[P] extends InputSignal<infer V> ? InputSignal<V> | WritableSignal<V> | V : T[P]}>` to allow for generic types to be wrapped inside a signal</td>
157163
</tr>
158164
</table>
159165

docs/guides/component-testing/angular/examples.mdx

Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,170 @@ in the future
193193

194194
:::
195195

196+
### Signals
197+
198+
With the releases of Angular versions [17.1](https://github.com/angular/angular/blob/main/CHANGELOG.md#1710-2024-01-17) and [17.2](https://github.com/angular/angular/blob/main/CHANGELOG.md#1720-2024-02-14), [input](https://github.com/angular/angular/pull/53521) and [model](https://github.com/angular/angular/pull/54252) signals were introduced into the `@angular/core` API.
199+
Since signals introduced new methods and types to the core API, Cypress introduced a new test harness, `@cypress/angular-signals`.
200+
201+
Though basic signals were introduced in Angular `16`, this testing harness requires Angular `17.2` and above.
202+
203+
For the below examples, we'll be working with a very simple component called `TestComponent`, which looks something like shown below:
204+
205+
```typescript
206+
// app/components/test-component.component.ts
207+
import { Component, input, model } from '@angular/core'
208+
209+
@Component({
210+
selector: 'test-component',
211+
templateUrl: './test-component.component.html',
212+
standalone: true,
213+
})
214+
export class TestComponent {
215+
title = input.required<string>()
216+
count = model<number>(1)
217+
}
218+
```
219+
220+
```html
221+
<!-- app/components/test-component.component.html -->
222+
<p data-cy="test-component-title-display">{{ title() }}</p>
223+
<p data-cy="test-component-count-display">{{ count() }}</p>
224+
<button data-cy="test-component-count-incr" (click)="count.set(count() + 1)">
225+
Increase
226+
</button>
227+
<button data-cy="test-component-count-decr" (click)="count.set(count() - 1)">
228+
Decrease
229+
</button>
230+
```
231+
232+
#### Testing Signals
233+
234+
There are two ways to test signals within Cypress Component Testing:
235+
236+
1. [Inferred Generic Type](#Inferred-Generic-Type)
237+
2. [Writable Signal](#Writable-Signal)
238+
239+
##### Inferred Generic Type
240+
241+
In the example below, the `title` prop being passed into our `TestComponent` is a `string`. A `string` is the generic type of our `input()` signal we defined in our `TestComponent`.
242+
243+
```typescript
244+
let titleProp = 'Test Component'
245+
cy.mount(TestComponent, {
246+
componentProperties: {
247+
title: titleProp,
248+
},
249+
})
250+
251+
cy.get('[data-cy="test-component-title-display"]').should(
252+
'have.text',
253+
'Test Component'
254+
)
255+
```
256+
257+
:::info
258+
Under the hood, Cypress wraps the generic value in a writable `signal()` and merges it into the prop. In other words, the `@cypress/angular-signals` test harness in this example is really:
259+
260+
```typescript
261+
cy.mount(TestComponent, {
262+
componentProperties: {
263+
title: signal('Test Component'),
264+
},
265+
})
266+
```
267+
268+
:::
269+
270+
This works for any signal. Shown below is an example of testing a `model()` signal with a generic type `number` as seen in our `TestComponent`:
271+
272+
```ts
273+
cy.mount(TestComponent, {
274+
componentProperties: {
275+
title: 'Test Component',
276+
count: 3,
277+
},
278+
})
279+
280+
cy.get('[data-cy="test-component-count-display"]').should('have.text', '3')
281+
```
282+
283+
##### Writable Signal
284+
285+
Inferred generic types work very well for most test cases. However, they don't allow us to update the prop in the component after the prop is passed in. For this use case, we need to use a writable `signal()`.
286+
287+
This allows us to test our one-way data binding for our `input()` signals.
288+
289+
```typescript
290+
const myTitlePropAsSignal = signal('Test Component')
291+
cy.mount(TestComponent, {
292+
componentProperties: {
293+
title: myTitlePropAsSignal,
294+
},
295+
})
296+
297+
cy.get('[data-cy="test-component-title-display"]').should(
298+
'have.text',
299+
'Test Component'
300+
)
301+
cy.then(() => {
302+
// now set the input() through a signal to update the one-way binding
303+
myTitlePropAsSignal.set('FooBar')
304+
})
305+
306+
cy.get('[data-cy="test-component-title-display"]').should('have.text', 'FooBar')
307+
```
308+
309+
And our two-way data binding for our `model()` signals.
310+
311+
```typescript
312+
let count = signal(5)
313+
cy.mount(TestComponent, {
314+
componentProperties: {
315+
title: 'Test Component',
316+
count,
317+
},
318+
})
319+
320+
cy.then(() => {
321+
// now set the model() through a signal to update the binding in the component
322+
count.set(8)
323+
})
324+
325+
cy.get('[data-cy="test-component-count-display"]').should('have.text', '8')
326+
327+
// some action occurs that changes the count to 9 inside the component, which updates the binding in our test
328+
cy.get('[data-cy="test-component-count-incr"]').click()
329+
cy.get('[data-cy="test-component-count-display"]').should('have.text', '9')
330+
cy.then(() => {
331+
expect(count()).to.equal(9)
332+
})
333+
```
334+
335+
##### Change Spies
336+
337+
Cypress doesn't propagate changes via spy from `input()` signals.
338+
339+
For writable signals, such as `model()`s or `signal()`s, Cypress **will** propagate changes if an output spy is created with the prop's name suffixed with `Change`. In the example below,
340+
`countChange` will spy on changes to the `count` signal.
341+
342+
```typescript
343+
cy.mount(TestComponent, {
344+
componentProperties: {
345+
title: 'Test Component',
346+
count: 4,
347+
// @ts-expect-error
348+
countChange: createOutputSpy('countChange'),
349+
},
350+
})
351+
352+
// some action occurs that changes the count
353+
cy.get('[data-cy="test-component-count-incr"]').click()
354+
355+
cy.get('@countChange').should('have.been.called')
356+
```
357+
358+
These spies can automatically be created if `autoSpyOutputs: true` is configured. The suffix in this case will be `ChangeSpy`.
359+
196360
## Custom Mount Commands
197361

198362
### Customizing `cy.mount()`

docs/guides/references/changelog.mdx

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,30 @@
22
title: Changelog
33
---
44

5+
## 13.13.0
6+
7+
_Released 7/02/2024_
8+
9+
**Performance:**
10+
11+
- Improved performance of `experimentalSourceRewriting` option. Fixed in [#29540](https://github.com/cypress-io/cypress/pull/29540).
12+
13+
**Features:**
14+
15+
- Adds Signal support for Angular Component Testing versions 17.2 and up. Addresses [#29264](https://github.com/cypress-io/cypress/issues/29264).
16+
17+
**Bugfixes:**
18+
19+
- Fixed an issue where Chrome launch instances would not recreate the browser CRI client correctly after recovering from an unexpected browser closure. Fixes [#27657](https://github.com/cypress-io/cypress/issues/27657). Fixed in [#29663](https://github.com/cypress-io/cypress/pull/29663).
20+
- Fixed an issue where Firefox 129 (Firefox Nightly) would not launch with Cypress. Fixes [#29713](https://github.com/cypress-io/cypress/issues/29713). Fixed in [#29720](https://github.com/cypress-io/cypress/pull/29720).
21+
22+
**Dependency Updates:**
23+
24+
- Updated `launch-editor` from `2.3.0` to `2.8.0`. Addressed in [#29770](https://github.com/cypress-io/cypress/pull/29770).
25+
- Updated `memfs` from `3.4.12` to `3.5.3`. Addressed in [#29746](https://github.com/cypress-io/cypress/pull/29746).
26+
- Updated `tmp` from `0.2.1` to `0.2.3`. Addresses [#29693](https://github.com/cypress-io/cypress/issues/29693).
27+
- Updated `ws` from `5.2.3` to `5.2.4`. Addressed in [#29698](https://github.com/cypress-io/cypress/pull/29698).
28+
529
## 13.12.0
630

731
_Released 6/18/2024_

0 commit comments

Comments
 (0)