angulartestingjasminesubscribespyon

Test the call to method into a subscribe on Jamine (Isolated Test)


I try to test a call to method inside on a subscriber, but I can't. Always that I call to method that has a subscribe, console send to me the error "Error: Expected spy saveMug to have been called". Also fail with reContent method.

My test should be isolated, so I can´t use fixture or testbed.

This is my component code

@Component({
  selector: "app-mug",
  templateUrl: "./mug.component.html",
  styleUrls: ["./mug.component.scss"],
})
export class MugComponent implements OnInit
{

  public mug: Mug= new Mug();

  constructor(
    public constants: Constants,
    public mugService: mugService,
    private messageService: MessageService,
    public route: ActivatedRoute,
    public router: Router,
  ) {
    super(constants, route);
  }

  ngOnInit() {}

  public saveMug(previous?: boolean): void {
    const sub = this.mugService.saveMug(this.mug).subscribe((mug) => {
      if (previous === undefined || previous === false) {
        this.messageService.showMessage(
          this.constants.MUG,
          [this.constants.MUG_OK]
        );
      } else {
        this.messageService.showMessage(
          this.constants.MUG,
          [this.constants.NO_MUG]
        );
      }
      this.mug= new Mug(mug.dates);
    });
    this.subscriptions.add(sub);
  }
}

This is my Spec.ts code

describe("MugComponent", () => {
  let component;
  const constants: Constants = new Constants();
  let messageService= jasmine.createSpyObj("messageService", ["showMessage"]);
  let route;
  let router: Router;

  beforeEach(() => {
    component = new MugComponent(
      constants,
      messageService,
      route,
      router
    );
    component.mug= new Mug();
  });

  it("should call to showMessage", () => {
    spyOn(component, "showMessage");
    component.saveMug(true);
    expect(component.showMessage).toHaveBeenCalled();
  });
});

This is the Error

Error: Expected spy showMessage to have been called. at

Thanks.


Solution

  • What is mugService? How do you have access to it without injecting it in the constructor?

    That being said, I think you may need to use fakeAsync/tick to make the subscription happen before your assertion.

    In the component, I am going to assume there is a MugService now.

    constructor(
        public constants: Constants,
        private messageService: MessageService,
        private mugService: MugService,
        public route: ActivatedRoute,
        public router: Router,
      ) {
        super(constants, route);
      }
    
    let component;
      const constants: Constants = new Constants();
      let messageService= jasmine.createSpyObj("messageService", ["showMessage"]);
      // !! create a spy
      let mugService = jasmine.createSpyObj<MugService>("MugService", ['saveMug']);
      let route;
      let router: Router;
    
      beforeEach(() => {
        component = new MugComponent(
          constants,
          messageService,
          // !! give spy object to component
          mugService,
          route,
          router
        );
        component.mug= new Mug();
      });
      
    // !! wrap in fakeAsync
      it("should call to showMessage", fakeAsync(() => {
        // !! I don't think component.showMessage exists, messageService.showMessge does and it is already spied on
        // !! make mugService.saveMug and return an observable
        mugService.saveMug.and.returnValue(of({})); // you can mock what it returns however you wish
        component.saveMug(true);
        // !! wait for the subscription to complete
        tick();
        expect(messageService.showMessage).toHaveBeenCalled();
      });
    }));