You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何正确Mock document并编写visibilitychange事件的Jasmine单元测试?

Angular Jasmine测试中Mock Document的正确方式

你的当前做法不正确,直接修改window.document会报错是因为浏览器环境中window.document是只读属性(仅包含getter),无法直接赋值替换。正确的做法是利用Angular的依赖注入机制,通过DOCUMENT令牌提供Mock对象,而非直接操作全局window.document。

前提:组件中正确注入Document

确保组件通过Angular的DOCUMENT令牌注入,而非直接使用window.document,这是可测试性的基础:

import { DOCUMENT } from '@angular/common';
import { Component, Inject, OnInit } from '@angular/core';

@Component({ selector: 'app-your-component', template: '' })
export class YourComponent implements OnInit {
  constructor(@Inject(DOCUMENT) private document: Document) {}

  ngOnInit(): void {
    this.document.addEventListener('visibilitychange', () => this.checkSessionOnVisibilityChange());
  }

  checkSessionOnVisibilityChange(): void {
    this.document.visibilityState === 'visible' ? this.callVisible() : this.reset();
  }

  callVisible(): void { /* 业务逻辑 */ }
  reset(): void { /* 业务逻辑 */ }
}

测试中的Mock实现步骤

  1. 创建Mock Document对象
    模拟需要的属性(visibilityState)和方法(addEventListener/removeEventListener),用Jasmine spy监听方法调用:

    const mockDocument = {
      visibilityState: 'visible',
      addEventListener: jasmine.createSpy('addEventListener'),
      removeEventListener: jasmine.createSpy('removeEventListener')
    } as unknown as Document;
    
  2. 在TestBed中注入Mock
    在测试模块配置里,用useValue替换DOCUMENT的默认提供:

    import { ComponentFixture, TestBed } from '@angular/core/testing';
    import { DOCUMENT } from '@angular/common';
    import { YourComponent } from './your.component';
    
    describe('YourComponent', () => {
      let component: YourComponent;
      let fixture: ComponentFixture<YourComponent>;
    
      beforeEach(async () => {
        await TestBed.configureTestingModule({
          declarations: [YourComponent],
          providers: [
            { provide: DOCUMENT, useValue: mockDocument }
          ]
        }).compileComponents();
      });
    
      beforeEach(() => {
        fixture = TestBed.createComponent(YourComponent);
        component = fixture.componentInstance;
        fixture.detectChanges(); // 触发ngOnInit
      });
    });
    
  3. 测试事件触发与方法调用
    通过spy获取事件处理函数,手动触发并验证逻辑:

    it('should call callVisible when document is visible', () => {
      spyOn(component, 'callVisible');
      // 获取visibilitychange的监听函数
      const visibilityChangeHandler = mockDocument.addEventListener.calls.mostRecent().args[1];
      
      mockDocument.visibilityState = 'visible';
      visibilityChangeHandler(); // 手动触发事件
    
      expect(component.callVisible).toHaveBeenCalled();
    });
    
    it('should call reset when document is hidden', () => {
      spyOn(component, 'reset');
      const visibilityChangeHandler = mockDocument.addEventListener.calls.mostRecent().args[1];
      
      mockDocument.visibilityState = 'hidden';
      visibilityChangeHandler();
    
      expect(component.reset).toHaveBeenCalled();
    });
    

额外说明

如果你的组件目前直接使用window.document而非依赖注入,建议改为@Inject(DOCUMENT)的方式——这不仅能解决测试中的Mock问题,也符合Angular的依赖注入最佳实践,让组件更易维护和测试。

内容的提问来源于stack exchange,提问作者Niranjan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 19:19:58