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

Angular 9中如何测试带有relativeTo参数的路由?

如何正确测试Angular 9中带有relativeTo的路由?

问题背景

组件方法代码

initiateDetailsView(detailsData) {
    this.router.navigate(['./personnel-details'], {
        relativeTo: this.activatedRoute,
    });
}

初始测试用例

it('should navigate to details page', () => {
    const routerNavigateSpy = spyOn(router, 'navigate');
    component.initiateDetailsView({});
    fixture.detectChanges();
    expect(routerNavigateSpy).toHaveBeenCalledWith([
        './personnel-details',
        { relativeTo: 'clinic-admin/scok-personnel' },
    ]);
});

初始错误信息

Expected spy navigate to have been called with:
      [ [ './personnel-details', Object({ relativeTo: 'clinic-admin/scok-personnel' }) ] ]
but actual calls were:
      [ [ './personnel-details' ], Object({ relativeTo: Route(url:'', path:'') }) ].

更新后的测试代码及新错误

更新后的测试代码:

fdescribe('ListPersonnelComponent', () => {
    let component: ListPersonnelComponent;
    let fixture: ComponentFixture<ListPersonnelComponent>;
    let location: Location;
    let activatedRoute:ActivatedRoute;
    let router;
    const routes = [
        {
            path: 'personnel-details',
            component: PersonnelDetailsComponent,
            relativeTo: activatedRoute,
        },
    ];

  beforeEach(async(() => {
        TestBed.configureTestingModule({
            imports: [
                RouterTestingModule.withRoutes(routes),
                SharedModule,
                BrowserAnimationsModule,
                HttpClientModule,
            ],
            declarations: [ListPersonnelComponent],
            providers: [PersonnelDataService],
        }).compileComponents();
    }));

    beforeEach(() => {
        fixture = TestBed.createComponent(ListPersonnelComponent);
        component = fixture.componentInstance;
        router = TestBed.inject(Router);
        fixture.detectChanges();
    });

    it('should create', () => {
        expect(component).toBeTruthy();
    });

    it('should navigate to details page', () => {
        const routerNavigateSpy = spyOn(router, 'navigate');
        component.initiateDetailsView({});
        fixture.detectChanges();
        expect(routerNavigateSpy).toHaveBeenCalledWith([
            './personnel-details',
            { relativeTo: activatedRoute },
        ]);
    });
});

出现新错误:变量“activatedRoute”在赋值前被使用.ts(2454)


解决方案

1. 模拟并注入ActivatedRoute实例

组件中relativeTo传入的是ActivatedRoute实例而非字符串,测试时需要创建模拟的ActivatedRoute对象并注入测试模块:

// 在测试块顶部声明模拟对象
let activatedRoute: SpyObj<ActivatedRoute>;

// 在async beforeEach中初始化模拟对象并配置到TestBed
beforeEach(async(() => {
    // 创建包含必要属性的ActivatedRoute模拟(根据组件实际使用的属性调整)
    activatedRoute = jasmine.createSpyObj('ActivatedRoute', [], { 
        snapshot: { url: [], path: '' },
        parent: null
    });

    TestBed.configureTestingModule({
        imports: [
            RouterTestingModule.withRoutes(routes),
            SharedModule,
            BrowserAnimationsModule,
            HttpClientModule,
        ],
        declarations: [ListPersonnelComponent],
        providers: [
            PersonnelDataService,
            { provide: ActivatedRoute, useValue: activatedRoute } // 注入模拟对象
        ],
    }).compileComponents();
}));

2. 修正路由配置

路由定义中不存在relativeTo属性,移除routes数组里的该配置项:

const routes = [
    {
        path: 'personnel-details',
        component: PersonnelDetailsComponent
    },
];

3. 修正测试断言

断言时使用模拟的activatedRoute实例匹配组件调用navigate的参数:

it('should navigate to details page with correct relativeTo', () => {
    const routerNavigateSpy = spyOn(router, 'navigate');
    
    component.initiateDetailsView({});
    
    // 注意参数结构:第一个是路径数组,第二个是配置对象
    expect(routerNavigateSpy).toHaveBeenCalledWith(
        ['./personnel-details'],
        { relativeTo: activatedRoute }
    );
});

错误原因说明

  • 初始错误:断言中用字符串作为relativeTo的值,但组件实际传入的是ActivatedRoute实例,导致匹配失败。
  • 更新后的错误:全局定义的routes数组引用了未赋值的activatedRoute变量,activatedRoute在beforeEach中才会初始化,全局作用域下变量未赋值就被使用。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 07:10:57