kandarp
kandarp

Reputation: 1111

How to write unit test for ActionsSubject subscription in Angular Component

I have an Angular component that uses ngrx ActionsSubject to listen to dispatched actions. How can I write a test that can check this subscription of ActionsSubject?

The component looks like this:

export class TestComponent {

constructor(public actionsSubject: ActionsSubject) { }

  public isUpdated = false;

  public ngOnInit() {
    this.actionSubscription = this.actionsSubject.subscribe(action => {
      if (action.type === "Update") {
        this.isUpdated = true; <----- I want to test this condition
      }
    });
  }
}

Currently, I am dispatching update action manually:

  it('isUpdated should be true, when update action dispatched', () => {
    component.store.dispatch(new UpdateAction());
    expect(component.isUpdated).toEqual(true);
  });

It works, but I want to mock this subscription instead of calling action manually.

For example:

  it('isUpdated should be true, when update action dispatched', () => {
    let actionSubject = TestBed.get(ActionsSubject);
    const action = {
      type: 'Update'
    };
    actionSubject = of({ action });
    component.ngOnInit();
    fixture.detectChanges()
    expect(component.isUpdated).toEqual(true);
  });

Test suit looks like this

const action = { type: FlowActionTypes.UpdateStep }; 
const actionSub: ActionsSubject = new ActionsSubject({ action }); <-- TS not accepting 


providers: [ { provide: ActionsSubject, useValue: actionSub } <-- here I am passing as you told ] 

But it never triggers the subscription in the component. How can I test it efficiently?

Upvotes: 3

Views: 3285

Answers (1)

Wesley Trantham
Wesley Trantham

Reputation: 1264

You're close as you are! A few things that will help you:

  • ngOnInit runs the very first time you call fixture.detectChanges (in this case in the beforeEach) so no need to call it again in your test
  • ActionsSubject inherits from BehaviorSubject, so you can treat it like any other observable
  • fixture.detectChanges updates the html in your test, since you are looking directly at a variable on your component, no need to call
  • TestBed.get returns any, it helps to cast as the service you're wanting
import { async, ComponentFixture, TestBed } from '@angular/core/testing';

import { TestComponent } from './test.component';
import { ActionsSubject } from '@ngrx/store';

describe('TestComponentComponent', () => {
  let component: TestComponent;
  let fixture: ComponentFixture<TestComponent>;

  beforeEach(async(() => {
    const actionSub: ActionsSubject = new ActionsSubject();

    TestBed.configureTestingModule({
      declarations: [TestComponent],
      providers: [{ provide: ActionsSubject, useValue: actionSub }],
    })
      .compileComponents();
  }));

  beforeEach(() => {
    fixture = TestBed.createComponent(TestComponent);
    component = fixture.componentInstance;
    fixture.detectChanges();
  });

  it('should create', () => {
    expect(component).toBeTruthy();
  });

  fit('isUpdated should be true, when update action dispatched', () => {
    const actionSubject = TestBed.get(ActionsSubject) as ActionsSubject;
    const action = {
      type: 'Update'
    };
    actionSubject.next(action);

    expect(component.isUpdated).toEqual(true);
  });
});

Upvotes: 3

Related Questions