Last active
November 24, 2020 11:27
-
-
Save LayZeeDK/222eb704349c80d6d8d7885e934d9159 to your computer and use it in GitHub Desktop.
Hero detail: Shallow routed component test suite.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<div *ngIf="hero"> | |
<h2> | |
{{hero.name | uppercase}} Details | |
</h2> | |
<div> | |
<span>id:</span> | |
{{hero.id}} | |
</div> | |
<div> | |
<label> | |
name: | |
<input [(ngModel)]="hero.name" placeholder="name"> | |
</label> | |
</div> | |
<button (click)="goBack()">go back</button> | |
<button (click)="save()">save</button> | |
</div> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; | |
import { ComponentFixture, TestBed } from '@angular/core/testing'; | |
import { FormsModule } from '@angular/forms'; | |
import { By } from '@angular/platform-browser'; | |
import { | |
ActivatedRoute, | |
ActivatedRouteSnapshot, | |
convertToParamMap, | |
ParamMap, | |
Params, | |
} from '@angular/router'; | |
import { of, ReplaySubject } from 'rxjs'; | |
import { Hero } from '../hero'; | |
import { HeroService } from '../hero.service'; | |
import { HEROES } from '../mock-heroes'; | |
import { HeroDetailComponent } from './hero-detail.component'; | |
class ActivatedRouteStub implements Partial<ActivatedRoute> { | |
private _paramMap: ParamMap; | |
private subject = new ReplaySubject<ParamMap>(); | |
paramMap = this.subject.asObservable(); | |
get snapshot(): ActivatedRouteSnapshot { | |
const snapshot: Partial<ActivatedRouteSnapshot> = { | |
paramMap: this._paramMap, | |
}; | |
return snapshot as ActivatedRouteSnapshot; | |
} | |
constructor(initialParams?: Params) { | |
this.setParamMap(initialParams); | |
} | |
setParamMap(params?: Params) { | |
const paramMap = convertToParamMap(params); | |
this._paramMap = paramMap; | |
this.subject.next(paramMap); | |
} | |
} | |
describe('HeroDetailComponent (shallow)', () => { | |
function getTitle() { | |
const element = fixture.debugElement.query(By.css('h2')) | |
.nativeElement as HTMLElement; | |
return element.textContent.trim(); | |
} | |
function navigateByHeroId(id: number) { | |
routeStub.setParamMap({ id }); | |
} | |
beforeEach(async () => { | |
const fakeService = { | |
getHero(id: number) { | |
const hero = [...fakeHeroes].find(h => h.id === id); | |
return of(hero); | |
}, | |
} as Partial<HeroService>; | |
routeStub = new ActivatedRouteStub(); | |
TestBed.configureTestingModule({ | |
declarations: [HeroDetailComponent], | |
imports: [FormsModule], | |
providers: [ | |
{ provide: ActivatedRoute, useValue: routeStub }, | |
{ provide: HeroService, useValue: fakeService }, | |
], | |
schemas: [CUSTOM_ELEMENTS_SCHEMA], | |
}); | |
await TestBed.compileComponents(); | |
}); | |
beforeEach(() => { | |
fixture = TestBed.createComponent(HeroDetailComponent); | |
component = fixture.componentInstance; | |
}); | |
let component: HeroDetailComponent; | |
const fakeHeroes: ReadonlyArray<Hero> = [...HEROES]; | |
let fixture: ComponentFixture<HeroDetailComponent>; | |
let routeStub: ActivatedRouteStub; | |
it("displays the hero's name in upper-case letters", () => { | |
const [expectedHero] = fakeHeroes; | |
navigateByHeroId(expectedHero.id); | |
fixture.detectChanges(); | |
expect(getTitle()).toContain(expectedHero.name.toUpperCase()); | |
}); | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { Location } from '@angular/common'; | |
import { Component, Input, OnInit } from '@angular/core'; | |
import { ActivatedRoute } from '@angular/router'; | |
import { Hero } from '../hero'; | |
import { HeroService } from '../hero.service'; | |
@Component({ | |
selector: 'app-hero-detail', | |
styleUrls: ['./hero-detail.component.css'], | |
templateUrl: './hero-detail.component.html', | |
}) | |
export class HeroDetailComponent implements OnInit { | |
@Input() hero: Hero; | |
constructor( | |
private route: ActivatedRoute, | |
private heroService: HeroService, | |
private location: Location, | |
) {} | |
ngOnInit(): void { | |
this.getHero(); | |
} | |
getHero(): void { | |
const id = +this.route.snapshot.paramMap.get('id'); | |
this.heroService.getHero(id) | |
.subscribe(hero => this.hero = hero); | |
} | |
goBack(): void { | |
this.location.back(); | |
} | |
save(): void { | |
this.heroService.updateHero(this.hero) | |
.subscribe(() => this.goBack()); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment