[Fixed] Unable to spy on window.confirm()

Issue

In my Angular 8 project, on clicking on signout, a confirm window comes up and asks Yes/No to logout. I want to test whether the confirm window appears or not. In my spec.ts, I wrote spyOn(window, 'confirm').and.returnValue(false);. I don’t know whether that is correct or not. I need two things. Firstly, whether the confirm window comes up or not; and secondly, how to click on the ‘Yes’ option using jasmine. Please help. Below is my code:

header.component.ts

...
import { AuthenticationService } from '../../core/authentication.service';
...
@Component({
  selector: 'app-header',
  templateUrl: './header.component.html',
  styleUrls: ['./header.component.css']
})
export class HeaderComponent implements OnInit {
legalName: any;
constructor(public authService: AuthenticationService, public accountService: AccountService, public router: Router) {}

ngOnInit() {
    this.accountService.getTransactionHistory().subscribe((res) => {
      res = JSON.parse(res);
      this.legalName = res['Result'].array.RevTrxn[0].trxn.legalName;
    })
  }

signout() {
    this.authService.signout();
  }

authentication.service.ts

signout(){
    var res = window.confirm("Are you Sure!")
    if(res){
      window.localStorage.removeItem('token');
      this.router.navigate(['/login'])
    } 
  }

header.component.spec.ts

import { HeaderComponent } from './header.component';
import { AuthenticationService } from 'src/app/core/authentication.service';
import { AccountService } from 'src/app/core/account.service';
import transactions from 'src/app/core/model/mock-transaction-history.json';

describe('HeaderComponent', () => {
  let component: HeaderComponent;
  let fixture: ComponentFixture<HeaderComponent>;
  let debugElement: DebugElement;
  let mockAuthService;
  let mockAccountService;
  let trans;
  beforeEach(async(() => {
    trans = transactions;
    mockAccountService = jasmine.createSpyObj(['getTransactionHistory']);
    mockAuthService = jasmine.createSpyObj(['signout']);
    TestBed.configureTestingModule({
      declarations: [HeaderComponent],
      imports: [RouterTestingModule, HttpClientTestingModule],
      providers: [
        { provide: AccountService, useValue: mockAccountService },
        { provide: AuthenticationService, useValue: mockAuthService },
      ],
    })
      .compileComponents();
  }));

  beforeEach(() => {
    fixture = TestBed.createComponent(HeaderComponent);
    component = fixture.componentInstance;
    debugElement = fixture.debugElement;
  });

  it('clicking on "Sign Out" should ask user to confirm', () => {
    mockAccountService.getTransactionHistory.and.returnValue(of(JSON.stringify(trans)));
    const callSignOut = mockAuthService.signout.and.returnValue([]);
    spyOn(window, 'confirm').and.returnValue(false);
    const signOut = debugElement.query(By.css('.sign-out'));
    signOut.triggerEventHandler('click', {});
    fixture.detectChanges();
    expect(window.confirm).toHaveBeenCalled();
  });

});

While running this, I am getting Expected spy confirm to have been called. in karma console. I don’t know why it is not getting called. I have tested whether signout() function of AuthenticationService is getting called or not. It is getting called anyways. The window.confirm() method is inside the signout() function as you can see.

Solution

I’ll put my feedback as an answer rather than a comment, reason being, your way of doing unit testing is slightly misleading.

The idea of unit testing is to isolate each file (service, component, pipe etc) and then test its functionality. To isolate , we use use mocks. I can see that you have done it perfectly.

Now, as a part of unit testing you should test whether this.authService.signout(); is called on signout() . Whether the authService.signout() calls windows.confirm should be a part of unit test of AuthenticationService.

Coming to your question of testing window object (for your service which you should do), you need to create serviceWindowObj and assign window object to it. I have covered similar question where I replaced window object. Take a look at it. I think you can get an idea from that.

Cheers !


Since you are new to unit testing of Angular, try this article which contains several more links at the bottom to help you out with best practices

Leave a Reply

(*) Required, Your email will not be published