2026-05-11 19:38:21 -04:00

88 lines
3.8 KiB
Markdown

# Testing with the RouterTestingHarness
When testing components that involve routing, it is crucial **not to mock the Router or related services**. Instead, use the `RouterTestingHarness`, which provides a robust and reliable way to test routing logic in an environment that closely mirrors a real application.
Using the harness ensures you are testing the actual router configuration, guards, and resolvers, leading to more meaningful tests.
## Setting Up for Router Testing
The `RouterTestingHarness` is the primary tool for testing routing scenarios. You also need to provide your test routes using the `provideRouter` function in your `TestBed` configuration.
### Example Setup
```ts
import {TestBed} from '@angular/core/testing';
import {provideRouter} from '@angular/router';
import {RouterTestingHarness} from '@angular/router/testing';
import {Dashboard} from './dashboard.component';
import {HeroDetail} from './hero-detail.component';
describe('Dashboard Component Routing', () => {
let harness: RouterTestingHarness;
beforeEach(async () => {
// 1. Configure TestBed with test routes
await TestBed.configureTestingModule({
providers: [
// Use provideRouter with your test-specific routes
provideRouter([
{path: '', component: Dashboard},
{path: 'heroes/:id', component: HeroDetail},
]),
],
}).compileComponents();
// 2. Create the RouterTestingHarness
harness = await RouterTestingHarness.create();
});
});
```
### Key Concepts
1. **`provideRouter([...])`**: Provide a test-specific routing configuration. This should include the routes necessary for the component-under-test to function correctly.
2. **`RouterTestingHarness.create()`**: Asynchronously creates and initializes the harness and performs an initial navigation to the root URL (`/`).
## Writing Router Tests
Once the harness is created, you can use it to drive navigation and make assertions on the state of the router and the activated components.
### Example: Testing Navigation
```ts
it('should navigate to a hero detail when a hero is selected', async () => {
// 1. Navigate to the initial component and get its instance
const dashboard = await harness.navigateByUrl('/', Dashboard);
// Suppose the dashboard has a method to select a hero
const heroToSelect = {id: 42, name: 'Test Hero'};
dashboard.selectHero(heroToSelect);
// Wait for stability after the action that triggers navigation
await harness.fixture.whenStable();
// 2. Assert on the URL
expect(harness.router.url).toEqual('/heroes/42');
// 3. Get the activated component after navigation
const heroDetail = await harness.getHarness(HeroDetail);
// 4. Assert on the state of the new component
expect(await heroDetail.componentInstance.hero.name).toBe('Test Hero');
});
it('should get the activated component directly', async () => {
// Navigate and get the component instance in one step
const dashboardInstance = await harness.navigateByUrl('/', Dashboard);
expect(dashboardInstance).toBeInstanceOf(Dashboard);
});
```
### Best Practices
- **Navigate with the Harness:** Always use `harness.navigateByUrl()` to simulate navigation. This method returns a promise that resolves with the instance of the activated component.
- **Access the Router State:** Use `harness.router` to access the live router instance and assert on its state (e.g., `harness.router.url`).
- **Get Activated Components:** Use `harness.getHarness(ComponentType)` to get an instance of a component harness for the currently activated routed component, or `harness.routeDebugElement` to get the `DebugElement`.
- **Wait for Stability:** After performing an action that causes navigation, always `await harness.fixture.whenStable()` to ensure the routing is complete before making assertions.