Search code examples
angularangular2-routing

Angular testing router params breaks test bed


When I provide params to my TestComponent the test bed blows up if the html contains a [routerLink]

testbed setup

TestBed.configureTestingModule({
        imports: [SharedModule.forRoot(), ManagementModule, HttpModule, RouterModule.forRoot([{
            path: '', component: TestComponent
        }])],
        declarations: [TestComponent],
        providers: [
            BaseRequestOptions,
            MockBackend,
            {
                provide: Http, useFactory: function (backend: MockBackend, defaultOptions: BaseRequestOptions) {
                    return new Http(backend, defaultOptions);
                },
                deps: [MockBackend, BaseRequestOptions]
            },
            { provide: APP_BASE_HREF, useValue: '/' },
            {
                provide: ActivatedRoute,
                useValue: {
                    params: Observable.of({ versionId: '1' }),
                    parent: {
                        params: Observable.of({ uniqueId: '1234' })
                    }
                }
            }
        ]
    });
    TestBed.compileComponents();
});

Error logged

Failed: Error in ./DetailComponent class DetailComponent - inline template:72:20 caused by: Cannot read property '_lastPathIndex' of undefined
TypeError: Cannot read property '_lastPathIndex' of undefined
    at findStartingPosition (webpack:///home/developer/Projects/project/~/@angular/router/src/create_url_tree.js:184:0 <- src/test.ts:100429:23)
    at createUrlTree (webpack:///home/developer/Projects/project/~/@angular/router/src/create_url_tree.js:27:21 <- src/test.ts:100272:45)
    at Router.createUrlTree (webpack:///home/developer/Projects/project/~/@angular/router/src/router.js:424:0 <- src/test.ts:28688:111)
    at RouterLinkWithHref.get [as urlTree] (webpack:///home/developer/Projects/project/~/@angular/router/src/directives/router_link.js:253:0 <- src/test.ts:50778:32)
    at RouterLinkWithHref.updateTargetUrlAndHref (webpack:///home/developer/Projects/project/~/@angular/router/src/directives/router_link.js:246:0 <- src/test.ts:50771:91)
    at RouterLinkWithHref.ngOnChanges (webpack:///home/developer/Projects/project/~/@angular/router/src/directives/router_link.js:217:67 <- src/test.ts:50742:74)
    at Wrapper_RouterLinkWithHref.ngDoCheck (/RouterModule/RouterLinkWithHref/wrapper.ngfactory.js:101:18)
    at DebugAppView.View_DetailComponent3.detectChangesInternal (/ManagementModule/DetailComponent/component.ngfactory.js:548:33)
    at DebugAppView.AppView.detectChanges (webpack:///home/developer/Projects/project/~/@angular/core/src/linker/view.js:425:0 <- src/test.ts:95635:14)
    at DebugAppView.detectChanges (webpack:///home/developer/Projects/project/~/@angular/core/src/linker/view.js:620:0 <- src/test.ts:95830:44)
    at ViewContainer.detectChangesInNestedViews (webpack:///home/developer/Projects/project/~/@angular/core/src/linker/view_container.js:67:0 <- src/test.ts:95967:37)
    at DebugAppView.View_DetailComponent0.detectChangesInternal (/ManagementModule/DetailComponent/component.ngfactory.js:85:14)
    at DebugAppView.AppView.detectChanges (webpack:///home/developer/Projects/project/~/@angular/core/src/linker/view.js:425:0 <- src/test.ts:95635:14)
    at DebugAppView.detectChanges (webpack:///home/developer/Projects/project/~/@angular/core/src/linker/view.js:620:0 <- src/test.ts:95830:44)

template line 72

<a class="button" [routerLink]="['/']">Back</a>

In an ideal world i'd like to continue providing the params, any idea why its blowing up?


Solution

  • I figured out the problem/solution.

    We're seeing Cannot read property '_lastPathIndex' of undefined because at one point the Angular router expects a _lastPathIndex property on a snapshot object.

    The relevant part of the Angular source code looks like this:

    if (route.snapshot._lastPathIndex === -1) {
      return new Position(route.snapshot._urlSegment, true, 0);
    }
    

    If snapshot is undefined, it will of course raise the error we're seeing.

    The problem can be solved by making snapshot not-undefined.

    Here's how I did it. My code is a little different from the OP's.

    I have a class called MockActivatedRoute that looks like this.

    export class MockActivatedRoute {
      parent: any;
      params: any;
    
      constructor(options) {
        this.parent = options.parent;
        this.params = options.params;
      }
    }
    

    Here's how I use it in my test.

    let mockActivatedRoute = new MockActivatedRoute({
      parent: new MockActivatedRoute({
        params: Observable.of({ id: '1' })
      })
    });
    

    To make the error go away I just added a snapshot property to MockActivatedRoute.

    export class MockActivatedRoute {
      parent: any;
      params: any;
      snapshot = {};
    
      constructor(options) {
        this.parent = options.parent;
        this.params = options.params;
      }
    }