What is the best way to test multiple store injections withLatestFrom in NgRx Effects?

Within our angular web application, we have implemented NgRx-effects that rely on various data sources within our store. To achieve this, we have adopted the suggested withLatestFrom strategy:

withLatestFrom(
   this.store.pipe(select(...)),
   this.store.pipe(select(...)),
   ...
)

While this method works effectively in production, it poses challenges when it comes to unit testing the effects.

Currently, our unit tests involve jasmine-marbles, jasmine spy-objects, and the ngrx MockStore (NgRx 7+). The main difficulty lies in providing the necessary store state to ensure that the selectors function correctly.

For instance, in our EXAMPLE-EFFECT, as illustrated below:

@Effect()
getStammdatenDetails$: Observable<Action> = this.actions$.pipe(
   ofType(StammdatenItemDetailActionTypes.REQUEST_DETAILS),
   withLatestFrom(
      this.store.pipe(select(fromRoot.getMetadata)),
      this.store.pipe(select(fromRoot.getCustomerId)),
      this.store.pipe(select(fromRoot.getRouterParams))
   ),
   mergeMap(([action, metadata, customerId, params]) => {
      *effect logic*
   })
);

We are seeking further guidance or helpful resources that could assist us in effectively unit testing such effects. Any insights on streamlining the testing process or refining the effects for better testability would be greatly appreciated.

Answer №1

If you're looking for a way to set up your testing environment for ChapterEffects, you can follow this approach:

describe('ChapterEffects', () => {
  const actions$ = new Subject<any>();
  let effects: ChapterEffects;

  beforeEach(() => {
    TestBed.configureTestingModule({
      providers: [
        TestedEffects,
        provideMockActions(() => actions$),
        ...otherMocks,
      ],
    });

    effects = TestBed.get(ChapterEffects);
  });

  it('', () => {

  });
});

Here is the tested effect:

  @Effect()
  fetchData$ = this.actions$.pipe(
    ofType<FetchAction>(ActionTypes.FetchAction),
    switchMap(({ payload }) => {
      return this.someService
        .get(payload)
        .pipe(
          map((data) => new LoadAction(data)),
          catchError(() => new ErrorAction()),
        );
    }),
  );

This is how you can set up your effect and test it. The goal is to verify whether the FetchAction will trigger a get request and load LoadAction once the request is complete.

First, you need to mock the SomeService in your TestBed:

const otherMocks = [ { provide: SomeService, useValue: { get: () => of(42)} }, ]

This means that during testing, this.someService will return { get: () => of(42)} }.

Next, you can mock the FetchAction. Since actions$ is a Subject, you can trigger the action with

actions$.next(new FetchRequest(7))
(7 as the payload).

After that, your effect should emit LoadAction with a value of 42, so:

