Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
548 views
in Technique[技术] by (71.8m points)

javascript - Unit test that sequence of calls are made in order when the method called is the same but with different arguments (Jasmine & Angular)

I have an Angular service with a method that makes a call to a method in an httpService that returns an observable. Once that method returns success, a series of parallel calls are made to the same method of the httpService but with different params to save some images.

I am trying to unit test that the calls are made in the right order and with the right params. When I try to use spies and .toHaveBeenCalled() I only get the 1st call recognised by Jasmine.

I am assuming it has something to do with timing but I am lost and can't find any examples of this use case. Any guidance will be appreciated.

Edit: the code works 100%, my issue is just how to write unit tests for the sequence calls.

// Service

// HttpS is a custom service that makes HTTP requests
constructor(private httpS: HttpS) {
}

save(params: {images: any[]}): Observable<any> {
   return this.saveEntry(params);
}

private saveEntry(params: {images: any[]}): Observable<any> {
  return this.httpS.put('url', {something: 'something'}).pipe(
    // once this request is successful, make parallel requests
    concatMap(() => {
      const reqs = [];
      params.images.forEach(image => {
        reqs.push(this.saveImage({ image }));
      });
    
      return forkJoin(reqs);
    })
  );
}

private saveImage(data: {image: any}): Observable<any> {
  return this.httpS.put('url',{imgData: data.image});
}

// Test

describe('save', () => {

  it('should make a PUT request with something, then on success multiple parallel PUT requests with imgData', () => {

   spyOn(httpService, 'put').and.callFake(() => cold('-a|', { a: {} }));
   service.save(data).pipe(take(1)).subscribe();
   
   // The mock data I'm passing has 3 images so it results in 1 call first, then 3 in parallel, 1 for each image, but this test says it has been called just once.
   expect(httpS.put).toHaveBeenCalledTimes(4);

   // Trying .toHaveBeenCalledWith() but obviously that fails too

  })
})

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

I think it has to do with subscribe running at a later point in time than your assertions (due to asynchronous nature).

Try this:

describe('save', () => {

  it('should make a PUT request with something, then on success multiple parallel PUT requests with imgData', (done) => { // add done to tell Jasmine when you're done with unit test

   spyOn(httpService, 'put').and.callFake(() => cold('-a|', { a: {} }));
   service.save(data).pipe(take(1)).subscribe(response => {
     expect(httpS.put).toHaveBeenCalledTimes(4); // make assertion once the response comes back
     done(); // call done to let Jasmine know you're done with the test
   });
  
  })
})

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...