0
votes

I have a below canDeactivate function in the component.

canDeactivate() {
return new Promise(resolve => {
 if(this.close){
   this.confirmationService.confirm({
      message: 'Please close',
      header: 'Warning',
      icon: 'pi pi-excalmation-triangle'
      accept: () => {
       resolve(true);
      },
      reject: () => {
       resolve(false);
      }
   });
  } else {
   resolve(true);
  }
 });
}

I have the below spec file for the same.

it('test canDeactivate', () => {
  component.close = true;
  const confirmationService: ConfirmationService = TestBed.get(ConfirmationService);
  fixture.detectChanges();
  spyOn<any>(confirmationService, 'confirm').and.callFake((param: any) => {
  params.accept();
  console.log('test spy');
  expect(Promise.resolve()).toBeTruthy();
  });
  component.canDeactivate();
 });

When I ran the spec with the above code, the test is passing but the statements line of confirmation service was not covered and even the console inside the spy is not logged. Please let me know how to test the confirmation service here in the right way.

2

2 Answers

1
votes

I think this has to do with the asynchrnous nature of your canDeactivate where you're returning a promise and we have to wait for the promise to resolve.

Try this:

// add async here since we will need await
it('test canDeactivate', async () => {
  component.close = true;
  const confirmationService: ConfirmationService = TestBed.get(ConfirmationService);
  fixture.detectChanges();
  spyOn<any>(confirmationService, 'confirm').and.callFake((param: any) => {
     console.log('test spy');
     params.accept(); // should resolve the promise
  });
  // wait until the promise is resolved
  const result = await component.canDeactivate();
  // we resolve(true)
  expect(result).toBe(true);
 });
0
votes

I had a similar situation and wanted to test the 'accept'/'reject' cases in different blocks, so I ended up with a slightly modified version of @alif50's answer.

    // On my component
    public doSomethingThatNeedsConfirmation(): void {
        this.confirmationService.confirm({
            message: 'Some message',
            accept: () => {
                this.otherService.someMethod({id: 1234});
            },
            reject: () => {
                // ...
            }
        });
    }

    // On the tests
    describe('after doing something that calls confirm', () => {
        let confirmSpy: Spy;
        let confirmService: ConfirmationService;
        let confirmObject: {accept: Function, reject: Function};
        let otherSpy: Spy;

        beforeEach(() => {
            confirmObject = {accept: null, reject: null};
            otherSpy = spyOn(TestBed.inject(OtherService, 'someMethod').and.callThrough();
            confirmService = TestBed.inject(ConfirmationService);
            // Fake the confirm method of the service and save the accept
            // and reject functions in an object that we can use in the tests.
            confirmSpy = spyOn(confirmService, 'confirm').and
                .callFake((confirmation: Confirmation): any => {
                    console.log('On fake confirm');
                    confirmObject.accept = confirmation.accept;                        
                    // default noop function for reject in case it's missing
                    const rejectFn = () => {};
                    confirmObject.reject = confirmation.reject ?? rejectFn;

                    confirmObject.reject = confirmation.reject;
                });
            // Click on some button and call detectChanges(), or we
            // can just call the funtion directly:
            component.doSomethingThatNeedsConfirmation();
            fixture.detectChanges(); // not needed if calling directly
        });

        it('calls confirm service', () => {
            expect(confirmSpy).toHaveBeenCalledTimes(1);
        });

        describe('after accepting', () => {
            beforeEach(() => {
                confirmObject.accept();
                fixture.detectChanges();
            });

            it('calls the other method', () => {
                expect(otherSpy).toHaveBeenCalledWith({id: 1234});
            });
        });

        describe('after rejecting', () => {
            beforeEach(() => {
                confirmObject.reject();
                fixture.detectChanges();
            });

            it('does not call the other-service', () => {
                expect(otherSpy).not.toHaveBeenCalled();
            });
        });
    });