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

Angular+Jest测试时引入moment.js出现循环结构转JSON错误

解决方案

1. 修复moment.js的导入方式

你收到的call-import-namespace警告是核心问题:import * as moment from "moment"导入的是整个命名空间对象,而非moment的默认导出函数。修改导入语句为默认导入:

import moment from "moment";

如果你的TypeScript配置启用了严格模式,需要在tsconfig.json中添加以下配置,确保允许合成默认导入:

{
  "compilerOptions": {
    "allowSyntheticDefaultImports": true,
    "esModuleInterop": true
  }
}

或者使用显式的默认导入语法:

import { default as moment } from "moment";

2. 解决测试中的循环结构序列化错误

报错里的循环结构来自Angular的Zone对象,原因是getAll()内部的Promise.all是异步操作,测试中没有等待异步完成,导致Jest尝试序列化包含Zone引用的对象时失败。

方案A:使用Angular的fakeAsync和tick处理异步

import { fakeAsync, tick, TestBed, ComponentFixture } from '@angular/core/testing';
import { YourComponent } from './your.component';
import { SettingsService } from './settings.service';

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

  beforeEach(async () => {
    // Mock SettingsService的getItem方法,返回预设的resolved Promise
    jest.spyOn(SettingsService.prototype, 'getItem').mockImplementation((key: string) => {
      switch(key) {
        case 'group': return Promise.resolve(false);
        case 'serialNumber': return Promise.resolve(false);
        case 'shifts': return Promise.resolve([]);
        case 'version': return Promise.resolve(1);
        default: return Promise.resolve(null);
      }
    });

    await TestBed.configureTestingModule({
      declarations: [YourComponent],
      providers: [SettingsService]
    }).compileComponents();

    fixture = TestBed.createComponent(YourComponent);
    component = fixture.componentInstance;
    fixture.detectChanges();
  });

  it('should execute getAll and set date correctly', fakeAsync(() => {
    component.getAll();
    tick(); // 触发Promise.all的then回调执行

    fixture.detectChanges();
    // 断言日期格式是否正确
    expect(component.selectedMonthData).toMatch(/^\d{4}-\d{2}-\d{2}$/);
  }));
});

方案B:使用async/await等待异步完成

先修改getAll()函数,让它返回内部的Promise,方便测试等待:

getAll(): Promise<void> {
  return Promise.all([
    this.settingsService.getItem("group", false),
    this.settingsService.getItem("serialNumber", false),
    this.settingsService.getItem("shifts"),
    this.settingsService.getItem("version")
  ]).then((res) => {
    this.settings = {
      group: res[0] as boolean,
      serialNumber: res[1] as boolean,
      shifts: (res[2] as number[]) || [],
      version: res[3] as number,
    };       
    this.getDate();
  });
}

然后在测试中使用async/await:

it('should execute getAll and set date correctly', async () => {
  await component.getAll();
  
  fixture.detectChanges();
  expect(component.selectedMonthData).toMatch(/^\d{4}-\d{2}-\d{2}$/);
});

验证

修改后,先确认call-import-namespace警告消失,再运行测试,循环结构的错误也会被解决——因为异步操作被正确等待,不会让Zone对象被意外序列化。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 07:30:14