angular - 测试ActivatedRoute.paramMap而不模拟路由器

标签 angular typescript unit-testing angular-router

我想测试组件如何在我的测试中处理this.activatedRoute.paramMap不模拟ActivatedRoute(即使用RouterTestingModule,没有 spy 或模拟)。

如下stackblitz ,我设置了一个相当简单的组件来监听 id 路由参数:

@Component({ /* ... */})
export class RoutingExamplesComponent {
  constructor(private readonly route: ActivatedRoute, /* ... */) {}

  readonly param$ = this.route.paramMap.pipe(map(params => params.get('id') ?? '<none>'));
  // ...
}

在我的测试中,我想设置我的路线并确保参数传播良好:

beforeEach(() => {
  TestBed.configureTestingModule({
    imports: [
      RoutingExamplesModule,
      RouterTestingModule.withRoutes([
        {
          path: "route/:id",
          component: RoutingExamplesComponent
        }
      ])
    ]
  });

  fixture = TestBed.createComponent(RoutingExamplesComponent);
  component = fixture.componentInstance;
  router = TestBed.get(Router);
});


it("receives initial setup", async () => {
  fixture.detectChanges();
  await router.navigate(["route", "1234"]);
  fixture.detectChanges();
  expect(fixture.nativeElement.querySelector("p").textContent).toContain(
      "1234"
    );
  });

此测试未通过,因为看起来参数未传播:

Expected '<none>' to contain '1234'.
Error: Expected '<none>' to contain '1234'. at <Jasmine> at UserContext.eval (https://angular-routing-playground-routing-test.stackblitz.io/~/app/routing-examples/routing-examples.component.spec.ts:31:80)

如何在不以任何方式模拟路由器的情况下获得正确的参数?


关于我正在做的事情的一些可选上下文:大多数有关路由器测试的堆栈溢出响应都建议模拟它,我认为这是一个严重的错误。一般来说,我已经成功地针对 RouterTestingModule 进行了测试,但是 paramMap 与子路由器相关。

最佳答案

因此,经过大量调查后,我实际上找到了两种解决此问题的方法。

未提供路由参数,因为路由器的上下文与嵌入 <router-outlet> 的组件中的上下文相同。 。由于我们不在路由器导出内,因此没有绑定(bind)到导出的路由,因此我们没有传播路由参数。

解决方案 1:让其如同在路由器 socket 中

这个解决方案基本上覆盖了 ActivatedRoute提供者提供路由器的第一个 child 。这使用与其定义相同的注入(inject)机制,但提供根上下文的第一个子级而不是根上下文:

TestBed.configureTestingModule({
  imports: [
    RoutingExamplesModule,
    RouterTestingModule.withRoutes([
      // ...
    ])
  ],
  providers: [
    // Patches the activated route to make it as if we were in the
    // <router-outlet>, so we can access the route parameters.
    {
      provide: ActivatedRoute,
      useFactory: (router: Router) => router.routerState.root.firstChild,
      deps: [Router],
    }
  ],
});

权衡:这意味着导航需要在组件实例化之前触发,否则您将无法定义路由的第一个子级:

beforeEach(async () => {
  TestBed.configureTestingModule( ... );

  router = TestBed.get(Router);
  await router.navigate(["route", "1234"]);

  fixture = TestBed.createComponent(RoutingExamplesComponent);
});

解决方案 2:在路由器 socket 中引导组件

这基本上意味着您实例化一个简单的组件,只需渲染 <router-outlet></router-outlet>然后您创建这个组件。

权衡:您不再能够直接访问固定装置,您需要检索调试组件。

关于angular - 测试ActivatedRoute.paramMap而不模拟路由器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65902273/

相关文章:

javascript - 如果用户登录则隐藏元素

javascript - rxjs 合并在 Angular5 中无法按预期工作

reactjs - 事件监听器回调函数的事件类型 - React 和 Typescript

javascript - 如何在 createSlice 的 reducer 中获取状态值?

unit-testing - Grails mock :与 Controller 解耦验证

c# - 如何在 ViewModel 中对 OnPropertyChanged 事件处理程序进行单元测试

javascript - 使用 i18n 翻译 Angular 2 中的数据绑定(bind)文本

使用 ngFor 提交的 Angular 2 ngModel

c++ - 通过契约(Contract)设计和 C++ 中的单元测试

php - Angular 6 .post .subscribe插入记录两次