Les nouveautés d'Angular 19 en 4 minutes

Angular 19 vient de sortir, et il y a beaucoup de nouveautés intéressantes : hydratation incrémentale, linkedSignal, l'API des ressources, et plein d'autres choses. Venez découvrir tout ça en moins de 4 minutes !

Skip to content

Vous souhaitez recevoir de l'aide sur ce sujet ? rejoignez la communauté Angular.fr sur Discord.

Comment tester un formulaire ngModel ?

Voici un composant:

ts
import { Component } from '@angular/core';
import { FormsModule } from '@angular/forms';

@Component({
  selector: 'app-signup',
  imports: [FormsModule],
  standalone: true,
  template: `
    <form action="#">
        <div>
            <label for="email" class="label">Votre email</label>
            <input type="email" name="email" [(ngModel)]="email" id="email" class="input" placeholder="[email protected]" required="">
        </div>
        <button type="submit" class="button">Créer le compte</button>
    </form>
  `
})
export class SignupComponent {
  email: string = ''
}

Le test unitaire serait alors le suivant:

ts
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { FormsModule } from '@angular/forms';
import { SignupComponent } from './signup.component';

describe('MonComposantComponent', () => {
    let component: SignupComponent;
    let fixture: ComponentFixture<SignupComponent>;

    beforeEach(async () => {
        await TestBed.configureTestingModule({
            imports: [SignupComponent, FormsModule]
        }).compileComponents();
    });

    beforeEach(() => {
        fixture = TestBed.createComponent(SignupComponent);
        component = fixture.componentInstance;
        fixture.detectChanges();
    });

    // test la propriété email après avoir rempli le champ email
    it('should have email property', async () => {
        const emailInput = fixture.nativeElement.querySelector('input[type="email"]');
        emailInput.value = '[email protected]'
        emailInput.dispatchEvent(new Event('input'));
        await fixture.whenStable()
        fixture.detectChanges()
        expect(component.email).toBe(emailInput.value)
    })
});
  1. emailInput.dispatchEvent(new Event('input')) simule un événement "input" sur l'élément emailInput. Cela permet de déclencher toutes les mécaniques liées à la modification de la valeur d'un champ dans le formulaire, telles que la mise à jour de la propriété email liée à ce champ via [(ngModel)]="email".

  2. await fixture.whenStable() attend que tous les observables liés à l'application soient résolus avant de continuer à exécuter le reste du code. Cela garantit que toutes les mises à jour liées à la modification de la valeur du champ email ont été effectuées avant de tester la valeur de la propriété email.

TIP

ngModelest asynchrone

fixture.detectChanges() déclenche une nouvelle itération de détection de modifications dans l'application. Cela permet de prendre en compte les modifications apportées à la propriété email lors de la simulation de l'événement "input" sur l'élément emailInput.

Tester

Le composant:

ts
import { Component } from '@angular/core';
import { ReactiveFormsModule, FormControl, FormGroup, Validators } from '@angular/forms';

@Component({
  selector: 'app-signup',
  standalone: true,
  imports: [ReactiveFormsModule],
  template: `
    <form [formGroup]="signupForm" (ngSubmit)="onSubmit()">
        <div>
            <label for="email" class="label">Votre email</label>
            <input type="email" name="email" formControlName="email" id="email" class="input" placeholder="[email protected]" required="">
        </div>
        <button type="submit" class="button">Créer le compte</button>
    </form>
  `
})
export class SignupComponent {
  signupForm = new FormGroup({
    email: new FormControl('', [Validators.required, Validators.email])
  });

  onSubmit() {
    console.log(this.signupForm.value);
  }
}

et le test unitaire:

ts
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { SignupComponent } from './signup.component';

describe('SignupComponent', () => {
    let component: SignupComponent;
    let fixture: ComponentFixture<SignupComponent>;

    beforeEach(async () => {
        await TestBed.configureTestingModule({
            imports: [SignupComponent, FormsModule, ReactiveFormsModule]
        }).compileComponents();
    });

    beforeEach(() => {
        fixture = TestBed.createComponent(SignupComponent);
        component = fixture.componentInstance;
        fixture.detectChanges();
    });

    it('should create', () => {
        expect(component).toBeTruthy();
    });

    it('form should be invalid', () => {
        expect(component.signupForm.valid).toBeFalsy();
    });

    it('email field validity', () => {
        let email = component.signupForm.controls['email'];
        expect(email.valid).toBeFalsy();

        email.setValue("test");
        expect(email.hasError('email')).toBeTruthy();

        email.setValue("[email protected]");
        expect(email.valid).toBeTruthy();
    });
});

Chaque mois, recevez en avant-première notre newsletter avec les dernières actualités, tutoriels, astuces et ressources Angular directement par email !