diff --git a/public/docs/_examples/testing/ts/app/banner.component.spec.ts b/public/docs/_examples/testing/ts/app/banner.component.spec.ts index c9af53a805..3e7f967b82 100644 --- a/public/docs/_examples/testing/ts/app/banner.component.spec.ts +++ b/public/docs/_examples/testing/ts/app/banner.component.spec.ts @@ -11,7 +11,8 @@ import { BannerComponent } from './banner.component'; // #docregion setup let comp: BannerComponent; let fixture: ComponentFixture; -let el: DebugElement; +let de: DebugElement; +let el: HTMLElement; describe('BannerComponent', () => { beforeEach(() => { @@ -23,25 +24,27 @@ describe('BannerComponent', () => { comp = fixture.componentInstance; // BannerComponent test instance - // get title DebugElement by element name - el = fixture.debugElement.query(By.css('h1')); + // query for the title

by CSS element selector + de = fixture.debugElement.query(By.css('h1')); + el = de.nativeElement; + }); // #enddocregion setup // #docregion tests it('should display original title', () => { - fixture.detectChanges(); // trigger data binding - expect(el.nativeElement.textContent).toContain(comp.title); + fixture.detectChanges(); + expect(el.textContent).toContain(comp.title); }); it('should display a different test title', () => { comp.title = 'Test Title'; - fixture.detectChanges(); // trigger data binding - expect(el.nativeElement.textContent).toContain('Test Title'); + fixture.detectChanges(); + expect(el.textContent).toContain('Test Title'); }); // #enddocregion tests // #docregion test-w-o-detect-changes it('no title in the DOM until manually call `detectChanges`', () => { - expect(el.nativeElement.textContent).toEqual(''); + expect(el.textContent).toEqual(''); }); // #enddocregion test-w-o-detect-changes @@ -59,8 +62,7 @@ describe('BannerComponent with AutoChangeDetect', () => { fixture = TestBed.configureTestingModule({ declarations: [ BannerComponent ], providers: [ - { provide: ComponentFixtureAutoDetect, - useValue: true } + { provide: ComponentFixtureAutoDetect, useValue: true } ] }) // #enddocregion auto-detect @@ -68,27 +70,28 @@ describe('BannerComponent with AutoChangeDetect', () => { comp = fixture.componentInstance; // BannerComponent test instance - // find title DebugElement by element name - el = fixture.debugElement.query(By.css('h1')); + // query for the title

by CSS element selector + de = fixture.debugElement.query(By.css('h1')); + el = de.nativeElement; }); // #docregion auto-detect-tests it('should display original title', () => { // Hooray! No `fixture.detectChanges()` needed - expect(el.nativeElement.textContent).toContain(comp.title); + expect(el.textContent).toContain(comp.title); }); it('should still see original title after comp.title change', () => { const oldTitle = comp.title; comp.title = 'Test Title'; // Displayed title is old because Angular didn't hear the change :( - expect(el.nativeElement.textContent).toContain(oldTitle); + expect(el.textContent).toContain(oldTitle); }); it('should display updated title after detectChanges', () => { comp.title = 'Test Title'; fixture.detectChanges(); // detect changes explicitly - expect(el.nativeElement.textContent).toContain(comp.title); + expect(el.textContent).toContain(comp.title); }); // #enddocregion auto-detect-tests }); @@ -114,14 +117,14 @@ describe('BannerComponent (simpified)', () => { // #docregion simple-example-it it('should display original title', () => { - // trigger data binding to update the view + // trigger change detection to update the view fixture.detectChanges(); - // find the title element in the DOM using a CSS selector - el = fixture.debugElement.query(By.css('h1')); + // query for the title

