I'm working on a Angular 5 Project, it's nothing serious. Though I've been out of the Angular2+ business since early 2.1/2.2.
So I've got this Service which calls a public API, however my test keeps failing with: Error: Expected one matching request for criteria "Match URL: http://api.icndb.com/jokes/random/10", found none.
code:
fact.service.spec.ts
import {HttpClientTestingModule, HttpTestingController} from "@angular/common/http/testing";
import {TestBed, inject} from "@angular/core/testing";
import {FactService} from "./fact.service";
import {Fact} from "../models/fact";
import {FactHttpResponse} from "../models/factHttpResponse";
describe("FactService", () => {
let factService: FactService;
let httpMock: HttpTestingController;
beforeEach(() => {
TestBed.configureTestingModule({
imports: [HttpClientTestingModule],
providers: [FactService],
});
httpMock = TestBed.get(HttpTestingController);
factService = TestBed.get(FactService);
});
// TODO: Something is going wrong with this test get some help online
it("Should be able to retrieve Facts in subscription when calling loadFacts", (done) => {
const factList: Fact[] = [
{id: 1, joke: "a"},
{id: 2, joke: "a"},
];
const factResponse: FactHttpResponse = { value: factList};
factService.subscribe(val => {
expect(val).toEqual(factList);
done();
});
const mockRequest = httpMock
.expectOne(factService.CHUCK_NORRIS_API.replace("{count}", "10"));
expect(mockRequest.request.method).toEqual('GET');
factService.loadFacts();
mockRequest.flush(factResponse);
});
afterEach(inject([HttpTestingController], (httpMock: HttpTestingController) => {
httpMock.verify();
}));
});
fact.service.ts
import { HttpClient } from "@angular/common/http";
import { Injectable } from "@angular/core";
import { Subject } from "rxjs/Subject";
import {Fact} from "../models/fact";
import {FactHttpResponse} from "../models/factHttpResponse";
@Injectable()
export class FactService {
// public for testing purposes
public readonly CHUCK_NORRIS_API = "http://api.icndb.com/jokes/random/{count}";
private factSubject = new Subject();
private facts: Fact[] = [];
private favorites: Fact[] = [];
constructor(private http: HttpClient) { }
public subscribe(callback: (value: Fact[]) => void) {
return this.factSubject.subscribe(callback);
}
public loadFacts(count = 10) {
this.http.get<FactHttpResponse>(this.CHUCK_NORRIS_API.replace("{count}", count.toString()))
.subscribe(data => {
if (data.value) {
this.facts = data.value
.map(f => {
f.favorite = !!this.favorites.find(fav => fav.id === f.id);
return f;
});
this.factSubject.next(this.facts);
}
});
}
}
The code actually works, but I can't seem to test it :-(. If I remove the verifyOne it actually complains about an open request to the exact same url mentioned in error.
Since it is your method factService.loadFacts()
that is generating the HTTP request, you have the last three pieces of your test out of order. It should be (with comments):
describe(..., () => {
it(..., () => {
...
// queue up the http request in the mockHttp request queue
factService.loadFacts();
// verify that there is now one (and only one) request queued up
const mockRequest = httpMock
.expectOne(factService.CHUCK_NORRIS_API.replace("{count}", "10"));
expect(mockRequest.request.method).toEqual('GET');
// satisfy the pending request in the mockHttp request queue
mockRequest.flush(factResponse);
});
// Bonus tip: you already have mockHttp in the describe() scope. Simplify:
afterEach(() => {
// verify there are no unsatisfied requests in the mockHttp queue
httpMock.verify();
});
});