Tips for testing nested subscribe methods in Angular unit testing

FunctionToTest() {
  this.someService.method1().subscribe((response) => {
   if (response.Success) {
     this.someService.method2().subscribe((res) => {
        this.anotherService.method3();
      })
    }
  });
}

Consider the following scenario.

Key points to test:

  1. someService.method1() should be called.
  2. If response.Success is true, then verify if someService.method2() was invoked.
  3. Ensure that anotherService.method3() was triggered when someService.method2() returned a value.

Testing the first point is straightforward.

let spy = spyOn(someService, 'method1');
expect(spy).toHaveBeenCalled();

But how about testing the second and third points?

 let spy= spyOn(someService, 'method1').and.returnValue({subscribe: () => {success:true}});
subject.FunctionToTest();

Is this approach correct?

Answer №1

After some investigation, I have discovered that the key method I need is callFake

it('should test within the subscribe block', () => {
    let spy = spyOn(serviceA, 'methodA1').and.callFake(() => {
      return of({ success: true });
    });
    let spy2 = spyOn(serviceA, 'methodA2').and.callFake(() => {
      return of({ success: true });
    });
    let spy3 = spyOn(serviceB, 'methodB1').and.returnValue(of({ success: true }));
     subject.MethodToBeTested();
    expect(spy3).toHaveBeenCalled();
  });

I've come to realize that using returnValue does not actually trigger execution inside the subscriber, whereas callFake accomplishes this by providing the necessary data.

Answer №2

A more efficient approach would be to avoid using a nested subscribe.

Consider the following alternative solution:

let $obs1 = this.serviceA.methodA1().pipe(share());
let $obs2 = $obs1.pipe(switchMap(x => this.serviceA.methodA2()));

$obs1.subscribe(logic1 here...);
$obs2.subscribe(logic2 here...);

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Uploading files with Angular 4 and Rails 5 using paperclip

I am currently engaged in a project that involves an Angular 4 frontend and a Rails 5 API backend. I'm facing an issue with uploading videos using paperclip, as they are not getting saved to the database for some unknown reason. Despite all the parame ...

Tips for ensuring a program pauses until an observable is completed within an Angular application

Currently, I am working on a project using Angular. I encountered a situation where a call to the backend is made using an observable to fetch products. Below is an example of how the code appears: getProducts () : Product[] { this.http.get<[]>(this ...

Can you explain the distinction between these two Redux reducer scenarios?

While looking at someone else's code for a reducer, I noticed this snippet: export default function reducer(state, action) { switch(action.type) { case 'ADD_TODO': Object.assign({}, state, { ...

Addressing ESLint and TypeScript Issues in Vue.js with Pinia: A comprehensive guide

Experiencing difficulties with Vue.js + Pinia and need assistance to resolve these issues. Error: 'state:' is defined but never used. Here is the snippet of code located in @/stores/user.ts. import { defineStore } from 'pinia' export ...

Encountering an 'undefined' response when passing an array in Express's res.render method

After my initial attempt at creating a basic node app, I discovered that the scraper module was working correctly as data was successfully printed in the command window. Additionally, by setting eventsArray in index.js, I confirmed that Express and Jade te ...

Excessive wait times during the construction of a moderately sized application (over 2 minutes) using TypeScript and loaders like Vue-Loader and TS-Loader

I'm currently utilizing Nuxt 2 with TypeScript and the most up-to-date dependency versions available. Even though my app is of medium size, the compilation time seems excessively slow. Here are my PC specs: Ryzen 7 2700X (8 Cores/16 Threads) 16 GB D ...

Send the id from the controller to the script following a Post request

In continuation from the previous question Original question I am currently facing an issue with passing an Id to a link (e.g. http://localhost:1914/en/Events/Index/22). I was advised to pass it via JSON results, but I am unable to retrieve it back in my ...

Employing async/await for efficient data retrieval

Attempting to utilize async-await in TypeScript Vue 3 to retrieve data, but encountering an issue where the function is already logging 'undefined' (or executing before the function call) private async exportDataOrder() { await this.getDataEx ...

The failover process for PayPal involves seamless transitions to backup systems in the

I am currently assisting a client with a unique architecture setup: Back End Running on Java Server Front End Powered by Proxy (Node JS + Express application) For security reasons, all requests made to the server must pass through the Proxy. We ar ...

Setting up flowplayer for multiple div elements: a tutorial

I have a collection of videos and I am trying to set up the player for each div that holds a video. When constructing the divs in my JavaScript code, it looks like this: <div id="player+{{$index}}"></div> // The "player" + index is generat ...

What is the best method for confirming that a string is not undefined, null, or an empty string in an Angular template?

Is there an efficient method to verify whether a string is not undefined, null, or '' in an angular template? If the value is valid, then show this section. <div class="flex-row date-area" *ngIf="startDate !== undefined && startDate ...

The use of jQuery ajax requests is leading to a refresh of the page

I've encountered an issue with a button on my HTML page that is not associated with any form. <input type='button' id='submitter' value='add'/> There is a click handler attached to it: $('#submitter').c ...

What's the best way to incorporate mouseenter() and mouseleave() into several elements sharing the same class?

I have a vision for a fun game where players must navigate from one platform to another without falling off the edges. The game starts when you hover over the initial platform, and success is achieved by reaching the final platform. However, failure occurs ...

Is there a way to adjust the dimensions of Google charts within a Bootstrap tab for a more customized appearance?

I've been working on a page that features tab navigation using Twitter Bootstrap and I want to include Google charts within each tab's content. However, I've encountered an issue where the charts are appearing in different sizes despite spec ...

Using JavaScript, add a complex JSON record to a JSON variable by pushing it

I have been attempting to insert a complex JSON data record into a JSON variable using the following code: var marks=[]; var studentData="student1":[{ "term1":[ {"LifeSkills":[{"obtained":"17","grade":"A","gp":"5"}]}, {"Work":[{"obtained":"13"," ...

javascript create smooth transitions when navigating between different pages

As a newcomer to JS, I am currently working on creating a website with an introduction animation. My goal is to have this animation displayed on a separate page and once it reaches the end, automatically redirect to the next webpage. <body onload="setT ...

Instructions for including packages in .vue files

Within the script section of my .vue file, I have the following code: <script> import get from 'lodash.get'; ... </script> Despite trying to import lodash.get, I keep encountering an error message stating ReferenceError: ge ...

Error 404 in Angular HTTP Request

I'm encountering a 404 error while attempting to send a post request, along with a 'possibly unhandled rejection' error. Given my limited experience with Angular, any advice would be greatly appreciated. I've gone through the documentat ...

Issue encountered: Dealing with a deadlock error triggered by a single query following the

I have a question about managing a query that runs across multiple micro-services, which can sometimes lead to deadlocks. const handleExecution = async (id: number): Promise<boolean> => { try { const query = ` UPDATE articles a1 ...

What can be done to prevent Leaflet from processing markers that fall outside of its bounding box?

I recently set up a Leaflet map with GeoDjango and rest_framework_gis, but I am facing issues with limited results and pagination. The map seems to process every marker it receives cumulatively, leading to lagging and browser crashes. I was advised in a co ...