Troubles encountered while trying to dispatch an action in an Angular ngrx unit test

I have a situation where a component is fetching data from an API, but the data is only needed once, so I have opted not to use a reducer and selector for it. Instead, I am using actions and effects to handle the API call.

Here is the code I am trying to test:

private loadData() {
    const subscriptions: Subscription = new Subscription();
    subscriptions.add(
      this.actions$
        .pipe(ofType(EApiActions.ApiLoaded))
        .subscribe((action: ApiLoaded) => {
          subscriptions.unsubscribe();
          this.data = action.result;
        })
    );
    subscriptions.add(
      this.actions$
        .pipe(ofType(EApiActions.ApiFailure))
        .subscribe((action: ApiFailure) => {
          subscriptions.unsubscribe();
        })
    );
    this.store.dispatch(
      new ApiRequest()
    );
  }

My test script is as follows:

let mockStore: MockStore;

beforeEach(async(() => {
    TestBed.configureTestingModule({
      declarations: [MyComponent],
      providers: [
        provideMockActions(() => actions$),
        provideMockStore({ initialState })
      ],
      schemas: [NO_ERRORS_SCHEMA]
    }).compileComponents();
  }));

  beforeEach(() => {
    fixture = TestBed.createComponent(MyComponent);
    component = fixture.componentInstance;
    mockStore = TestBed.inject(MockStore);
  });

  it('should dispatch action and trigger the result|failure action handler', () => {
    // Arrange
    const expectedAction = new ApiRequest();
    const dispatchSpy = spyOn(mockStore, 'dispatch');

    // Act
    fixture.detectChanges();

    // Assert
    expect(dispatchSpy).toHaveBeenCalledWith(expectedAction);

    // Act - test success
    mockStore.dispatch(new ApiLoaded([]));
    fixture.detectChanges();

    // Assert
    expect(component.data).not.toBeNull();
  });

The test fails after the line expect(dispatchSpy).toHaveBeenCalledWith(expectedAction);

Upon examining the code, it seems that the component is listening for EApiActions.ApiLoaded, so I attempt to dispatch the action with mockStore.dispatch(new ApiLoaded([])); however, the code within my component does not get executed.

How can I solve this issue? Do you believe this approach of using actions and effects is appropriate, or do you think it might be better to go through a reducer to store the result and then access it using a selector?

Answer №1

Andrei Gătej provided me with a helpful hint. Much appreciated!

Here is the functional test that is working:

it('should trigger action and handle the result or failure in actionhandler', () => {
    // Arrange
    actions$ = of({ type: EApiActions.ApiLoaded });
    const expectedAction = new ApiRequest();
    const dispatchSpy = spyOn(mockStore, 'dispatch');

    // Act
    fixture.detectChanges();

    // Assert
    expect(dispatchSpy).toHaveBeenCalledWith(expectedAction);

    // Act - test success
    mockStore.dispatch(new ApiLoaded([]));
    fixture.detectChanges();

    // Assert
    expect(component.data).not.toBeNull();
  });

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

What defines a suitable application of the ref feature in React?

How can the ref attribute be effectively used in React? I understand that it is considered a shortcut that may go against the principles of React DOM, but I want to know the specifics of how and why. I'm currently evaluating if my use case justifies t ...

Encountering difficulties accessing private variables within the template/html in Angular 5

After creating multiple variables and accessing them in their respective templates or HTML files, I've realized that having all variables set as public can be problematic. I want to convert these public variables to private, but when I do so, I receiv ...

Ways to address the Generic Object Injection Sink eslint error (security/detect-object-injection)

