Home > other >  Angular unit testing "SPEC HAS NO EXPECTATIONS" and "error: Timeout"
Angular unit testing "SPEC HAS NO EXPECTATIONS" and "error: Timeout"

Time:12-11

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.

  • Related