Site icon Ampersand Tutorials

Testing and Debugging Angular Apps (2026)

Quick answer: Angular testing runs on Vitest, the CLI’s default test runner, with jsdom providing a DOM in Node. Write tests beside the code in .spec.ts files, run them with ng test, and use TestBed to configure and create components and services. Debug with the browser DevTools, Angular DevTools, and breakpoints in the sources panel.

What changed in Angular testing

For years Angular tests ran on Karma and Jasmine in a real browser. New projects now default to Vitest running on jsdom, which starts faster and integrates with the modern toolchain. Karma is still supported if you select it — ng new my-app --test-runner=karma — so you can keep the old setup, but Vitest is where new work happens.

Testing a component

TestBed configures a test module and creates the component. Standalone components are configured the same way they are used: pass them to imports.

import { TestBed } from '@angular/core/testing';
import { CounterComponent } from './counter.component';

describe('CounterComponent', () => {
  beforeEach(async () => {
    await TestBed.configureTestingModule({
      imports: [CounterComponent],
    }).compileComponents();
  });

  it('increments the count when clicked', () => {
    const fixture = TestBed.createComponent(CounterComponent);
    const el = fixture.nativeElement as HTMLElement;
    fixture.detectChanges();

    el.querySelector('button')!.click();
    fixture.detectChanges();

    expect(el.textContent).toContain('Count: 1');
  });
});

Two calls do the work: createComponent builds the component and its template, and detectChanges runs change detection so the DOM reflects the current state. Click the real element, run change detection again, and assert on the rendered text — that is a component test in full.

Testing a service

Services are plain classes, so most need no DOM and almost no setup. When a service depends on HttpClient, provide a testing backend so no real request leaves the machine.

import { TestBed } from '@angular/core/testing';
import { provideHttpClient } from '@angular/common/http';
import { provideHttpClientTesting, HttpTestingController } from '@angular/common/http/testing';
import { ProductService } from './product.service';

describe('ProductService', () => {
  let service: ProductService;
  let httpMock: HttpTestingController;

  beforeEach(() => {
    TestBed.configureTestingModule({
      providers: [provideHttpClient(), provideHttpClientTesting()],
    });
    service = TestBed.inject(ProductService);
    httpMock = TestBed.inject(HttpTestingController);
  });

  afterEach(() => httpMock.verify());

  it('fetches products', () => {
    let result: unknown;
    service.get(1).subscribe(p => (result = p));

    const req = httpMock.expectOne('/api/products/1');
    expect(req.request.method).toBe('GET');
    req.flush({ id: 1, name: 'Widget', price: 9.99 });

    expect(result).toEqual({ id: 1, name: 'Widget', price: 9.99 });
  });
});

The testing backend records every request so you can assert on the URL and method, then flush a fake response.

httpMock.verify() in afterEach fails the test if a request was left outstanding — a quick way to catch code that forgets to subscribe.

Debugging Angular testing failures in the browser

An Angular testing habit worth building

Test the logic you are most afraid to change: a price calculation, a permission check, a state transition. Those tests pay for themselves every refactor. Do not chase coverage for its own sake — a handful of meaningful tests beats a hundred assertions on generated code. See performance and deployment next, where tests guard the build you ship.

Want to learn testing on a real Angular codebase rather than toy examples? Ampersand Academy teaches Angular one-to-one.

Frequently asked questions

What test runner does Angular use now?

New Angular projects default to Vitest, running on jsdom for a fast Node-based test loop. Karma and Jasmine are still supported if you select them when creating the project.

What is TestBed in Angular testing?

TestBed configures a test module and creates the components and services under test. Standalone components are passed to its imports array, the same way the app uses them.

How do I test a service that calls an API?

Provide provideHttpClient with provideHttpClientTesting, inject HttpTestingController, and assert on the recorded request before flushing a fake response.

Why does my component test show no DOM changes?

You probably forgot to call fixture.detectChanges() after changing state. The test DOM only updates when change detection runs.

What is Angular DevTools used for?

It shows the component tree, each component’s inputs and the change-detection activity, which makes it easy to see what re-rendered and why.

Exit mobile version