'jasmine window.location.reload in ngOnDestroy

public ngOnDestroy(): void { window.location.reload(); }

How can I unit test this? All answers I found didn't work or only worked when the test was the only one executed. It looks like jasmine is inherently calling ngOnDestroy() outside of a test suite scope. Mocking ngOnDestroy() and writing a console.log into the real thing also always resulted in a console output.

specs:

  • karma-jasmine: 4.0.2
  • jasmine-core: 4.0.0
  • angular: 12

For completion, I tried the following:

(also checked every possibility in beforeAll(), afterEach() and afterAll())

  • mock ngOnDestroy():

    beforeEach(() => {
      fixture = TestBed.createComponent(Component);
      fixture.componentInstance.ngOnDestroy = () => null,
    }
    
  • spyOn ngOnDestroy():

    beforeEach(() => {
      fixture = TestBed.createComponent(Component);
      spyOn(fixture.componentInstance, 'ngOnDestroy').and.callFake(() => null);
    }
    
  • spyOn fixture.destroy():

    beforeEach(() => {
      fixture = TestBed.createComponent(Component);
      spyOn(fixture, 'destroy').and.callFake(() => null);
    
  • spyOn a component function:

    // component:
       public ngOnDestroy(): void { this.reload(); }
       public reload(): void { window.location.reload; }
    
    // test:
       beforeEach(() => {
         fixture = TestBed.createComponent(Component);
         spyOn(fixture.componentInstance, 'reload').and.callFake(() => null);
    
  • spyOn reload:

     beforeEach(() => {
       fixture = TestBed.createComponent(Component);
       spyOn(window.location, 'reload').and.callFake(() => null);
    
  • mock reload:

     beforeEach(() => {
       fixture = TestBed.createComponent(component);
       window.location.reload = () => null,
    
  • mock location (this one gives wild results...):

    beforeEach(() => {
      fixture = TestBed.createComponent(Component);
      window.location = {reload: () => null};
    


Solution 1:[1]

window is your dependency, therefore, it should be injected as any other dependency, for example, as a token:

export const WINDOW = new InjectionToken('WINDOW');

then, in the module of Component, you need to provide it:

@NgModule({
  // ...
  providers: [
    {
      provide: WINDOW,
      useValue: window,
    },
  ],
  // ...
})

then, inject it in your Component, you need to inject it as dependency:

export class Component {
  constructor(@Inject(WINDOW) private window: Window) {}

  public ngOnDestroy(): void {
    this.window.location.reload(); // add this.
  }
}

Now, you can mock it in your tests:

beforeEach(() => {
  return TestBed.configureTestingModule({
    declarations: [Component],
    providers: [
      {
        provide: WINDOW,
        useValue: {
          location: {
            reload: () => undefined, // or a spy
          },
        },
      },
    ],
  }).compileComponents();
});

Profit!

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 satanTime