如何在 Angular 12 单元测试中对 window.location.reload 进行单元测试?

6
在我的angular项目中,我有一个函数。
reloadPage(): void {
  window.location.reload();
}

所以,每当我需要重新加载页面时,我都会调用这个函数。

现在,我正在尝试为这个函数添加单元测试,但它不起作用。

it("reloadPage: should be validated", () => {
    spyOn(window.location, 'reload').and.callFake(() => {
      //test
    });
    component.reloadPage();
});

在单元测试中,它仍会重新加载页面。

我该如何为此函数实现单元测试?任何帮助将不胜感激。谢谢你!


只是一个想法,不确定是否可行 - 可以使用spy重新分配reload方法吗? window.location.reload = jasmine.spy()。测试运行后别忘了恢复reload方法。 - IAfanasov
4个回答

3

您需要在TestBed.configureTestingModule中提供模拟的Window对象。

首先创建一个窗口令牌。

import { InjectionToken } from '@angular/core';

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

创建一个模拟对象

windowMock = {
location: {
reload: jasmine.createSpy('reload')
 }
}

然后在providers

{provide: WINDOW, useValue: windowMock}

结果为 找不到名称 'WINDOW'。你是指 'Window' 吗? - wlf
你必须先创建一个窗口令牌。 - user12251399

2
我发现下面的解决方案可行。
在你的组件中,使用一个InjectionToken注入窗口。
const MY_WINDOW_TOKEN = new InjectionToken<Window>('Window');

您的组件构造函数需要接受以下内容:
constructor(@Inject(MY_WINDOW_TOKEN) private window: Window) { ... }

在你的模块中提供:
{ provide: MY_WINDOW_TOKEN, useValue: window }

在您的测试(spec)中,可以通过在TestBed配置中提供模拟/间谍实现来注入另一个(模拟)窗口。请注意保留HTML标签。
{ 
  provide: MY_WINDOW_TOKEN, 
  useFactory: () => {
    return jasmine.createSpyObj('Window', [...]);
  }
}

基本上就是将测试对象与其依赖项隔离开来。

(注意:所有代码都是从记忆中编写的,可能需要进行一些修改才能正常工作/编译)


这真的非常有帮助,谢谢...我遇到了karma-coverage问题,因为window.location.reload会导致测试失败,显示类似于“您的测试重新加载了页面!”的信息。 - Nathan Beach

0

我找到了一个不错的解决方案,使用了 Angular 内部函数和Location

constructor(
    ...
    private location: Location
) {}

并使用

this.location.historyGo(0);

重新加载页面。这样你就不会在测试中遇到问题了。

-1

没有简单的方法来测试是否已调用location.reload()。这也不值得头疼(你也不应该刷新页面,这是一种hack,只在非常罕见的情况下才有用,比如在运行时玩环境变量)...

因此,为了能够测试任何onEvent函数的逻辑(这是必要的),并跳过由刷新页面引起的任何错误(我们将隐藏它们),您可能会有一个类似于这样的组件:

@Component({
  ...
})
export class SomethingComponent {
  ...

  onEvent = () => {
    ... some logic to test
    this.reloadPage();
  }

  private reloadPage = () => location.reload();
}

那么测试将会是这样的:

describe('SomethingComponent', () => {
  let component: SomethingComponent;
  let fixture: ComponentFixture<SomethingComponent>;

  beforeEach(async () => {
    await TestBed.configureTestingModule({
      declarations: [ SomethingComponent ]
    })
      .compileComponents();
  });

  beforeEach(() => {
    fixture = TestBed.createComponent(SomethingComponent);
    component = fixture.componentInstance;
    fixture.detectChanges();
  });

  it('should do something onEvent', () => {
    // hack to change a private attribute of your component
    // strongly suggest not to use this as a routine
    component[ 'reloadPage' ] = () => null;

    component.onEvent();

    ... some tests here ...

    // do not test expect(location.reload).toHasBeenCalled()
    // it won't work and it's not worth make this working
  });
});

这将避免刷新页面时出现错误,您将能够实际检查onEvent函数中的任何逻辑。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接