0
0
Angularframework~5 mins

Testing forms and user interactions in Angular

Choose your learning style9 modes available
Introduction

Testing forms and user interactions helps make sure your app works right when people use it. It catches mistakes early so users have a smooth experience.

You want to check if a form accepts and validates user input correctly.
You want to test if buttons and inputs respond properly when clicked or typed into.
You want to make sure error messages show up when users enter wrong data.
You want to verify that submitting a form triggers the right actions.
You want to catch bugs before users find them by simulating real user actions.
Syntax
Angular
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { ReactiveFormsModule } from '@angular/forms';
import { By } from '@angular/platform-browser';

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

it('should update form value on input', () => {
  const fixture = TestBed.createComponent(YourFormComponent);
  fixture.detectChanges();
  const input = fixture.debugElement.query(By.css('input[name="yourInput"]')).nativeElement;
  input.value = 'test';
  input.dispatchEvent(new Event('input'));
  fixture.detectChanges();
  expect(fixture.componentInstance.form.get('yourInput')?.value).toBe('test');
});

Use TestBed to set up your test environment with needed modules and components.

Use fixture.debugElement.query(By.css()) to find elements and simulate user actions like typing or clicking.

Examples
This test checks that the form is invalid when no data is entered.
Angular
it('should mark form as invalid when empty', () => {
  const fixture = TestBed.createComponent(YourFormComponent);
  fixture.detectChanges();
  expect(fixture.componentInstance.form.valid).toBeFalse();
});
This test simulates typing a wrong email and checks if an error message appears.
Angular
it('should show error message on invalid input', () => {
  const fixture = TestBed.createComponent(YourFormComponent);
  fixture.detectChanges();
  const input = fixture.debugElement.query(By.css('input[name="email"]')).nativeElement;
  input.value = 'wrong';
  input.dispatchEvent(new Event('input'));
  fixture.detectChanges();
  const error = fixture.debugElement.query(By.css('.error-message'));
  expect(error).toBeTruthy();
});
This test checks if the form's submit method runs when the form is submitted.
Angular
it('should call submit method on form submit', () => {
  const fixture = TestBed.createComponent(YourFormComponent);
  fixture.detectChanges();
  spyOn(fixture.componentInstance, 'onSubmit');
  const form = fixture.debugElement.query(By.css('form'));
  form.triggerEventHandler('submit', null);
  expect(fixture.componentInstance.onSubmit).toHaveBeenCalled();
});
Sample Program

This example shows a simple Angular form with one required input. The tests check if the form is invalid when empty, updates value on typing, shows error messages, and calls the submit method when submitted.

Angular
import { Component } from '@angular/core';
import { FormBuilder, Validators } from '@angular/forms';

@Component({
  selector: 'app-simple-form',
  template: `
    <form [formGroup]="form" (ngSubmit)="onSubmit()">
      <label for="name">Name:</label>
      <input id="name" formControlName="name" name="name" />
      <div *ngIf="form.get('name')?.invalid && form.get('name')?.touched" class="error-message">
        Name is required.
      </div>
      <button type="submit" [disabled]="form.invalid">Submit</button>
    </form>
  `
})
export class SimpleFormComponent {
  form = this.fb.group({
    name: ['', Validators.required]
  });

  constructor(private fb: FormBuilder) {}

  onSubmit() {
    if (this.form.valid) {
      console.log('Form submitted with:', this.form.value);
    }
  }
}

// Test file
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { ReactiveFormsModule } from '@angular/forms';
import { By } from '@angular/platform-browser';

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

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

    fixture = TestBed.createComponent(SimpleFormComponent);
    fixture.detectChanges();
  });

  it('should mark form invalid when empty', () => {
    expect(fixture.componentInstance.form.valid).toBeFalse();
  });

  it('should update form value on input', () => {
    const input = fixture.debugElement.query(By.css('input[name="name"]')).nativeElement;
    input.value = 'Alice';
    input.dispatchEvent(new Event('input'));
    fixture.detectChanges();
    expect(fixture.componentInstance.form.get('name')?.value).toBe('Alice');
  });

  it('should show error message when input touched and empty', () => {
    const input = fixture.debugElement.query(By.css('input[name="name"]')).nativeElement;
    input.dispatchEvent(new Event('blur'));
    fixture.detectChanges();
    const error = fixture.debugElement.query(By.css('.error-message'));
    expect(error).toBeTruthy();
  });

  it('should call onSubmit when form submitted', () => {
    spyOn(fixture.componentInstance, 'onSubmit');
    const form = fixture.debugElement.query(By.css('form'));
    form.triggerEventHandler('submit', null);
    expect(fixture.componentInstance.onSubmit).toHaveBeenCalled();
  });
});
OutputSuccess
Important Notes

Always import ReactiveFormsModule or FormsModule in your test setup if your component uses forms.

Use fixture.detectChanges() after simulating user events to update the view and component state.

Use spyOn to check if component methods are called during interactions.

Summary

Testing forms means simulating user typing, clicking, and submitting to check app behavior.

Use Angular's testing utilities like TestBed and By.css to find elements and trigger events.

Check form validity, error messages, and method calls to ensure your form works well.