steve
steve

Reputation: 1169

How to match any URL with HttpTestingController.expectOne?

expectOne() requires a URL string to match the request that the code under test makes via HttpClient. But, I want separate tests for verifying the request URL and verifying the result data. I want one test to verify the request URL -- ignoring the result data -- which I can write. And I want another test to verify the result data -- regardless of the URL -- which I cannot write since expectOne requires the URL parameter to match.

I searched for a way to tell expectOne to ignore the URL or to match any URL, but found nothing. I did try passing '*', but that didn't work.

Is there a way to get HttpTestingController to match any URL?

import { TestBed } from '@angular/core/testing';
import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing';

import { OperationsLogService } from './operations-log.service';
import { Severity } from './severity.enum';

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

    beforeEach(() => {
        TestBed.configureTestingModule({
            imports: [
                HttpClientTestingModule
            ],
            providers: [
                OperationsLogService
            ]
        });

        service = TestBed.get(OperationsLogService);
        httpMock = TestBed.get(HttpTestingController);
    });
    it('requests by page and max-count', (done) => {
        service
            .getEntries(3, 5)
            .subscribe((res: any) => {
                done();
            });
        const request = httpMock.expectOne('api/operations-log/oplog.json?page=3&max-count=5');
        request.flush({});
        httpMock.verify();
    });
    it('provides entries', (done) => {
        const entries = [
            {
                severity: Severity.Informational,
                whenLogged: Date.now(),
                code: 123,
                message: 'msg'
            }
        ];
        service
            .getEntries(3, 5)
            .subscribe((res: any) => {
                expect(res).toEqual(entries);
                done();
            });
        // don't want to specify the URL here
        const request = httpMock.expectOne('api/operations-log/oplog.json?page=3&max-count=5');
        request.flush(entries);
        httpMock.verify();
    });
});

Why I want this capability: Tests should be independent of each other. One issue/change should cause as few tests to fail as possible. If the URL test fails, then I don't want the other test (provides entries) to fail. One suggested that I store the URL in a common variable. That does eliminate code duplication, but the tests are still weak. If one fails (due to the URL changing), they both will fail.

Upvotes: 9

Views: 11574

Answers (1)

Dick Porter
Dick Porter

Reputation: 171

There is an overload to expectOne() that will do what you need (see the documentation at https://angular.io/api/common/http/testing/HttpTestingController#expectone):

abstract expectOne(matchFn: ((req: HttpRequest<any>) => boolean), description?: string): TestRequest

So for your test to match any URL, just return true for every call to the match predicate:

const request = httpMock.expectOne(() => true);
request.flush(entries);

Upvotes: 13

Related Questions