Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@LayZeeDK
Last active February 8, 2023 23:16
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save LayZeeDK/e64005b9ce11d864cf084fae5f2b7837 to your computer and use it in GitHub Desktop.
Save LayZeeDK/e64005b9ce11d864cf084fae5f2b7837 to your computer and use it in GitHub Desktop.
Dashboard: Shallow and integrated routing component test suites.
<h3>Top Heroes</h3>
<div class="grid grid-pad">
<a *ngFor="let hero of heroes" class="col-1-4"
routerLink="/detail/{{hero.id}}">
<div class="module hero">
<h4>{{hero.name}}</h4>
</div>
</a>
</div>
<app-hero-search></app-hero-search>
import { Location } from '@angular/common';
import { Component, ViewChild } from '@angular/core';
import {
ComponentFixture,
fakeAsync,
TestBed,
tick,
} from '@angular/core/testing';
import { By } from '@angular/platform-browser';
import { Router, RouterOutlet } from '@angular/router';
import { RouterTestingModule } from '@angular/router/testing';
import { asapScheduler, of } from 'rxjs';
import { observeOn } from 'rxjs/operators';
import { HeroSearchComponent } from '../hero-search/hero-search.component';
import { HeroService } from '../hero.service';
import { HEROES } from '../mock-heroes';
import { DashboardComponent } from './dashboard.component';
@Component({
template: '<router-outlet></router-outlet>',
})
class TestRootComponent {
@ViewChild(RouterOutlet)
routerOutlet: RouterOutlet;
}
@Component({
template: '',
})
class TestHeroDetailComponent {}
const leftMouseButton = 0;
describe('DashboardComponent (integrated)', () => {
function advance() {
tick();
rootFixture.detectChanges();
}
function clickTopHero() {
const firstHeroLink = rootFixture.debugElement.query(By.css('a'));
rootFixture.ngZone.run(() =>
firstHeroLink.triggerEventHandler('click', { button: leftMouseButton }));
}
function getActiveComponent<T>(): T {
return rootComponent.routerOutlet.component as T;
}
beforeEach(async () => {
const fakeService = {
getHeroes() {
return of([...HEROES]).pipe(observeOn(asapScheduler));
},
} as Partial<HeroService>;
TestBed.configureTestingModule({
declarations: [
TestRootComponent,
TestHeroDetailComponent,
DashboardComponent,
HeroSearchComponent,
],
imports: [
RouterTestingModule.withRoutes([
{ path: '', pathMatch: 'full', component: DashboardComponent },
{ path: 'detail/:id', component: TestHeroDetailComponent },
]),
],
providers: [
{ provide: HeroService, useValue: fakeService },
],
});
await TestBed.compileComponents();
rootFixture = TestBed.createComponent(TestRootComponent);
rootComponent = rootFixture.componentInstance;
location = TestBed.inject(Location);
});
beforeEach(fakeAsync(() => {
const router = TestBed.inject(Router);
rootFixture.ngZone.run(() => router.initialNavigation());
advance();
advance();
}));
let location: Location;
let rootComponent: TestRootComponent;
let rootFixture: ComponentFixture<TestRootComponent>;
it('navigates to the detail view when a hero link is clicked', fakeAsync(() => {
const component: DashboardComponent = getActiveComponent();
const [topHero] = component.heroes;
clickTopHero();
advance();
const expectedPath = '/detail/' + topHero.id;
expect(location.path()).toBe(
expectedPath,
'must navigate to the detail view for the top hero');
}));
});
import {
CUSTOM_ELEMENTS_SCHEMA,
Directive,
HostListener,
Input,
} from '@angular/core';
import {
ComponentFixture,
fakeAsync,
TestBed,
tick,
} from '@angular/core/testing';
import { By } from '@angular/platform-browser';
import { Router } from '@angular/router';
import { asapScheduler, of } from 'rxjs';
import { observeOn } from 'rxjs/operators';
import { HeroService } from '../hero.service';
import { HEROES } from '../mock-heroes';
import { DashboardComponent } from './dashboard.component';
@Directive({
selector: '[routerLink]'
})
class FakeRouterLink {
@Input()
routerLink = '';
constructor(
private router: Router,
) { }
@HostListener('click')
onClick() {
this.router.navigateByUrl(this.routerLink);
}
}
const leftMouseButton = 0;
describe('DashboardComponent (shallow)', () => {
function advance() {
tick();
fixture.detectChanges();
}
function clickTopHero() {
const firstLink = fixture.debugElement.query(By.css('a'));
firstLink.triggerEventHandler('click', { button: leftMouseButton });
}
beforeEach(async () => {
const fakeService = {
getHeroes() {
return of([...HEROES]).pipe(observeOn(asapScheduler));
},
} as Partial<HeroService>;
routerSpy = jasmine.createSpyObj('Router', ['navigateByUrl']);
TestBed.configureTestingModule({
declarations: [
DashboardComponent,
FakeRouterLink,
],
providers: [
{ provide: HeroService, useValue: fakeService },
{ provide: Router, useValue: routerSpy },
],
schemas: [CUSTOM_ELEMENTS_SCHEMA],
});
await TestBed.compileComponents();
});
beforeEach(fakeAsync(() => {
fixture = TestBed.createComponent(DashboardComponent);
component = fixture.componentInstance;
advance();
advance();
}));
let component: DashboardComponent;
let fixture: ComponentFixture<DashboardComponent>;
let routerSpy: jasmine.SpyObj<Router>;
it('navigates to hero detail when a hero link is clicked', fakeAsync(() => {
const [topHero] = component.heroes;
clickTopHero();
advance();
const expectedPath = '/detail/' + topHero.id;
const [actualPath] = routerSpy.navigateByUrl.calls.first().args;
expect(actualPath).toBe(
expectedPath,
'must navigate to the detail view for the top hero');
}));
});
import { Component, OnInit } from '@angular/core';
import { Hero } from '../hero';
import { HeroService } from '../hero.service';
@Component({
selector: 'app-dashboard',
templateUrl: './dashboard.component.html',
styleUrls: ['./dashboard.component.css']
})
export class DashboardComponent implements OnInit {
heroes: Hero[] = [];
constructor(private heroService: HeroService) {}
ngOnInit() {
this.getHeroes();
}
getHeroes(): void {
this.heroService.getHeroes()
.subscribe(heroes => this.heroes = heroes.slice(1, 5));
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment