0
votes

I try to test a routerlink click that should route from /parent to /parent/child in the root router-outlet. When i start my application everything works, but in my test i get this error message:

Error: Cannot match any routes. URL Segment: 'child'

My routes:

export const routes: Routes = [
  {
    path: 'parent',
    pathMatch: 'full',
    component: ParentComponent
  },

  {
    path: 'parent/child',
    component: ChildComponent
  }

];

HTML on parent (/parent) that should route to /parent/child

<a routerLink="./child">child</a>

this works aswell but not in test:

<a routerLink="child">child</a>

My test:

describe('ParentComponent', () => {
  let component: ParentComponent;
  let fixture: ComponentFixture<ParentComponent>;

  let location: Location;
  let router: Router;

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      imports: [
        RouterTestingModule.withRoutes(routes),
        AppModule
      ]
    })
    .compileComponents();
  }));

  beforeEach(() => {
    fixture = TestBed.createComponent(ParentComponent);
    component = fixture.componentInstance;
    router = TestBed.get(Router);
    location = TestBed.get(Location);
    fixture.detectChanges();
  });

  it('router to child test', fakeAsync(() => {
    router.navigate(["/parent"]);
    tick();
    expect(location.path()).toBe("/parent")
    fixture.debugElement.query(By.css("a")).nativeElement.click();
    tick();
    expect(location.path()).toBe("/parent/child");
  }));
});

The route itself is there, because when i try something like this, it works:

 it('router to child test', fakeAsync(() => {
    router.navigate(["/parent"]);
    tick();
    expect(location.path()).toBe("/parent")
    //fixture.debugElement.query(By.css("a")).nativeElement.click();
    router.navigate(["/parent/child"]);

    tick();
    expect(location.path()).toBe("/parent/child");
  }));

It seems that my test cant handle the routerLink directly.

1

1 Answers

1
votes

It looks like you are trying to test Angular's inner workings.

Instead what would be enough is to check if the element has the correct attribute value in routerLink and trust the framework to do the right thing.

Something like this:

  it('renders the correct routerLink attribute to the child component', () => {
    const anchor = fixture.debugElement.query(By.css('a'));

    expect(anchor.nativeElement.getAttribute('routerLink')).toEqual('./child');
  });

UPDATE

Yes, during unit testing the child route is not added to the parent route.

router.navigate(['./child']); // <-- not working

now let's go back to your original implementation:

router.navigate(["/parent/child"]); // <-- it works

now to make it work from your html you can change the routerLink attribute to this:

<a routerLink="/parent/child">child</a>

now your unit test will pass.

  it('router to child test', fakeAsync(() => {
    router.navigate(['/parent']);
    tick();

    expect(location.path()).toBe('/parent');

    fixture.debugElement.query(By.css('a')).nativeElement.click();    
    tick();

    expect(location.path()).toBe('/parent/child');
  }));

Also note the children attribute on route configuration to create true child routes. Something like this:

  {
    path: 'parent',
    component: ParentComponent,
    children: [
      {
        path: 'child',
        component: ChildComponent
      }
    ]
  },