Angular 6-如何在单元测试中模拟router.events url响应

kri*_*nya 1 unit-testing typescript angular

如标题所示,我需要router.events在单元测试中进行模拟。

在我的组件中,我做了一些正则表达式来获取url中斜线之间的文本的第一个实例;例如,/pdp/

  constructor(
    private route: ActivatedRoute,
    private router: Router,
  }

this.router.events.pipe(takeUntil(this.ngUnsubscribe$))
      .subscribe(route => {
        if (route instanceof NavigationEnd) {
        // debugger
          this.projectType = route.url.match(/[a-z-]+/)[0];
        }
      });
Run Code Online (Sandbox Code Playgroud)

构建组件时,我的单元测试出错误:Cannot read property '0' of null。当我在调试器中添加注释时,route似乎没有正确设置,但是我在单元测试中对其进行了设置。我已经通过几种不同的方式完成了此工作(受本篇文章的启发:模拟router.events.subscribe()Angular2等)。

第一次尝试:

providers: [
        {
          provide: Router,
          useValue: {
            events: of(new NavigationEnd(0, '/pdp/project-details/4/edit', 'pdp/project-details/4/edit'))
          }
        },
        // ActivatedRoute also being mocked
        {
          provide: ActivatedRoute,
          useValue: {
            snapshot: { url: [{ path: 'new' }, { path: 'edit' }] },
            parent: {
              parent: {
                snapshot: {
                  url: [
                    { path: 'pdp' }
                  ]
                }
              }
            }
          }
        }
]
Run Code Online (Sandbox Code Playgroud)

第二次尝试(基于以上帖子):

class MockRouter {
  public events = of(new NavigationEnd(0, '/pdp/project-details/4/edit', '/pdp/project-details/4/edit'))
}

providers: [
        {
          provide: Router,
          useClass: MockRouter
        }
]
Run Code Online (Sandbox Code Playgroud)

第三次尝试(也基于以上帖子):

class MockRouter {
  public ne = new NavigationEnd(0, '/pdp/project-details/4/edit', '/pdp/project-details/4/edit');
  public events = new Observable(observer => {
    observer.next(this.ne);
    observer.complete();
  });
}

providers: [
        {
          provide: Router,
          useClass: MockRouter
        }
]
Run Code Online (Sandbox Code Playgroud)

第四次尝试:

beforeEach(() => {
    spyOn((<any>component).router, 'events').and.returnValue(of(new NavigationEnd(0, '/pdp/project-details/4/edit', 'pdp/project-details/4/edit')))
...
Run Code Online (Sandbox Code Playgroud)

第五次尝试:

beforeEach(() => {
    spyOn(TestBed.get(Router), 'events').and.returnValue(of({ url:'/pdp/project-details/4/edit' }))
...
Run Code Online (Sandbox Code Playgroud)

在以上所有情况下,route均未设置;该NavigationEnd对象等于:

{ id: 1, url: "/", urlAfterRedirects: "/" }
Run Code Online (Sandbox Code Playgroud)

有什么想法吗?

kri*_*nya 9

这是我想出的答案。我想我只是没有将第一种方法扩展到足够远:

import { of } from 'rxjs';
import { NavigationEnd, Router } from '@angular/router';

providers: [
    {
      provide: Router,
      useValue: {
        url: '/non-pdp/phases/8',
        events: of(new NavigationEnd(0, 'http://localhost:4200/#/non-pdp/phases/8', 'http://localhost:4200/#/non-pdp/phases/8')),
        navigate: jasmine.createSpy('navigate')
      }
    }
]
Run Code Online (Sandbox Code Playgroud)


dan*_*-sc 8

它可以很简单:

TestBed.configureTestingModule({
  imports: [RouterTestingModule]
}).compileComponents()

...

const event = new NavigationEnd(42, '/', '/');
TestBed.get(Router).events.next(event);
Run Code Online (Sandbox Code Playgroud)

  • TS2339 类型“Observable&lt;event&gt;”上不存在属性“next” (8认同)
  • @RichardCollette 您对未来破坏更改的风险是正确的。关于编译错误:我无法理解 - `TestBed.get` 方法的返回类型为 `any`,因此不能进行任何编译时检查(除非您专门将结果强制转换为 `Router`)。 (2认同)

swa*_*dog 5

认为这可能会有所帮助...在模板中使用带有 routerLinks 的页脚组件。收到未提供根的错误...必须使用“真正的”路由器...但有一个间谍变量...并将 router.events 指向我的测试可观察值,以便我可以控制导航事件

export type Spied<T> = { [Method in keyof T]: jasmine.Spy };

describe("FooterComponent", () => {
   let component: FooterComponent;
   let fixture: ComponentFixture<FooterComponent>;
   let de: DebugElement;
   const routerEvent$ = new BehaviorSubject<RouterEvent>(null);
   let router: Spied<Router>;

 beforeEach(async(() => {
    TestBed.configureTestingModule({
        providers: [provideMock(SomeService), provideMock(SomeOtherService)],
        declarations: [FooterComponent],
        imports: [RouterTestingModule]
    }).compileComponents();

    router = TestBed.get(Router);
    (<any>router).events = routerEvent$.asObservable();

    fixture = TestBed.createComponent(FooterComponent);
    component = fixture.componentInstance;
    de = fixture.debugElement;
}));
// component subscribes to router nav event...checking url to hide/show a link
it("should return false for showSomeLink()", () => {
    routerEvent$.next(new NavigationEnd(1, "/someroute", "/"));
    component.ngOnInit();
    expect(component.showSomeLink()).toBeFalsy();
    fixture.detectChanges();
    const htmlComponent = de.query(By.css("#someLinkId"));
    expect(htmlComponent).toBeNull();
});
Run Code Online (Sandbox Code Playgroud)