I'm trying to write a test for my post function. This is an Angular app and I'm using Karma/Jasmine to test.
This was my test:
it(`should post data`, ()=>{
const service: ApiService = TestBed.get(ApiService);
service.sendMessage(data).subscribe(values =>{
expect(values).toBe('observable value');
});
});
Both methods "pass" the test, but have the "SPEC HAS NO EXPECTATIONS" message. The fix I have found for this is to try to get a promise from it. I tried two ways:
Adding "done()"
it(`should post data`, (done:any)=>{
const service: ApiService = TestBed.get(ApiService);
service.sendMessage(data).subscribe(values =>{
expect(values).toBe('observable value');
done();
});
});
or rewriting the whole thing to this:
it('should post data', inject([ApiService], async (service: ApiService) => {
const tada = await service.sendMessage(data).toPromise();
expect(tada).toBe('observable data');
}));
These call the test to fail due to timing out.(Error: Timeout - Async function did not complete within 5000ms (set by jasmine.DEFAULT_TIMEOUT_INTERVAL)) So, to fix that I tried increasing the timeout. I used
jasmine.DEFAULT_TIMEOUT_INTERVAL = 150000;
but even after longer periods, it would still timeout. This makes me think that's not the right solution, but I couldn't find answers beyond what I've tried. I have also tried moving parts around, like putting the expect() outside of the subscribe, etc.
EDIT: HERE IS THE WHOLE UNIT TEST FILE
import { TestBed } from '@angular/core/testing';
import { ApiService } from './api.service';
import { HttpClientTestingModule } from '@angular/common/http/testing';
describe('ApiService', () => {
let service: ApiService;
beforeEach(() => {
TestBed.configureTestingModule({
imports: [HttpClientTestingModule],
providers: [ApiService]
});
// service = TestBed.inject(ApiService);
});
it('should be created', () => {
const service: ApiService = TestBed.get(ApiService);
expect(service).toBeTruthy();
});
let data = {
name: "fdsgs",
sex: "gfjhghj",
address:"ghmfgj",
county: "ghjdgfhj",
contactMethod: ["dfghjsfdghd", "helloworld"],
daysAvailable: ["dfghfdgh", "heloo world"],
timesAvailable: ["sdfghfgh", "hello world"],
aboutPerson: ["stfghfdghd", "sadf"],
aboutChildren: ["jdfhjtd", "awert"],
questions: "gfhdfgh",
howTheyHeardOfUs: ["dfghasg", "fasfg"]
}
it(`should post data`, (done: DoneFn)=>{
const service: ApiService = TestBed.get(ApiService);
service.sendMessage(data).subscribe(values =>{
expect(values).toBe('observable value');
done();
});
});
AND HERE IS THE API SERVICE FILE:
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { map } from 'rxjs/operators';
@Injectable({
providedIn: 'root'
})
export class ApiService {
constructor(private http: HttpClient) { }
sendMessage(data:any){
return this.http.post<any>("URL", data)
.pipe(map((res:any)=>{
return res;
}));
}
}
CodePudding user response:
I would not touch the jasmine.DEFAULT_TIMEOUT_INTERVAL
property because I think the default 5 seconds is plenty for a unit test.
This approach is good:
it(`should post data`, (done: DoneFn)=>{
const service: ApiService = TestBed.get(ApiService);
// !! service.sendMessage is never emitting and therefore never going
const httpTestingController = TestBed.get(HttpTestingController);
// inside of the subscribe block !!
service.sendMessage(data).subscribe(values =>{
expect(values).toEqual({});
done();
});
// expect an http call
const req = httpTestingController.expectOne(request => request.method === 'POST');
// flush an empty object for it
req.flush({});
});
The issue is written as a comment in the unit test file.
If you can show me the service and the whole unit test file, I can possibly help. The issue is that the observable being returned from sendMessage
is never emitting.
Also get rid of this in the service:
.pipe(map((res:any)=>{
return res;
})
It's doing nothing.