9

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.

2
  • can't you just put the url in the variable and pass it to expectOne() in both tests? Not sure what is the problem you're trying to solve here, as you have one test for url an another for data. Commented Nov 13, 2018 at 11:02
  • 1
    @Mac_W: I agree that your suggestion makes the tests work. And, for a small number of tests (as in my example) it's fine. But, consider having many tests. In general, a test should not verify too much. When over-specified, one change will cause many tests to file. Better that the minimum number of tests fail for any specific change. I don't want every test to verify the URL, because changing the URL would cause every test to fail, but the tests that verify the logic should not fail -- should not depend on the URL. Commented Mar 4, 2019 at 22:10

1 Answer 1

13

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); 
Sign up to request clarification or add additional context in comments.

2 Comments

Thanks, () => true is a much cleaner solution and one can avoid having all kind of URLs in the spec file.
Gives out error now Error: Expected one matching request for criteria "Match by function: ", found none.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.