by CSS element selector + de = fixture.debugElement.query(By.css('h1')); // confirm the element's content - expect(el.nativeElement.textContent).toContain(comp.title); + expect(de.nativeElement.textContent).toContain(comp.title); }); // #enddocregion simple-example-it }); diff --git a/public/docs/_examples/testing/ts/app/shared/title-case.pipe.spec.ts b/public/docs/_examples/testing/ts/app/shared/title-case.pipe.spec.ts index 7481537c10..5dfc5d91b0 100644 --- a/public/docs/_examples/testing/ts/app/shared/title-case.pipe.spec.ts +++ b/public/docs/_examples/testing/ts/app/shared/title-case.pipe.spec.ts @@ -2,14 +2,15 @@ // #docregion import { TitleCasePipe } from './title-case.pipe'; -// #docregion excerpt +// #docregion excerpt, mini-excerpt describe('TitleCasePipe', () => { - // This pipe is a pure function so no need for BeforeEach + // This pipe is a pure, stateless function so no need for BeforeEach let pipe = new TitleCasePipe(); it('transforms "abc" to "Abc"', () => { expect(pipe.transform('abc')).toBe('Abc'); }); +// #enddocregion mini-excerpt it('transforms "abc def" to "Abc Def"', () => { expect(pipe.transform('abc def')).toBe('Abc Def'); @@ -28,6 +29,6 @@ describe('TitleCasePipe', () => { it('transforms " abc def" to " Abc Def" (preserves spaces) ', () => { expect(pipe.transform(' abc def')).toBe(' Abc Def'); }); -// #docregion excerpt +// #docregion excerpt, mini-excerpt }); -// #enddocregion excerpt +// #enddocregion excerpt, mini-excerpt diff --git a/public/docs/_examples/testing/ts/app/shared/twain.component.spec.ts b/public/docs/_examples/testing/ts/app/shared/twain.component.spec.ts index 767e1ec2ca..b80993cc0b 100644 --- a/public/docs/_examples/testing/ts/app/shared/twain.component.spec.ts +++ b/public/docs/_examples/testing/ts/app/shared/twain.component.spec.ts @@ -12,7 +12,8 @@ describe('TwainComponent', () => { let fixture: ComponentFixture; let spy: jasmine.Spy; - let twainEl: DebugElement; // the element with the Twain quote + let de: DebugElement; + let el: HTMLElement; let twainService: TwainService; // the actually injected service const testQuote = 'Test Quote'; @@ -37,54 +38,53 @@ describe('TwainComponent', () => { // #enddocregion spy // Get the Twain quote element by CSS selector (e.g., by class name) - twainEl = fixture.debugElement.query(By.css('.twain')); + de = fixture.debugElement.query(By.css('.twain')); + el = de.nativeElement; }); // #enddocregion setup // #docregion tests - function getQuote() { return twainEl.nativeElement.textContent; } - it('should not show quote before OnInit', () => { - expect(getQuote()).toBe('', 'nothing displayed'); + expect(el.textContent).toBe('', 'nothing displayed'); expect(spy.calls.any()).toBe(false, 'getQuote not yet called'); }); it('should still not show quote after component initialized', () => { - fixture.detectChanges(); // trigger data binding + fixture.detectChanges(); // getQuote service is async => still has not returned with quote - expect(getQuote()).toBe('...', 'no quote yet'); + expect(el.textContent).toBe('...', 'no quote yet'); expect(spy.calls.any()).toBe(true, 'getQuote called'); }); // #docregion async-test it('should show quote after getQuote promise (async)', async(() => { - fixture.detectChanges(); // trigger data binding + fixture.detectChanges(); fixture.whenStable().then(() => { // wait for async getQuote fixture.detectChanges(); // update view with quote - expect(getQuote()).toBe(testQuote); + expect(el.textContent).toBe(testQuote); }); })); // #enddocregion async-test // #docregion fake-async-test it('should show quote after getQuote promise (fakeAsync)', fakeAsync(() => { - fixture.detectChanges(); // trigger data binding + fixture.detectChanges(); tick(); // wait for async getQuote fixture.detectChanges(); // update view with quote - expect(getQuote()).toBe(testQuote); + expect(el.textContent).toBe(testQuote); })); // #enddocregion fake-async-test // #enddocregion tests // #docregion done-test it('should show quote after getQuote promise (done)', done => { - fixture.detectChanges(); // trigger data binding + fixture.detectChanges(); // get the spy promise and wait for it to resolve spy.calls.mostRecent().returnValue.then(() => { fixture.detectChanges(); // update view with quote - expect(getQuote()).toBe(testQuote); + expect(el.textContent).toBe(testQuote); done(); }); }); diff --git a/public/docs/_examples/testing/ts/app/welcome.component.spec.ts b/public/docs/_examples/testing/ts/app/welcome.component.spec.ts index f99687148f..e506dda396 100644 --- a/public/docs/_examples/testing/ts/app/welcome.component.spec.ts +++ b/public/docs/_examples/testing/ts/app/welcome.component.spec.ts @@ -1,7 +1,7 @@ // #docplaster -import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { By } from '@angular/platform-browser'; -import { DebugElement } from '@angular/core'; +import { ComponentFixture, inject, TestBed } from '@angular/core/testing'; +import { By } from '@angular/platform-browser'; +import { DebugElement } from '@angular/core'; import { UserService } from './model'; import { WelcomeComponent } from './welcome.component'; @@ -10,8 +10,10 @@ describe('WelcomeComponent', () => { let comp: WelcomeComponent; let fixture: ComponentFixture; - let userService: UserService; // the actually injected service - let welcomeEl: DebugElement; // the element with the welcome message + let componentUserService: UserService; // the actually injected service + let userService: UserService; // the TestBed injected service + let de: DebugElement; // the DebugElement with the welcome message + let el: HTMLElement; // the DOM element with the welcome message let userServiceStub: { isLoggedIn: boolean; @@ -32,7 +34,8 @@ describe('WelcomeComponent', () => { TestBed.configureTestingModule({ declarations: [ WelcomeComponent ], // #enddocregion setup - // providers: [ UserService ] // a real service would be a problem! + // providers: [ UserService ] // NO! Don't provide the real service! + // Provide a test-double instead // #docregion setup providers: [ {provide: UserService, useValue: userServiceStub } ] }); @@ -42,51 +45,64 @@ describe('WelcomeComponent', () => { comp = fixture.componentInstance; // #enddocregion setup - // #docregion inject-from-testbed - // UserService provided to the TestBed - userService = TestBed.get(UserService); - // #enddocregion inject-from-testbed - // #docregion setup - // #docregion injected-service + // #docregion injected-service // UserService actually injected into the component userService = fixture.debugElement.injector.get(UserService); // #enddocregion injected-service + componentUserService = userService; + // #docregion setup + // #docregion inject-from-testbed + // UserService from the root injector + userService = TestBed.get(UserService); + // #enddocregion inject-from-testbed // get the "welcome" element by CSS selector (e.g., by class name) - welcomeEl = fixture.debugElement.query(By.css('.welcome')); + de = fixture.debugElement.query(By.css('.welcome')); + el = de.nativeElement; }); // #enddocregion setup // #docregion tests it('should welcome the user', () => { - fixture.detectChanges(); // trigger data binding - - let content = welcomeEl.nativeElement.textContent; + fixture.detectChanges(); + const content = el.textContent; expect(content).toContain('Welcome', '"Welcome ..."'); expect(content).toContain('Test User', 'expected name'); }); it('should welcome "Bubba"', () => { userService.user.name = 'Bubba'; // welcome message hasn't been shown yet - - fixture.detectChanges(); // trigger data binding - - let content = welcomeEl.nativeElement.textContent; - expect(content).toContain('Bubba'); + fixture.detectChanges(); + expect(el.textContent).toContain('Bubba'); }); it('should request login if not logged in', () => { userService.isLoggedIn = false; // welcome message hasn't been shown yet - - fixture.detectChanges(); // trigger data binding - - let content = welcomeEl.nativeElement.textContent; + fixture.detectChanges(); + const content = el.textContent; expect(content).not.toContain('Welcome', 'not welcomed'); expect(content).toMatch(/log in/i, '"log in"'); }); // #enddocregion tests - it('orig stub and injected UserService are not the same object', () => { + // #docregion inject-it + it('should inject the component\'s UserService instance', + inject([UserService], (service: UserService) => { + expect(service).toBe(componentUserService); + })); + // #enddocregion inject-it + + it('TestBed and Component UserService should be the same', () => { + expect(userService === componentUserService).toBe(true); + }); + + // #docregion stub-not-injected + it('stub object and injected UserService should not be the same', () => { expect(userServiceStub === userService).toBe(false); + + // Changing the stub object has no effect on the injected service + userServiceStub.isLoggedIn = false; + expect(userService.isLoggedIn).toBe(true); }); + // #enddocregion stub-not-injected }); diff --git a/public/docs/dart/latest/cookbook/_data.json b/public/docs/dart/latest/cookbook/_data.json index 931857b846..f0c0dad0d4 100644 --- a/public/docs/dart/latest/cookbook/_data.json +++ b/public/docs/dart/latest/cookbook/_data.json @@ -60,7 +60,7 @@ "ts-to-js": { "title": "TypeScript to JavaScript", - "intro": "Convert Angular 2 TypeScript examples into ES5 JavaScript", + "intro": "Convert Angular TypeScript examples into ES5 JavaScript", "hide": true }, diff --git a/public/docs/dart/latest/guide/_data.json b/public/docs/dart/latest/guide/_data.json index f13c3c42c8..68717b46ce 100644 --- a/public/docs/dart/latest/guide/_data.json +++ b/public/docs/dart/latest/guide/_data.json @@ -10,7 +10,7 @@ "architecture": { "title": "Architecture Overview", "navTitle": "Architecture", - "intro": "The basic building blocks of Angular 2 applications", + "intro": "The basic building blocks of Angular applications", "nextable": true, "basics": true }, @@ -59,7 +59,7 @@ "style-guide": { "title": "Style Guide", - "intro": "Write Angular 2 with style.", + "intro": "Write Angular with style.", "basics": true }, @@ -92,7 +92,7 @@ "glossary": { "title": "Glossary", - "intro": "Brief definitions of the most important words in the Angular 2 vocabulary", + "intro": "Brief definitions of the most important words in the Angular vocabulary", "basics": true }, @@ -125,7 +125,7 @@ "router": { "title": "Routing & Navigation", - "intro": "Discover the basics of screen navigation with the Angular 2 Component Router." + "intro": "Discover the basics of screen navigation with the Angular Component Router." }, "security": { @@ -140,13 +140,13 @@ "testing": { "title": "Testing", - "intro": "Techniques and practices for testing an Angular 2 app", + "intro": "Techniques and practices for testing an Angular app", "hide": true }, "typescript-configuration": { "title": "TypeScript Configuration", - "intro": "TypeScript configuration for Angular 2 developers", + "intro": "TypeScript configuration for Angular developers", "hide": true }, @@ -158,7 +158,7 @@ "webpack": { "title": "Webpack: an introduction", - "intro": "Create your Angular 2 applications with a Webpack based tooling", + "intro": "Create your Angular applications with a Webpack based tooling", "hide": true } } diff --git a/public/docs/js/latest/cookbook/_data.json b/public/docs/js/latest/cookbook/_data.json index 7443923155..a5e0ca3011 100644 --- a/public/docs/js/latest/cookbook/_data.json +++ b/public/docs/js/latest/cookbook/_data.json @@ -55,7 +55,7 @@ "ts-to-js": { "title": "TypeScript to JavaScript", - "intro": "Convert Angular 2 TypeScript examples into ES5 JavaScript" + "intro": "Convert Angular TypeScript examples into ES5 JavaScript" }, "visual-studio-2015": { diff --git a/public/docs/js/latest/guide/_data.json b/public/docs/js/latest/guide/_data.json index 724711f666..72977625c0 100644 --- a/public/docs/js/latest/guide/_data.json +++ b/public/docs/js/latest/guide/_data.json @@ -10,7 +10,7 @@ "architecture": { "title": "Architecture Overview", "navTitle": "Architecture", - "intro": "The basic building blocks of Angular 2 applications", + "intro": "The basic building blocks of Angular applications", "nextable": true, "basics": true }, @@ -59,7 +59,7 @@ "style-guide": { "title": "Style Guide", - "intro": "Write Angular 2 with style.", + "intro": "Write Angular with style.", "basics": true }, @@ -86,7 +86,7 @@ "glossary": { "title": "Glossary", - "intro": "Brief definitions of the most important words in the Angular 2 vocabulary", + "intro": "Brief definitions of the most important words in the Angular vocabulary", "basics": true }, @@ -118,7 +118,7 @@ "router": { "title": "Routing & Navigation", - "intro": "Discover the basics of screen navigation with the Angular 2 router." + "intro": "Discover the basics of screen navigation with the Angular router." }, "security": { @@ -133,13 +133,13 @@ "testing": { "title": "Testing", - "intro": "Techniques and practices for testing an Angular 2 app", + "intro": "Techniques and practices for testing an Angular app", "hide": true }, "typescript-configuration": { "title": "TypeScript Configuration", - "intro": "TypeScript configuration for Angular 2 developers", + "intro": "TypeScript configuration for Angular developers", "hide": true }, @@ -150,7 +150,7 @@ "webpack": { "title": "Webpack: an introduction", - "intro": "Create your Angular 2 applications with a Webpack based tooling", + "intro": "Create your Angular applications with a Webpack based tooling", "hide": true } } diff --git a/public/docs/ts/latest/cookbook/_data.json b/public/docs/ts/latest/cookbook/_data.json index 828aece748..87e4619d56 100644 --- a/public/docs/ts/latest/cookbook/_data.json +++ b/public/docs/ts/latest/cookbook/_data.json @@ -65,7 +65,7 @@ "ts-to-js": { "title": "TypeScript to JavaScript", - "intro": "Convert Angular 2 TypeScript examples into ES5 JavaScript" + "intro": "Convert Angular TypeScript examples into ES5 JavaScript" }, "visual-studio-2015": { diff --git a/public/docs/ts/latest/guide/_data.json b/public/docs/ts/latest/guide/_data.json index 2bd99c1ca6..be61fbd4ce 100644 --- a/public/docs/ts/latest/guide/_data.json +++ b/public/docs/ts/latest/guide/_data.json @@ -10,7 +10,7 @@ "architecture": { "title": "Architecture Overview", "navTitle": "Architecture", - "intro": "The basic building blocks of Angular 2 applications", + "intro": "The basic building blocks of Angular applications", "nextable": true, "basics": true }, @@ -59,7 +59,7 @@ "style-guide": { "title": "Style Guide", - "intro": "Write Angular 2 with style.", + "intro": "Write Angular with style.", "basics": true }, @@ -90,7 +90,7 @@ "glossary": { "title": "Glossary", - "intro": "Brief definitions of the most important words in the Angular 2 vocabulary", + "intro": "Brief definitions of the most important words in the Angular vocabulary", "basics": true }, @@ -122,7 +122,7 @@ "router": { "title": "Routing & Navigation", - "intro": "Discover the basics of screen navigation with the Angular 2 Router." + "intro": "Discover the basics of screen navigation with the Angular Router." }, "security": { @@ -137,12 +137,12 @@ "testing": { "title": "Testing", - "intro": "Techniques and practices for testing an Angular 2 app" + "intro": "Techniques and practices for testing an Angular app" }, "typescript-configuration": { "title": "TypeScript Configuration", - "intro": "TypeScript configuration for Angular 2 developers" + "intro": "TypeScript configuration for Angular developers" }, "upgrade": { @@ -152,6 +152,6 @@ "webpack": { "title": "Webpack: an introduction", - "intro": "Create your Angular 2 applications with a Webpack based tooling" + "intro": "Create your Angular applications with a Webpack based tooling" } } diff --git a/public/docs/ts/latest/guide/testing.jade b/public/docs/ts/latest/guide/testing.jade index 7889cb668b..abea24721d 100644 --- a/public/docs/ts/latest/guide/testing.jade +++ b/public/docs/ts/latest/guide/testing.jade @@ -9,7 +9,7 @@ block includes :marked This chapter offers tips and techniques for testing Angular applications. Along the way you will learn some general testing principles and techniques but the focus is on - Angular testing. + testing applications written with Angular #top :marked @@ -21,17 +21,20 @@ block includes - [npm packages](#npm-packages) 1. [The first karma test](#1st-karma-test)