I am seeking a solution to resolve this issue without needing to deactivate eslint. Moreover, I am eager to comprehend the cause of the error. const getMappedCard = (cardName: CardName) => { const mappedCards = { Mastercard: <Mastercard /> ...

Dependency on Angular's HTTP service inside a component

I've been experimenting with loading data from a static JSON file as part of my journey to learn angular templating. After some searching online, I came across a few examples. However, I want to steer clear of implementing a service until I have a be ...

What is the best way to expand the width of ngbmodal?

I am trying to find a way to enlarge the size of the ngbModal box as some fonts are getting cut off due to its small size. <ng-template #deletecontent2 let-c="close" let-d="dismiss" > <div class="modal-header text-center" > <h2 clas ...

Guide to accessing a nested and potentially optional object property with a default value and specifying its data type

Just a simple query here... my goal is to extract data.user.roles, but there's a possibility that data may be empty. In such cases, I want an empty array as the output. Additionally, I need to specify the type of user - which in this instance is any. ...

Unit Testing AngularJS Configuration in TypeScript with Jasmine

I'm in the process of Unit Testing the configuration of a newly developed AngularJS component. Our application uses ui-router for handling routing. While we had no issues testing components written in plain Javascript, we are encountering difficulties ...

"Optimize Your Workflow with the Virtual Assistant Bot Platform and Command Center

As I work on developing a Virtual Assistant for Microsoft Teams, I've noticed some limitations with using adaptive cards due to the version of Teams I'm working with. For example, the buttons always need to be placed at the end of the card. In se ...

Ways to monitor modifications in an Angular4 service

Is there a way to monitor a variable or array within a service in order to identify any changes in its value or any additions to it? ...

The playwright signs in to the application through the cached session in global-setup.ts, where the wait for the selector times out when DEBUG=0 but does not time out when DEBUG=

*Updates 22.6.2022 / Identified a recurring issue with OAuth on another site, where globalSetup fails to function properly on the OAuth domain. 21.6.2022 / Analysis from Trace.zip reveals that the OAuth login URL is correct, but the screenshot depicts a bl ...

Is there a way to prevent the expansion of "--base-href" to an absolute path during the npm build process?

Currently working with Angular 14 and NPM 8. I've been using the following command to build my artifact... npm run build -- --source-map --base-href=/my-app/ --output-path=dist/my-app/ An issue arises when the index.html file in dist/my-app is create ...

The 'items' property cannot be linked to 'virtual-scroller' as it is not a recognized attribute

I'm currently facing an issue with integrating virtual scroll into my Ionic 4 + Angular project. Previously, I relied on Ionic's implementation of virtual scroll (ion-virtual-scroll) which worked well initially. However, I encountered a major dr ...

Implementing an All-Routes-Except-One CanActivate guard in Angular2

In order to group routes within a module, I am aware that it can be done like this: canActivate: [AuthGuard], children: [ { path: '', children: [ { path: 'crises', component: ManageCrisesComponent }, ...

Changing {number, Observable<string>} to Observable<number, string> is a necessary transformation to be made

Is there a way to convert an array of objects with the following structure: { id: number, data: Observable<string> } into an array of objects with this structure: Observable<{id: number, data: string}> using only RxJS operators? ...

I am having trouble with the TypeScript compiler options not being detected in Visual Studio 2015

After creating an ASP.NET 5 Empty Website project in Visual Studio 2015, I set up a tsconfig.json file with the following settings: { "compilerOptions": { "noImplicitAny": false, "noEmitOnError": true, "removeComments": false ...

Navigating through segment tabs on Ionic 3 with a simple swipe

In the code snippet provided, segments from Ionic 3 are used with ngSwitch and ngModel. However, I am looking for a way to switch between segment tabs by simply swiping on the content area, rather than tapping the tabs at the top. Is there a way to achieve ...

Steps to activate Angular Progressive Web App service worker

When I set up an Angular project, I executed the following commands in the terminal: ng add @angular/pwa ng build --prod The static website output was published in the /dist folder. After running the URL through PWABuilder, it detected the manifest bu ...

Offset the CDK Menu

Is it possible to adjust the position of the trigger using the CDK overlay by setting an offset (e.g. cdkConnectedOverlayOffsetY)? I've looked through the CDK menu documentation but couldn't find a similar functionality. Is there a method to achi ...

Error when using ES6 modules in ts-jest

I keep running into an 'unexpected token' error whenever I run my tests using ts-jest. To show you exactly what's going on, I've created a small repo with all of my current configurations available here: https://github.com/ramoneguru/t ...

Declaring a function type with a void parameter type in typescript

Embarking on my journey with ts and currently exploring TypeGraphQL. I came across something that caught my attention and seems unfamiliar to me: export declare type ReturnTypeFunc = (returns?: void) => ReturnTypeFuncValue; How should this type be unde ...