Reputation: 3791
I am writing a spec for an Angular component that displays a button that will navigate to another page. The component makes use of Router::navigate()
but does not itself have a router outlet. A parent component has the outlet. In my spec, the test should confirm that clicking on the button routes to the correct path.
My current (broken) spec tries to use RouterTestingModule
to provide a route to a DummyComponent
. When the button is clicked in the spec I get the following error:
'Unhandled Promise rejection:', 'Cannot find primary outlet to load 'DummyComponent'', '; Zone:', 'angular', '; Task:', 'Promise.then', '; Value:', Error{__zone_symbol__error: Error{originalStack: 'Error: Cannot find primary outlet to load 'DummyComponent'
Obviously I am approaching this problem in the wrong manner. What is the correct way to test router navigation when the component does not have a router outlet?
The component (pseudo-code):
@Component({
template: `
Go to the <button (click)="nextPage">next page</button>
`
})
export class ExampleComponent {
public myId = 5;
constructor(private _router: Router);
public nextPage(): void {
this._router.navigate(['/example', this.myId]);
}
}
The spec. This does not work:
const FAKE_ID = 999;
describe('ExampleComponent Test', () => {
let exampleComponent: ExampleComponent;
let fixture: ComponentFixture<ExampleComponent>;
beforeEach(() => {
TestBed.configureTestingModule({
declarations: [ DummyComponent ],
imports: [
RouterTestingModule.withRoutes([
{ path: 'example/:id', component: DummyComponent }
]);
]
});
fixture = TestBed.createComponent(exampleComponent);
exampleComponent = fixture.componentInstance;
});
it('should route to example/:id', inject([Router, Location], (router: Router, location: Location) => {
fixture.detectChanges();
exampleComponent.myId = FAKE_ID;
const LINK_BUTTON = fixture.debugElement.query(By.css('button'));
LINK_BUTTON.nativeElement.dispatchEvent(new Event('click'));
expect(location.path()).toEqual('/example/' + FAKE_ID);
});
});
Upvotes: 2
Views: 1741
Reputation: 208964
There needs to be an outlet (<router-outlet>
) for the DummyComponent
. If the DummyComponent
is a route being navigated to from the ExampleComponent
, then the ExampleComponent
should have the outlet. You also also need to add the ExampleComponent
to the declarations`
@Component({
tempalte: `
<router-outlet></router-outlet>
<button (click)="nextPage">next page</button>
`
})
class ExampleComponent{}
declarations: [ ExampleComponent, DummyComponent ]
If you want to avoid having to set up this infrastructure just to test the route being navigated to, the better option might be to just mock the Router
, and just check that the navigate
method is called with the correct path.
beforeEach(()=>{
TestBed.configureTestingModule({
providers: [
{
provide: Router,
useValue: { navigate: jasmine.createSpy('navigate') }
}
]
})
})
With this, you don't need to configure an routing at all, as you're using a fake Router
. Then in your test
it('should route to example/:id', inject([Router], (router: Router) => {
expect(router.navigate).toHaveBeenCalledWith(['/example', FAKE_ID]);
});
Upvotes: 1