Files
Angular-Cn/aio/content/examples/testing/src/app/app.component.router.spec.ts
T
George Kalpakas d707124fd9 test(docs-infra): fix unit tests and run them for specific docs examples on CI (#36143)
Previously, only e2e tests were run for docs examples on CI. As a
result, unit tests (which are included in the zipped archives we provide
for users to download and play with the examples locally) were often
outdated and broken.

This commit configures specific docs examples that have meaningful unit
tests to run them on CI (via the `run-example-e2e.js` script). Where
necessary, the unit tests are fixed to ensure they pass and reflect the
changes in the corresponding component/service.
This commit also removes some auto-generated unit tests that are not
meaningful (e.g. make trivial assertions, such that a component instance
is truthy) and are often broken anyway (e.g. because the corresponding
component has been changed in ways that make the tests fail).

PR Close #36143
2020-04-06 15:31:07 -07:00

191 lines
5.5 KiB
TypeScript

// For more examples:
// https://github.com/angular/angular/blob/master/modules/@angular/router/test/integration.spec.ts
import { async, ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing';
import { asyncData } from '../testing';
import { RouterTestingModule } from '@angular/router/testing';
import { SpyLocation } from '@angular/common/testing';
import { Router, RouterLinkWithHref } from '@angular/router';
import { By } from '@angular/platform-browser';
import { DebugElement, Type } from '@angular/core';
import { Location } from '@angular/common';
import { click } from '../testing';
import { routes } from './app-routing.module';
import { AppModule } from './app.module';
import { AppComponent } from './app.component';
import { AboutComponent } from './about/about.component';
import { DashboardComponent } from './dashboard/dashboard.component';
import { TwainService } from './twain/twain.service';
import { HeroService, TestHeroService } from './model/testing/test-hero.service';
let comp: AppComponent;
let fixture: ComponentFixture<AppComponent>;
let page: Page;
let router: Router;
let location: SpyLocation;
describe('AppComponent & RouterTestingModule', () => {
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [
AppModule,
RouterTestingModule.withRoutes(routes),
],
providers: [
{ provide: HeroService, useClass: TestHeroService }
]
})
.compileComponents();
}));
it('should navigate to "Dashboard" immediately', fakeAsync(() => {
createComponent();
tick(); // wait for async data to arrive
expectPathToBe('/dashboard', 'after initialNavigation()');
expectElementOf(DashboardComponent);
}));
it('should navigate to "About" on click', fakeAsync(() => {
createComponent();
click(page.aboutLinkDe);
// page.aboutLinkDe.nativeElement.click(); // ok but fails in phantom
advance();
expectPathToBe('/about');
expectElementOf(AboutComponent);
}));
it('should navigate to "About" w/ browser location URL change', fakeAsync(() => {
createComponent();
location.simulateHashChange('/about');
// location.go('/about'); // also works ... except, perhaps, in Stackblitz
advance();
expectPathToBe('/about');
expectElementOf(AboutComponent);
}));
// Can't navigate to lazy loaded modules with this technique
xit('should navigate to "Heroes" on click (not working yet)', fakeAsync(() => {
createComponent();
page.heroesLinkDe.nativeElement.click();
advance();
expectPathToBe('/heroes');
}));
});
///////////////
import { NgModuleFactoryLoader } from '@angular/core';
import { SpyNgModuleFactoryLoader } from '@angular/router/testing';
import { HeroModule } from './hero/hero.module'; // should be lazy loaded
import { HeroListComponent } from './hero/hero-list.component';
let loader: SpyNgModuleFactoryLoader;
///////// Can't get lazy loaded Heroes to work yet
xdescribe('AppComponent & Lazy Loading (not working yet)', () => {
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [
AppModule,
RouterTestingModule.withRoutes(routes),
],
})
.compileComponents();
}));
beforeEach(fakeAsync(() => {
createComponent();
loader = TestBed.inject(NgModuleFactoryLoader) as SpyNgModuleFactoryLoader;
loader.stubbedModules = { expected: HeroModule };
router.resetConfig([{path: 'heroes', loadChildren: 'expected'}]);
}));
it('should navigate to "Heroes" on click', async(() => {
page.heroesLinkDe.nativeElement.click();
advance();
expectPathToBe('/heroes');
expectElementOf(HeroListComponent);
}));
it('can navigate to "Heroes" w/ browser location URL change', fakeAsync(() => {
location.go('/heroes');
advance();
expectPathToBe('/heroes');
expectElementOf(HeroListComponent);
}));
});
////// Helpers /////////
/**
* Advance to the routed page
* Wait a tick, then detect changes, and tick again
*/
function advance(): void {
tick(); // wait while navigating
fixture.detectChanges(); // update view
tick(); // wait for async data to arrive
}
function createComponent() {
fixture = TestBed.createComponent(AppComponent);
comp = fixture.componentInstance;
const injector = fixture.debugElement.injector;
location = injector.get(Location) as SpyLocation;
router = injector.get(Router);
router.initialNavigation();
spyOn(injector.get(TwainService), 'getQuote')
// fake fast async observable
.and.returnValue(asyncData('Test Quote'));
advance();
page = new Page();
}
class Page {
aboutLinkDe: DebugElement;
dashboardLinkDe: DebugElement;
heroesLinkDe: DebugElement;
// for debugging
comp: AppComponent;
location: SpyLocation;
router: Router;
fixture: ComponentFixture<AppComponent>;
constructor() {
const links = fixture.debugElement.queryAll(By.directive(RouterLinkWithHref));
this.aboutLinkDe = links[2];
this.dashboardLinkDe = links[0];
this.heroesLinkDe = links[1];
// for debugging
this.comp = comp;
this.fixture = fixture;
this.router = router;
}
}
function expectPathToBe(path: string, expectationFailOutput?: any) {
expect(location.path()).toEqual(path, expectationFailOutput || 'location.path()');
}
function expectElementOf(type: Type<any>): any {
const el = fixture.debugElement.query(By.directive(type));
expect(el).toBeTruthy('expected an element for ' + type.name);
return el;
}