-
-
Save LayZeeDK/3e80b507b31089da1bc9b5db07c1519f to your computer and use it in GitHub Desktop.
<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> |
import { Component } from '@angular/core'; | |
import { | |
ComponentFixture, | |
fakeAsync, | |
TestBed, | |
tick, | |
} from '@angular/core/testing'; | |
import { FormsModule } from '@angular/forms'; | |
import { By } from '@angular/platform-browser'; | |
import { Router } from '@angular/router'; | |
import { RouterTestingModule } from '@angular/router/testing'; | |
import { of } from 'rxjs'; | |
import { Hero } from '../hero'; | |
import { HeroService } from '../hero.service'; | |
import { HEROES } from '../mock-heroes'; | |
import { HeroDetailComponent } from './hero-detail.component'; | |
@Component({ | |
template: '<router-outlet></router-outlet>', | |
}) | |
class TestRootComponent {} | |
describe('HeroDetailComponent (integrated)', () => { | |
function advance() { | |
tick(); | |
rootFixture.detectChanges(); | |
} | |
function getTitle() { | |
const element = rootFixture.debugElement.query(By.css('h2')) | |
.nativeElement as HTMLElement; | |
return element.textContent.trim(); | |
} | |
function navigateByHeroId(id: number) { | |
rootFixture.ngZone.run(() => router.navigate(['detail', id])); | |
} | |
beforeEach(async () => { | |
const fakeService = { | |
getHero(id: number) { | |
const hero = [...fakeHeroes].find(h => h.id === id); | |
return of(hero); | |
}, | |
} as Partial<HeroService>; | |
TestBed.configureTestingModule({ | |
declarations: [ | |
TestRootComponent, | |
HeroDetailComponent, | |
], | |
imports: [ | |
RouterTestingModule.withRoutes([ | |
{ path: 'detail/:id', component: HeroDetailComponent }, | |
]), | |
FormsModule, | |
], | |
providers: [ | |
{ provide: HeroService, useValue: fakeService }, | |
], | |
}); | |
await TestBed.compileComponents(); | |
rootFixture = TestBed.createComponent(TestRootComponent); | |
router = TestBed.inject(Router); | |
}); | |
const fakeHeroes: ReadonlyArray<Hero> = [...HEROES]; | |
let router: Router; | |
let rootFixture: ComponentFixture<TestRootComponent>; | |
it("displays the hero's name in upper-case letters", fakeAsync(() => { | |
const [expectedHero] = fakeHeroes; | |
navigateByHeroId(expectedHero.id); | |
advance(); | |
expect(getTitle()).toContain(expectedHero.name.toUpperCase()); | |
})); | |
}); |
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()); | |
} | |
} |
@meirka
I identified a few issues and suggested some stylistic changes to your repo: meirka/angular-unit-test-navigation#1
@LayZeeDK
Thank you, I'll go over your changes.
I'm attempting to do kinda full integration test: navigation, fill forms, backend calls (mocked by testingController) and all of it from Jasmine tests. I don't want to do e2e (for multiple reasons - long story).
@meirka
That's exactly why I built Spectacular, in particular its Feature testing API, preferably used with Angular Testing Library and/or Angular CDK Component Harnesses as described in the docs. Slide deck from NG Poland 2021 coming soon at https://speakerdeck.com/layzee
@LayZeeDK
Thank you, I'll check it out!
I guess I'm not only one who doesn't want to waste time on e2e.
Can you take a look at my simple example? I created it just to make sure we are on the same page:
https://github.com/meirka/angular-unit-test-navigation
It looks to me that Location actually changes pages (via angular routing)... lol. I wonder what broke in my actual project, since location.back() doesn't seem to work there :(