sarfrazanwar
sarfrazanwar

Reputation: 393

How to mock the Event Emitter of a Service in Jasmine/Angular

I am trying to write a Unit Test for Component which has Dependency Service which contains EventEmitter. I have subscribed to this Event Emitter in this Component. How can I mock this?

Dependent Service :

Service A {
  testEmitter : EventEmitter<any>();
}

Component has function :

funcA() {
  service.testEmitter.subscribe()....//
}

How can I mock this subscription? This function is called during Initialization So the Test won't work

Upvotes: 5

Views: 11144

Answers (2)

Kaloyan Stamatov
Kaloyan Stamatov

Reputation: 4024

First of all, it is wrong to use EventEmitter in a service.

It has been made for components use only!

I had made the same mistake and also had issues with the tests. Anyway, for the current case scenario, you can use rxjs 'Subject' to emulate the Emitter behavior

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

   let aServiceInj: ServiceA;
   const aServiceMock = {
      testEmitter: new Subject<any>();
      triggerEmitter(res) {
        this.testEmitter.next(res);
      }
    };

  beforeEach(async(() => {

    await TestBed.configureTestingModule({
      declarations: [SomeComponent],
      providers: [{provide: ServiceA, useValue: aServiceMock}]
    }).compileComponents();
  }));

  beforeEach(() => {
    fixture = TestBed.createComponent(SomeComponent);
    component = fixture.componentInstance;
    aServiceInj = TestBed.inject(ServiceA);
    fixture.detectChanges();
  });

  it('should trigger service emit', () => {

    aServiceInj.triggerEmitter({prop: 'whatever you want'});

   // ...Handle service respond here and write tests
  });

Upvotes: 2

Buczkowski
Buczkowski

Reputation: 2416

@Injectable()
class SomeService {
  testEmitter = new EventEmitter<any>();
}

@Component({
  selector: 'app-some',
  template: ''
})
class SomeComponent implements OnInit {
  shouldCall = true;

  constructor(private someService: SomeService) {
  }

  ngOnInit() {
    if (this.shouldCall) {
      this.funcA();
    }
  }

  private funcA() {
    this.someService.testEmitter.subscribe();
  }
}

describe('SomeComponent', () => {
  let component: SomeComponent;
  let fixture: ComponentFixture<SomeComponent>;
  let someServiceMock;

  beforeEach(async(() => {
    someServiceMock = {testEmitter: {subscribe: createSpy('testEmitter subscribe')}};

    TestBed.configureTestingModule({
      declarations: [SomeComponent],
      providers: [{provide: SomeService, useValue: someServiceMock}]
    }).compileComponents();
  }));

  beforeEach(() => {
    fixture = TestBed.createComponent(SomeComponent);
    component = fixture.componentInstance;
    // fixture.detectChanges(); // move to test suites as it cause ngOnInit call
  });

  it('should subscribe', () => {
    fixture.detectChanges();

    expect(someServiceMock.testEmitter.subscribe).toHaveBeenCalled();
  });

  it('should not subscribe', () => {
    component.shouldCall = false;

    fixture.detectChanges();

    expect(someServiceMock.testEmitter.subscribe).toHaveBeenCalled();
  });
});

Upvotes: 2

Related Questions