- 1. [The Angular Testing Platform (ATP) ](#atp-intro) + 1. [Introduction to the Angular testing utilities](#atu-intro)

1. [The sample application and its tests](#sample-app)

1. [A simple component test](#simple-component-test) - [_configureTestingModule_](#configure-testing-module) - [_createComponent_](#create-component) + - [_ComponentFixture_, _DebugElement_, _query(By.css)_](#component-fixture) - [_detectChanges_](#detect-changes) - [_autoDetectChanges_](#auto-detect-changes) 1. [Test a component with a service dependency](#component-with-dependency) -

+ - [test doubles](#service-test-doubles) + - [get the injected service](#get-injected-service) + - [_TestBed.get_](#testbed-get) 1. [Test a component with an async service](#component-with-async-service) - [spies](#service-spy) - [_async_](#async) @@ -64,12 +67,12 @@ block includes

1. [Test an attribute directive](#attribute-directive)

- 1. [Isolated tests](#testing-without-atp "Testing without the Angular Testing Platform") + 1. [Isolated unit tests](#isolated-unit-tests "Unit testing without the Angular testing utilities") - [Services](#isolated-service-tests) - [Pipes](#isolated-pipe-tests) - [Components](#isolated-component-tests) - 1. [_Angular Testing Platform_ API](#atp-api) - - [Stand-alone functions](#atp-api): `async`, `fakeAsync`, etc. + 1. [Angular testing utility APIs](#atu-apis) + - [Stand-alone functions](#atu-apis): `async`, `fakeAsync`, etc. - [_TestBed_](#testbed-class-summary) - [_ComponentFixture_](#component-fixture-class-summary) - [_DebugElement_](#debug-element-details) @@ -102,9 +105,6 @@ a(href="#top").to-top Back to top When a part of the application seems hard to test, the root cause is often a design flaw, something to cure now rather than later when it becomes expensive to fix. - This chapter assumes that you know something about testing. Don't worry if you don't. - There are plenty of books and online resources to get up to speed. -