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.
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.
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.
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.
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);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With