In-depth Guides
HTTP Client

Test requests

As for any external dependency, you must mock the HTTP backend so your tests can simulate interaction with a remote server. The @angular/common/http/testing library provides tools to capture requests made by the application, make assertions about them, and mock the responses to emulate your backend's behavior.

The testing library is designed for a pattern in which the app executes code and makes requests first. The test then expects that certain requests have or have not been made, performs assertions against those requests, and finally provides responses by "flushing" each expected request.

At the end, tests can verify that the app made no unexpected requests.

Setup for testing

To begin testing usage of HttpClient, configure TestBed and include provideHttpClient() and provideHttpClientTesting in your test's setup. This configures HttpClient to use a test backend instead of the real network. It also provides HttpTestingController, which you'll use to interact with the test backend, set expectations about which requests have been made, and flush responses to those requests. HttpTestingController can be injected from TestBed once configured.

providers: [
// ... other test providers
const httpTesting = TestBed.inject(HttpTestingController);

Now when your tests make requests, they will hit the testing backend instead of the normal one. You can use httpTesting to make assertions about those requests.

Expecting and answering requests

For example, you can write a test that expects a GET request to occur and provides a mock response:

providers: [
const httpTesting = TestBed.inject(HttpTestingController);
// Load `ConfigService` and request the current configuration.
const service = TestBed.inject(ConfigService);
const config$ = this.configService.getConfig<Config>();
// `firstValueFrom` subscribes to the `Observable`, which makes the HTTP request,
// and creates a `Promise` of the response.
const configPromise = firstValueFrom(config$);
// At this point, the request is pending, and we can assert it was made
// via the `HttpTestingController`:
const req = httpTesting.expectOne('/api/config', 'Request to load the configuration');
// We can assert various properties of the request if desired.
// Flushing the request causes it to complete, delivering the result.
// We can then assert that the response was successfully delivered by the `ConfigService`:
expect(await configPromise).toEqual(DEFAULT_CONFIG);
// Finally, we can assert that no other requests were made.

Note: expectOne will fail if the test has made more than one request which matches the given criteria.

As an alternative to asserting on req.method, you could instead use an expanded form of expectOne to also match the request method:

const req = httpTesting.expectOne({
method: 'GET',
url: '/api/config',
}, 'Request to load the configuration');

HELPFUL: The expectation APIs match against the full URL of requests, including any query parameters.

The last step, verifying that no requests remain outstanding, is common enough for you to move it into an afterEach() step:

afterEach(() => {
// Verify that none of the tests make any extra HTTP requests.

Handling more than one request at once

If you need to respond to duplicate requests in your test, use the match() API instead of expectOne(). It takes the same arguments but returns an array of matching requests. Once returned, these requests are removed from future matching and you are responsible for flushing and verifying them.

const allGetRequests = httpTesting.match({method: 'GET'});
foreach (const req of allGetRequests) {
// Handle responding to each request.

Advanced matching

All matching functions accept a predicate function for custom matching logic:

// Look for one request that has a request body.
const requestsWithBody = httpTesting.expectOne(req => req.body !== null);

The expectNone function asserts that no requests match the given criteria.

// Assert that no mutation requests have been issued.
httpTesting.expectNone(req => req.method !== 'GET');

Testing error handling

You should test your app's responses when HTTP requests fail.

Backend errors

To test handling of backend errors (when the server returns a non-successful status code), flush requests with an error response that emulates what your backend would return when a request fails.

const req = httpTesting.expectOne('/api/config');
req.flush('Failed!', {status: 500, statusText: 'Internal Server Error'});
// Assert that the application successfully handled the backend error.

Network errors

Requests can also fail due to network errors, which surface as ProgressEvent errors. These can be delivered with the error() method:

const req = httpTesting.expectOne('/api/config');
req.error(new ProgressEvent('network error!'));
// Assert that the application successfully handled the network error.