Home > front end >  Error on test with two diferents EventEmitters on Jamine (Isolated Test)
Error on test with two diferents EventEmitters on Jamine (Isolated Test)

Time:06-25

I have a class that I need to test and it has two services that use two different EventEmitters (event import and @angular/core). The problem is that if I import one of these EventEmitters I can't import the other but with only one EventEmitter the test fails.

This is my component code

@Component({
  selector: "app-mug",
  templateUrl: "./mug.component.html",
  styleUrls: ["./mug.component.scss"],
})
export class MugComponent implements OnInit
{
  @Output() nav: EventEmitter<number> = new EventEmitter<number>();

  public mug: Mug= new Mug();

  constructor(
    public constants: Constants,
    public mugService: mugService,
    public basicService: BasicService,
    public toolsService: ToolsService,
    private modalService: NgbModal,
  ) 
  
  ngOnInit() {
    this.basicService.siteChange.subscribe((value) => {
      this.mugService.filterC.id = value;
      this.mugService.getRelatedMugs(); 
    });
  }

  public openModal(contentType: string): void {
    this.toolsService.eventEmitter.removeAllListeners();
    this.toolsService.eventEmitter.addListener("close-modal", () =>
      this.toolsService.eventEmitter.removeAllListeners()
    );
    this.toolsService.eventEmitter.addListener(
      "contentEvent",
      (content) => {
        this.setContent(contentType, content);
      }
    );
    const data = {
      component: ModalSearchComponent,
      input: inputList,
      ModalTitle: "Mug finder",
    };
    const modalC = this.modalService.open(ModalContainerComponent, {
      size: "lg",
      backdrop: "static",
    });
    modalC.componentInstance.showComponent(data);
  }
}

This is my Spec.ts code

import { EventEmitter } from "events";
//import { EventEmitter } from "@angular/core";

describe("MugComponent", () => {
  let component;
  const constants: Constants = new Constants();
  let mugService = jasmine.createSpyObj("mugService", [
    "filterC",
    "getRelatedMugs",
  ]);
  let modalService = jasmine.createSpyObj("modalService", ["open"]);
  let basicService = jasmine.createSpyObj("basicService", [ "siteChange"]);
  let toolsService = jasmine.createSpyObj("toolsService", ["toRoute"], {
    eventEmitter: new EventEmitter(),
  });
  //It needs a different import of EventEmitter
  //basicService.siteChange = new EventEmitter<number>(null);

  beforeEach(() => {
    component = new MugComponent(
      constants,
      mugService,
      basicService,
      toolsService,
      modalService,
    );
    component.mug = new Mug();

  });

  it("should call getRelatedMugs", fakeAsync(() => {
    component.ngOnInit();
    tick();
    expect(mugService.getRelatedMugs).toHaveBeenCalled();
  }));

//this also fail with modalC.componentInstance
  it("should call setContent openModal", fakeAsync(() => {
    component.openModal();
    tick();
    expect(component.setContent).toHaveBeenCalled();
  }));
});

These are the errors

HeadlessChrome 102.0.5005 (Windows 10.0.0) MugComponent Comprobamos ngOnInit FAILED
        TypeError: Cannot read properties of undefined (reading 'subscribe')

HeadlessChrome 102.0.5005 (Windows 10.0.0) MugComponent Comprobando openModal FAILED
        TypeError: Cannot read properties of undefined (reading 'componentInstance')

Thanks.

CodePudding user response:

The reading property subscribe of undefined is because siteChange is not mocked correctly.

When you do:

let basicService = jasmine.createSpyObj<BasicService>("basicService", [ "siteChange"]);

You are saying that siteChange is a public method but in this case it is a property. Also, notice the <BasicService> generic supplied, doing so well help you catch errors.

For a quick unblock, try this:

let basicService = { siteChange: of('1') };

For reading componentInstance of undefined, make modal.open return what is required.

let modalService = jasmine.createSpyObj("modalService", ["open"]);
// Mock here or before the openModal is called
modalService.open.and.returnValue({
  componenntInstance: {
     showComponent: () => null,
  }
});
....
component = new MugComponent(
      constants,
      mugService,
      basicService,
      toolsService,
      modalService,
    );

Edit

You need to mock the toolsService differently, I am not sure if new EventEmitter() has those methods that are being called.

Mock like this:

let toolsService = jasmine.createSpyObj("toolsService", ["toRoute"], {
    eventEmitter: {
      addListener: () => null,
      removeAllListeners: () => null,
      // keep adding all the rest you need
    }
  });

If you're new, I highly recommend for you to take your time and read this resource, it should help you a lot: https://testing-angular.com/.

  • Related