it('', (done) => {
  effect.fetchData$.subscribe(action => {
    expect(action.payload).toEqual(42);
  }
  done()
  actions$.next(7);
});

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

When no values are passed to props in Vue.js, set them to empty

So I have a discount interface set up like this: export interface Discount { id: number name: string type: string } In my Vue.js app, I am using it on my prop in the following way: export default class DiscountsEdit extends Vue { @Prop({ d ...

Is it possible to align the radio-button label above the radio-button in Angular Material 2?

Currently, I am utilizing angular material 2 (material.io) and attempting to position the label of the md-radio-button above the radio button itself. Here's an illustration: View Radio Buttons The official documentation mentions that you can easily ...

Guide on linking a trust policy to an IAM role through CDK

{ "Version": "2008-10-17", "Statement": [ { "Sid": "", "Effect": "Allow", "Principal": { "AWS": [ ...

Alias route for `src` in Ionic 3

I have set up a custom webpack configuration for Ionic 3 in order to use src as a path alias (meaning I can import from src/module/file): resolve: { alias: { 'src': path.resolve('./src') } } However, after updating to Ionic ap ...

Dynamic Introduction Screen - Ionic Version 4.0

Greetings! My client has requested that we include an animated splash screen in our app, and has provided us with an animated GIF for this purpose. Despite my efforts, I have not been able to find any tutorials on how to achieve this in Ionic 4.0. I did ...

Declaring scoped runtime interfaces with Typescript

I need to create a global interface that can be accessed at runtime under a specific name. /** Here is my code that will be injected */ // import Vue from "vue"; <- having two vue instances may cause issues // ts-ignore <- Vue is only ava ...

The object must contain a property 'children', which is required in the type '{ children: any; }' but missing in the type '{}'

While learning React from a variety of sources, I've encountered an issue with one of the examples. Error message: Property 'children' is missing in type '{}' but required in type '{ children: any; }' export default fu ...

The utilization of the rest parameter in combination with generics

I encountered an issue with my iteration. The error message "Operator '+=' cannot be applied to types 'number' and 'T'" is showing up. I am puzzled as to why this is happening. let a: number = 1, b: number = 2, c: number ...

Encountering unusual results while utilizing interfaces with overloaded arguments

I came across a situation where TypeScript allows calling a method with the wrong type of argument. Why doesn't the TypeScript compiler flag this as an issue? interface IValue { add(value: IValue): IValue; } class NumberValue implements IValue { ...

Adding a component dynamically with a link click in Angular: A step-by-step guide

I am encountering an issue with my web application setup. I have a navigation bar, a home page with left and right divs, and a view-associates component. My goal is to dynamically add the view-associates component into the home's right div when a spec ...

Tips for utilizing generated *.d.ts files

I have been utilizing a Visual Studio 2017 extension called TypeScript Definition Generator to automatically create TypeScript interfaces for my MVC-ViewModels. Despite trying various similar tools, they all seem to result in the same output (*.cs.d.ts-Fil ...

Encountering difficulty when determining the total cost in the shopping cart

I am currently working on a basic shopping cart application and I am facing an issue when users add multiple quantities of the same product. The total is not being calculated correctly. Here is my current logic: Data structure for Products, product = { ...

Encountering a 401 Unauthorized error due to CORS origin issue when making a post request with HttpClient in Angular

Encountering an error when trying to upload data to my backend Firebase database. Here are the relevant code snippets: storeUsers(users: any[]){ return this.http.post('https://promise-90488.firebaseio.com/data.json', users); } appc ...

Issues with Ajax calls in IOS on Ionic Cordova, functioning properly on Android

After meticulously following the instructions provided on this website, I successfully got my app to work flawlessly on Android and in my Chrome browser using the Ionic server. However, I encountered issues when testing it on an iOS emulator or my actual i ...

What is the best way to limit the type of the second argument based on the type of the

Within the tutorial Exploring How to Extract Parameter Types from String Literal Types Using TypeScript, a fascinating problem is presented without a solution. function calculate(operation, data) { if (operation === 'add') { return da ...

Angular reactive form pattern validator restricts input to text, digits, and certain special characters

I am currently working with Angular 10 and reactive forms. I have a requirement where an input field should only accept letters, numbers, and the special characters "_" and "-". I have attempted to allow letters and numbers using the following code: Valid ...

The error message "Angular formGroup requires a FormGroup instance. Kindly provide one."

I used angular reactiveforms to create a form. The default data is successfully printed on the form, however, I am facing an error in the console that says "formGroup expects a FormGroup instance. Please pass one in." Can someone guide me on how to resolve ...

What methods can I use to emphasize a row of mat-radio-buttons?

UPDATE: https://stackblitz.com/edit/angular-uhuwie I am struggling to implement row highlighting for a specific mat-radio-button. Currently, all rows are being highlighted when the correct choice is selected. The desired behavior is that only the row corr ...

Utilize the function specified in an external file

In my project, I have a typescript file named "menuTree.ts" which compiles to the following JavaScript code: define(["require", "exports"], function (require, exports) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var Menu ...

What is the way to assign a variable to ngClass in Angular?

I'm currently working on creating modals that will display different content based on which button is clicked. Each button should trigger a unique modal to appear, each with its own specific content inside. When a button is clicked, the 'active&a ...