Angular 18 + Jest 29:如何在单元测试中动态修改ActivatedRoute快照的permissions数组值
Angular 18 + Jest 29:如何在单元测试中动态修改ActivatedRoute快照的permissions数组值
我来帮你拆解问题根源,再给出可落地的解决方案!
问题到底出在哪?
你当前的测试逻辑有两个核心问题,导致修改permissions始终不生效:
ngOnInit执行时机过早:在beforeEach里你调用了fixture.detectChanges(),这会立刻触发组件的ngOnInit方法。此时route.snapshot.data.session.permissions还是初始的空数组,之后在测试用例里修改route的值,已经晚了——ngOnInit已经执行完毕,不会重新读取新的权限值。- 共享路由实例的状态污染:你在
describe作用域创建了单个MockActivatedRoute实例,所有测试用例共享它。如果没有正确重置状态,后续测试会继承之前的修改,导致逻辑混乱。
解决方案:调整执行顺序 + 手动触发初始化
我们需要把ngOnInit的触发时机推迟到每个测试用例中,先设置好想要的权限值,再让组件读取并执行逻辑。
步骤1:修改beforeEach,移除提前触发的detectChanges
首先,在beforeEach里不要调用fixture.detectChanges(),避免过早执行ngOnInit:
beforeEach(async () => { await TestBed.configureTestingModule({ imports: [], providers:[ provideHttpClient(), provideHttpClientTesting(), { provide: ActivatedRoute, useValue: route}, ], declarations: [ SidebarComponent ], schemas: [NO_ERRORS_SCHEMA], }).compileComponents(); fixture = TestBed.createComponent(SidebarComponent); component = fixture.componentInstance; // 移除这行:fixture.detectChanges(); });
步骤2:在每个测试用例中先设置权限,再触发ngOnInit
现在你可以在每个测试里自由修改权限,然后手动触发组件初始化逻辑:
// 测试无权限的场景(原通过的测试调整后) it('should not call getRequestSummary when Permissions.VIEW_REQUEST_SUMMARY_PERMISSION does not exist', () => { // 确保权限数组为空 route.snapshot.data.session.permissions = []; // 手动触发ngOnInit,让组件读取最新权限 component.ngOnInit(); // 验证方法未被调用 const spy = jest.spyOn(mockAccountsService, 'getRequests'); expect(spy).not.toHaveBeenCalled(); }); // 测试有权限的场景 it('should call getRequestSummary when Permissions.VIEW_REQUEST_SUMMARY_PERMISSION does exist', () => { // 设置目标权限 route.snapshot.data.session.permissions = [Permissions.VIEW_REQUEST_SUMMARY_PERMISSION]; // 手动触发ngOnInit component.ngOnInit(); // 验证方法被调用 const spy = jest.spyOn(mockAccountsService, 'getRequests'); expect(spy).toHaveBeenCalled(); });
可选优化:每个测试用例使用独立的路由实例
如果你想彻底避免测试之间的状态污染,可以在beforeEach里每次创建新的MockActivatedRoute实例:
describe('SidebarComponent', () => { let component: SidebarComponent; let fixture: ComponentFixture<SidebarComponent>; let route: MockActivatedRoute; // 只声明,不提前实例化 beforeEach(async () => { // 每次创建新的路由实例 route = new MockActivatedRoute(); route.snapshot = { data: { session: { permissions: [] } }, }; await TestBed.configureTestingModule({ // ... 其他配置不变 providers:[ provideHttpClient(), provideHttpClientTesting(), { provide: ActivatedRoute, useValue: route}, // 使用新创建的route ], }).compileComponents(); fixture = TestBed.createComponent(SidebarComponent); component = fixture.componentInstance; }); // 测试用例和上面一致 });
为什么之前的尝试没生效?
- 你用
jest.spyOn或jest.replaceProperty修改权限时,ngOnInit已经执行过了,组件不会重新读取新的权限值。 fixture.detectChanges()在beforeEach里的调用时机太早,直接固化了初始权限的逻辑判断结果。
这样调整后,你就能在不同测试用例中灵活切换permissions数组的值,准确验证组件的逻辑了!
内容来源于stack exchange
相关产品推荐
相关产品推荐

