Skip to content
This repository was archived by the owner on Dec 4, 2017. It is now read-only.

docs(testing): more scenarios #2396

Merged
merged 1 commit into from
Sep 20, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions public/docs/_examples/testing/ts/app-specs.html
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@

<script>
var __spec_files__ = [
'app/about.component.spec',
'app/app.component.spec',
'app/app.component.router.spec',
'app/banner.component.spec',
Expand Down
26 changes: 26 additions & 0 deletions public/docs/_examples/testing/ts/app/about.component.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { NO_ERRORS_SCHEMA } from '@angular/core';
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { By } from '@angular/platform-browser';

import { AboutComponent } from './about.component';
import { HighlightDirective } from './shared/highlight.directive';

let fixture: ComponentFixture<AboutComponent>;

describe('AboutComponent (highlightDirective)', () => {
// #docregion tests
beforeEach(() => {
fixture = TestBed.configureTestingModule({
declarations: [ AboutComponent, HighlightDirective],
schemas: [ NO_ERRORS_SCHEMA ]
})
.createComponent(AboutComponent);
fixture.detectChanges(); // initial binding
});

it('should have skyblue <h2>', () => {
const de = fixture.debugElement.query(By.css('h2'));
expect(de.styles['backgroundColor']).toBe('skyblue');
});
// #enddocregion tests
});
7 changes: 2 additions & 5 deletions public/docs/_examples/testing/ts/app/about.component.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
// #docregion
import { Component } from '@angular/core';

import { Component } from '@angular/core';
@Component({
template: `
<h2 highlight="skyblue">About</h2>
<twain-quote></twain-quote>
<p>All about this sample</p>
`,
styleUrls: ['app/shared/styles.css']
<p>All about this sample</p>`
})
export class AboutComponent { }
16 changes: 16 additions & 0 deletions public/docs/_examples/testing/ts/app/app-routing.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { NgModule } from '@angular/core';
import { RouterModule } from '@angular/router';

import { AboutComponent } from './about.component';

@NgModule({
imports: [
RouterModule.forRoot([
{ path: '', redirectTo: 'dashboard', pathMatch: 'full'},
{ path: 'about', component: AboutComponent },
{ path: 'heroes', loadChildren: 'app/hero/hero.module#HeroModule'}
])
],
exports: [ RouterModule ] // re-export the module declarations
})
export class AppRoutingModule { };
1 change: 1 addition & 0 deletions public/docs/_examples/testing/ts/app/app.component.html
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
<!-- #docregion -->
<app-banner></app-banner>
<app-welcome></app-welcome>

Expand Down
161 changes: 95 additions & 66 deletions public/docs/_examples/testing/ts/app/app.component.spec.ts
Original file line number Diff line number Diff line change
@@ -1,108 +1,94 @@
// #docplaster
import { async, ComponentFixture, TestBed
} from '@angular/core/testing';

import { NO_ERRORS_SCHEMA } from '@angular/core';
import { DebugElement } from '@angular/core';
import { By } from '@angular/platform-browser';

import { AppComponent } from './app.component';
import { BannerComponent } from './banner.component';
import { SharedModule } from './shared/shared.module';

import { Router, RouterStub, RouterLinkDirectiveStub, RouterOutletStubComponent
} from '../testing';

// #docregion setup-schemas
import { NO_ERRORS_SCHEMA } from '@angular/core';
// #enddocregion setup-schemas
// #docregion setup-stubs-w-imports
import { Component } from '@angular/core';
// #docregion setup-schemas
import { AppComponent } from './app.component';
// #enddocregion setup-schemas
import { BannerComponent } from './banner.component';
import { RouterLinkStubDirective } from '../testing';
// #docregion setup-schemas
import { RouterOutletStubComponent } from '../testing';

// #enddocregion setup-schemas
@Component({selector: 'app-welcome', template: ''})
class WelcomeStubComponent {}

// #enddocregion setup-stubs-w-imports

let comp: AppComponent;
let fixture: ComponentFixture<AppComponent>;

describe('AppComponent & TestModule', () => {
// #docregion setup-stubs, setup-stubs-w-imports
beforeEach( async(() => {
TestBed.configureTestingModule({
declarations: [
AppComponent, BannerComponent,
RouterLinkDirectiveStub, RouterOutletStubComponent
],
providers: [{ provide: Router, useClass: RouterStub }],
schemas: [NO_ERRORS_SCHEMA]
AppComponent,
BannerComponent, WelcomeStubComponent,
RouterLinkStubDirective, RouterOutletStubComponent
]
})

.compileComponents()

.then(() => {
fixture = TestBed.createComponent(AppComponent);
comp = fixture.componentInstance;
});

}));

// #enddocregion setup-stubs, setup-stubs-w-imports
tests();
});

function tests() {

it('can instantiate it', () => {
expect(comp).not.toBeNull();
});

it('can get RouterLinks from template', () => {
fixture.detectChanges();

const links = fixture.debugElement
// find all elements with an attached FakeRouterLink directive
.queryAll(By.directive(RouterLinkDirectiveStub))
// use injector to get the RouterLink directive instance attached to each element
.map(de => de.injector.get(RouterLinkDirectiveStub) as RouterLinkDirectiveStub);

expect(links.length).toBe(3, 'should have 3 links');
expect(links[0].linkParams).toBe('/dashboard', '1st link should go to Dashboard');
expect(links[1].linkParams).toBe('/heroes', '1st link should go to Heroes');
});

it('can click Heroes link in template', () => {
fixture.detectChanges();

// Heroes RouterLink DebugElement
const heroesLinkDe = fixture.debugElement
.queryAll(By.directive(RouterLinkDirectiveStub))[1];

expect(heroesLinkDe).toBeDefined('should have a 2nd RouterLink');

const link = heroesLinkDe.injector.get(RouterLinkDirectiveStub) as RouterLinkDirectiveStub;

expect(link.navigatedTo).toBeNull('link should not have navigate yet');

heroesLinkDe.triggerEventHandler('click', null);
//////// Testing w/ NO_ERRORS_SCHEMA //////
describe('AppComponent & NO_ERRORS_SCHEMA', () => {
// #docregion setup-schemas
beforeEach( async(() => {
TestBed.configureTestingModule({
declarations: [ AppComponent, RouterLinkStubDirective ],
schemas: [ NO_ERRORS_SCHEMA ]
})

fixture.detectChanges();
expect(link.navigatedTo).toBe('/heroes');
});
}
.compileComponents()
.then(() => {
fixture = TestBed.createComponent(AppComponent);
comp = fixture.componentInstance;
});
}));
// #enddocregion setup-schemas
tests();
});

//////// Testing w/ real root module //////
// Best to avoid
// Tricky because we are disabling the router and its configuration
// Better to use RouterTestingModule
import { AppModule } from './app.module';
import { AppRoutingModule } from './app-routing.module';

describe('AppComponent & AppModule', () => {

beforeEach( async(() => {

TestBed.configureTestingModule({
imports: [ AppModule ],
})

.overrideModule(AppModule, {
// Must get rid of `RouterModule.forRoot` to prevent attempt to configure a router
// Can't remove it because it doesn't have a known type (`forRoot` returns an object)
// therefore, must reset the entire `imports` with just the necessary stuff
set: { imports: [ SharedModule ]}
imports: [ AppModule ]
})

// Separate override because cannot both `set` and `add/remove` in same override
// Get rid of app's Router configuration otherwise many failures.
// Doing so removes Router declarations; add the Router stubs
.overrideModule(AppModule, {
remove: {
imports: [ AppRoutingModule ]
},
add: {
declarations: [ RouterLinkDirectiveStub, RouterOutletStubComponent ],
providers: [{ provide: Router, useClass: RouterStub }]
declarations: [ RouterLinkStubDirective, RouterOutletStubComponent ]
}
})

Expand All @@ -117,3 +103,46 @@ describe('AppComponent & AppModule', () => {
tests();
});

function tests() {
let links: RouterLinkStubDirective[];
let linkDes: DebugElement[];

// #docregion test-setup
beforeEach(() => {
// trigger initial data binding
fixture.detectChanges();

// find DebugElements with an attached RouterLinkStubDirective
linkDes = fixture.debugElement
.queryAll(By.directive(RouterLinkStubDirective));

// get the attached link directive instances using the DebugElement injectors
links = linkDes
.map(de => de.injector.get(RouterLinkStubDirective) as RouterLinkStubDirective);
});
// #enddocregion test-setup

it('can instantiate it', () => {
expect(comp).not.toBeNull();
});

// #docregion tests
it('can get RouterLinks from template', () => {
expect(links.length).toBe(3, 'should have 3 links');
expect(links[0].linkParams).toBe('/dashboard', '1st link should go to Dashboard');
expect(links[1].linkParams).toBe('/heroes', '1st link should go to Heroes');
});

it('can click Heroes link in template', () => {
const heroesLinkDe = linkDes[1];
const heroesLink = links[1];

expect(heroesLink.navigatedTo).toBeNull('link should not have navigated yet');

heroesLinkDe.triggerEventHandler('click', null);
fixture.detectChanges();

expect(heroesLink.navigatedTo).toBe('/heroes');
});
// #docregion tests
}
3 changes: 1 addition & 2 deletions public/docs/_examples/testing/ts/app/app.component.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
// #docregion
import { Component } from '@angular/core';

import { Component } from '@angular/core';
@Component({
selector: 'my-app',
templateUrl: 'app/app.component.html'
Expand Down
10 changes: 3 additions & 7 deletions public/docs/_examples/testing/ts/app/app.module.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { RouterModule } from '@angular/router';


import { AppComponent } from './app.component';
import { AppRoutingModule } from './app-routing.module';

import { AboutComponent } from './about.component';
import { BannerComponent } from './banner.component';
import { HeroService,
Expand All @@ -19,11 +19,7 @@ import { SharedModule } from './shared/shared.module';
imports: [
BrowserModule,
DashboardModule,
RouterModule.forRoot([
{ path: '', redirectTo: 'dashboard', pathMatch: 'full'},
{ path: 'about', component: AboutComponent },
{ path: 'heroes', loadChildren: 'app/hero/hero.module#HeroModule'}
]),
AppRoutingModule,
SharedModule
],
providers: [ HeroService, TwainService, UserService ],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import { DashboardModule } from './dashboard.module';

// #docregion router-stub
class RouterStub {
navigateByUrl(url: string) { return url; }
navigateByUrl(url: string) { return url; }
}
// #enddocregion router-stub

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,7 @@ import { Hero, HeroService } from '../model';
@Component({
selector: 'app-dashboard',
templateUrl: 'app/dashboard/dashboard.component.html',
styleUrls: [
'app/shared/styles.css',
'app/dashboard/dashboard.component.css'
]
styleUrls: ['app/dashboard/dashboard.component.css']
})
export class DashboardComponent implements OnInit {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ class Page {
const router = compInjector.get(Router);
this.gotoSpy = spyOn(comp, 'gotoList').and.callThrough();
this.saveSpy = spyOn(hds, 'saveHero').and.callThrough();
this.navSpy = spyOn(router, 'navigate').and.callThrough();
this.navSpy = spyOn(router, 'navigate');
}

/** Add page elements after hero arrives */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,7 @@ import { HeroDetailService } from './hero-detail.service';
@Component({
selector: 'app-hero-detail',
templateUrl: 'app/hero/hero-detail.component.html',
styleUrls: [
'app/shared/styles.css',
'app/hero/hero-detail.component.css'
],
styleUrls: ['app/hero/hero-detail.component.css'],
providers: [ HeroDetailService ]
})
export class HeroDetailComponent implements OnInit {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ class Page {

// Get the component's injected router and spy on it
const router = fixture.debugElement.injector.get(Router);
this.navSpy = spyOn(router, 'navigate').and.callThrough();
this.navSpy = spyOn(router, 'navigate');
};
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,7 @@ import { Hero, HeroService } from '../model';
@Component({
selector: 'app-heroes',
templateUrl: 'app/hero/hero-list.component.html',
styleUrls: [
'app/shared/styles.css',
'app/hero/hero-list.component.css'
]
styleUrls: ['app/hero/hero-list.component.css']
})
export class HeroListComponent implements OnInit {
heroes: Promise<Hero[]>;
Expand Down
Loading