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

如何测试Angular中用户闲置15分钟后自动登出的函数?

问题描述

我正在使用Angular/Jasmine/Karma测试一个在ngOnInit中运行的函数,该函数会在用户15分钟无操作后执行登出。

原组件中相关函数代码:

#setSessionTimeout() {
  const clicks$ = fromEvent(document, 'click');
  const checkInterval = 60000; // 1 minute
  const timeLimit = 15; // 15 minutes

  clicks$.pipe(
    startWith('fake click'),
    switchMap(() =>
      interval(checkInterval).pipe(
        tap(value => {                                    
          console.log(value);                                                        
          if (value > timeLimit) {                                                   
            this.router.navigate(['logout']);                            
          }                                                                
        })
      )                                                                 
    )                                                                     
  ).subscribe()                                                          
}  

我的测试代码:

fit('should log out a user after 15 minutes of inactivity', fakeAsync(() => {                                    
  tick(1000 * 60 * 60 * 60);                                                                                                                      
  fixture.detectChanges();                                                                                                                                                       
  expect(routerMock.navigate).toHaveBeenCalledWith(['logout']);                                                                  
}));

目前测试无法通过,且函数似乎未执行(看不到console.log输出),请问该如何正确测试这个函数?


解决步骤
  • 先触发组件初始化逻辑
    测试中必须先调用fixture.detectChanges()触发ngOnInit,否则setSessionTimeout函数根本不会执行,自然看不到日志和登出逻辑。

  • 修正tick的时间参数
    原代码里interval每分钟触发一次,value从0开始递增:

    • 第1次触发(1分钟后):value=1
    • ...
    • 第15次触发(15分钟后):value=15,此时不满足value > timeLimit
    • 第16次触发(16分钟后):value=16,才会触发登出
      所以需要tick(16 * 60 * 1000),而不是你写的1小时。
  • 正确的测试代码示例

fit('should log out a user after 15 minutes of inactivity', fakeAsync(() => {                                    
  // 触发组件初始化,执行ngOnInit和setSessionTimeout
  fixture.detectChanges();

  // 模拟等待16分钟,让interval触发到value=16
  tick(16 * 60 * 1000);

  // 触发变更检测,确保router.navigate的调用被捕获
  fixture.detectChanges();

  expect(routerMock.navigate).toHaveBeenCalledWith(['logout']);                                                                  
}));
  • 可选:验证点击重置计时器的逻辑
    如果需要覆盖完整场景,可以模拟用户点击,验证计时器会重置:
fit('should reset timeout on user click', fakeAsync(() => {                                    
  fixture.detectChanges();
  
  // 等待10分钟
  tick(10 * 60 * 1000);
  // 模拟用户点击document,触发计时器重置
  document.dispatchEvent(new Event('click'));
  
  // 再等待10分钟,此时总时长20分钟但因重置不会登出
  tick(10 * 60 * 1000);
  expect(routerMock.navigate).not.toHaveBeenCalled();
  
  // 再等待6分钟,累计16分钟无操作,触发登出
  tick(6 * 60 * 1000);
  expect(routerMock.navigate).toHaveBeenCalledWith(['logout']);                                                                  
}));
  • 清理订阅避免内存泄漏
    建议在组件中保存setSessionTimeout的订阅对象,在ngOnDestroy中取消订阅,测试时也可以在afterEach里手动清理,避免影响其他测试用例:
// 组件内修改
private timeoutSubscription!: Subscription;

#setSessionTimeout() {
  // ... 原有代码 ...
  this.timeoutSubscription = clicks$.pipe(...).subscribe();
}

ngOnDestroy() {
  this.timeoutSubscription?.unsubscribe();
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 16:55:11