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
相关产品推荐
相关产品推荐

