Ushelajyan
Ushelajyan

Reputation: 1

Testing effects NgRx Angular 11

I am having problems while trying to test effects in my Angular 11 project. I use the karma runner. It would seem that when I dispatch an action in my tests, the effects does't seem to respond to it.

import { TestBed } from '@angular/core/testing';
import { of } from 'rxjs';
import { provideMockActions } from '@ngrx/effects/testing';
import {
  SimpleActionTypes,
} from '../actions/simple.action';
import {SimpleEffects} from './simple.effect';
import {MockStore, provideMockStore} from '@ngrx/store/testing';
import {Store} from '@ngrx/store';

describe('SimpleEffects', () => {
  let actions$: any;
  let effects: SimpleEffects;
  let store: MockStore<Store>;
  beforeEach(() => {
    TestBed.configureTestingModule({
      providers: [
        SimpleEffects,
        provideMockActions(() => actions$),
        provideMockStore() ,
      ],
    });
    store = TestBed.inject(MockStore);
    effects = TestBed.inject(SimpleEffects);
  });
  it('should be created', () => {
    expect(effects).toBeTruthy();
  });
  it('should fire with a default price', (done) => {
    // Mock the action that we use to activate the effect
    actions$ = of(SimpleActionTypes.UnavailablePrice);
    // Subscribe to the effect
    effects.getPriceAfterLocalCartUpdate.subscribe((res) => {
      // the expected results verification
      expect(res).toEqual(SimpleActionTypes.ComputePrice);
      // And all done !
      done();
    });
  });
});

I have tried many ways to enter the subscribe part of my effect (using marbles hot cold ...), but it doesn't seem to work. I have a failure indicating :

"SimpleEffects should fire with a default price FAILED
        Error: Timeout - Async function did not complete within 5000ms (set by jasmine.DEFAULT_TIMEOUT_INTERVAL)"

The micro project is hosted here : https://github.com/Ushelajyan/simple-ngrx-testing-effects

Thank you in advance for your help.

Upvotes: 0

Views: 2045

Answers (1)

Philipp Meissner
Philipp Meissner

Reputation: 5482

You override actions$ within your test (it-block). Unfortunately the TestBed.configureTestingModule() gets executed inside a beforeEach block, which happens right before the it-block gets executed.

import { TestBed } from '@angular/core/testing';
import { of } from 'rxjs';
import { provideMockActions } from '@ngrx/effects/testing';
import {
  SimpleActionTypes,
} from '../actions/simple.action';
import {SimpleEffects} from './simple.effect';
import {MockStore, provideMockStore} from '@ngrx/store/testing';
import {Store} from '@ngrx/store';

describe('SimpleEffects', () => {
  let store: MockStore<Store>;
  
  const createEffects = (actions$) => {
    TestBed.configureTestingModule({
      providers: [
        SimpleEffects,
        provideMockActions(() => actions$),
        provideMockStore() ,
      ],
    });
    store = TestBed.inject(MockStore);
    return TestBed.inject(SimpleEffects);
  };

  it('should be created', () => {
    const effects = createEffects(of(undefined));

    expect(effects).toBeTruthy();
  });

  it('should fire with a default price', (done) => {
    // Mock the action that we use to activate the effect
    const actions$ = of(SimpleActionTypes.UnavailablePrice);

    // Create the effect with your given mock
    const effects = createEffects(actions$)

    effects.getPriceAfterLocalCartUpdate.subscribe((res) => {
      // the expected results verification
      expect(res).toEqual(SimpleActionTypes.ComputePrice);
      // And all done !
      done();
    });
  });
});

This should do the trick. I added a createEffect function that configures your TestBed properly with the given actions$ mock and returns a new instance of SimpleEffects. This instance can then be used to subscribe to its defined effects.

Upvotes: 1

Related Questions