Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 714
steve Avatar asked Nov 13 '18 10:11

steve


People also ask

What is HttpTestingController?

HttpTestingController. Controller to be injected into tests, that allows for mocking and flushing of requests. Angular's new HttpClient has a testing module, HttpClientTestingModule, that makes it easy to unit test HTTP requests.

What is HttpClientTestingModule?

Using the HttpClientTestingModule and HttpTestingController provided by Angular makes mocking out results and testing http requests simple by providing many useful methods for checking http requests and providing mock responses for each request.

What is flush in angular testing?

From the angular documentation, it says for tick: Simulates the asynchronous passage of time for the timers in the fakeAsync zone. and for flush: Simulates the asynchronous passage of time for the timers in the fakeAsync zone by draining the macrotask queue until it is empty.


1 Answers

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);
like image 104
Dick Porter Avatar answered Sep 21 '22 16:09

Dick Porter