cypress-io / cypress

Fast, easy and reliable testing for anything that runs in a browser.
https://cypress.io
MIT License
46.68k stars 3.16k forks source link

Html code block not displayed inside defer block in Angular v17 #28306

Closed MattiaMalandrone closed 8 months ago

MattiaMalandrone commented 10 months ago

Current behavior

Trying testing new angular control flow the html inside a defer block is not displayed when running test in component testing inside cypress

describe('AppComponent.cy.ts', () => {
  it('should mount', () => {
    cy.mount(AppComponent)
  })
})

app.component.html

outside defer

@defer() {
  inside defer
}

@defer(on timer(500ms)) {
  inside defer with condition
}

Only string "outside defer" is displayed

Desired behavior

I expect that html code inside a defer block will be displayed

Test code to reproduce

https://github.com/MattiaMalandrone/cypress-defer-block-angular17

launching npx cypress open -> component testing -> chrome -> AppComponent.cy.ts

Cypress Version

13.5.0

Node version

18.18.2

Operating System

windows 10

Debug Logs

No response

Other

No response

kanidjar commented 10 months ago

Same issue here. Critical bug on my side since i cannot test my components.

MattiaMalandrone commented 10 months ago

any news about it?

felixgeissler commented 10 months ago

We are experiencing the same behaviour in our component tests running v13.5.1

psrebrny commented 8 months ago

I confirm this behaviour in cypress v13.6.1 when can we expect to handle defer in component testing?

psrebrny commented 8 months ago

I have written a workaround for this issue

Service:

import { Injectable, signal, Signal } from '@angular/core';

@Injectable({
    providedIn: 'root',
})
export class DeferrableStateService {
    defer: Signal<boolean> = signal(true);
    constructor() {}
}

Component:

import { ChangeDetectionStrategy, Component, Input } from '@angular/core';
import { DeferrableStateService } from '../../services/deferrable-state.service';
import { NgTemplateOutlet } from '@angular/common';

@Component({
    selector: 'app-deferrer',
    standalone: true,
    imports: [NgTemplateOutlet],
    templateUrl: './deferrer.component.html',
    changeDetection: ChangeDetectionStrategy.OnPush,
})
export class DeferrerComponent {
    isdeferred = this.deferrableStateService.defer;
    constructor(private deferrableStateService: DeferrableStateService) {}
}

and HTML for that component:

<ng-template #content>
    <ng-content></ng-content>
</ng-template>

@if (isdeferred()) { @defer (on viewport) {
<ng-container *ngTemplateOutlet="content"></ng-container>
} @placeholder () {
 // your placeholder
} } @else {
<ng-container *ngTemplateOutlet="content"></ng-container>
}

then in component test add configuration

cy.mount(Component, {
  imports: [
      // YourComponents and/or modules
  ],
  providers: [
      {
          provide: DeferrableStateService,
          useValue: {
              defer: signal(false),
          },
      },
  ],
  declarations: [],
  componentProperties: {
      // your properties
  },

});
jordanpowell88 commented 8 months ago

Hey @MattiaMalandrone thanks for opening this issue. I went ahead and created an example repo and blog article to highlight how you can do this. https://dev.to/angular/testing-defer-blocks-in-angular-with-cypress-21j8

Hopefully this helps!

jordanpowell88 commented 8 months ago

I'm going to close this for now but we may create something more "official" in the future

MattiaMalandrone commented 8 months ago

Hey @MattiaMalandrone thanks for opening this issue. I went ahead and created an example repo and blog article to highlight how you can do this. https://dev.to/angular/testing-defer-blocks-in-angular-with-cypress-21j8

Hopefully this helps!

Thanks Jordan!!!!