diff --git a/public/docs/ts/latest/guide/testing.jade b/public/docs/ts/latest/guide/testing.jade index 0014c5e3fa..dc4e9e873a 100644 --- a/public/docs/ts/latest/guide/testing.jade +++ b/public/docs/ts/latest/guide/testing.jade @@ -11,7 +11,7 @@ block includes Along the way you will learn some general testing principles and techniques but the focus is on Angular testing. -a#top +#top :marked # Table of Contents 1. [Introduction to Angular Testing](#testing-intro) @@ -83,7 +83,7 @@ a#top a(href="#top").to-top Back to top .l-hr -a#testing-intro +#testing-intro :marked # Introduction to Angular Testing @@ -154,7 +154,7 @@ table(width="100%") and assert that the application responds in the browser as expected. .l-hr -a#setup +#setup :marked # Setup @@ -184,7 +184,7 @@ a#setup you can skip the rest of this section and get on with your first test. The QuickStart repo provides all necessary setup. -a#setup-files +#setup-files :marked ### Setup files Here's brief description of the setup files. @@ -247,7 +247,7 @@ table(width="100%") They were installed when you ran `npm install`. .l-hr -a#1st-karma-test +#1st-karma-test :marked # The first karma test @@ -368,7 +368,7 @@ figure.image-display a(href="#top").to-top Back to top .l-hr -a#atp-intro +#atp-intro :marked # The Angular Testing Platform (ATP) @@ -439,7 +439,7 @@ a(href="#top").to-top Back to top .l-hr -a#sample-app +#sample-app :marked # The sample application and its tests @@ -460,7 +460,7 @@ a#sample-app a(href="#top").to-top Back to top .l-hr -a#simple-component-test +#simple-component-test :marked # Test a component @@ -476,7 +476,7 @@ a#simple-component-test Start with ES6 import statements to get access to symbols referenced in the spec. +makeExample('testing/ts/app/banner.component.spec.ts', 'imports', 'app/banner.component.spec.ts (imports)')(format='.') -a#configure-testing-module +#configure-testing-module :marked Here's the setup for the tests followed by observations about the `beforeEach`: +makeExample('testing/ts/app/banner.component.spec.ts', 'setup', 'app/banner.component.spec.ts (setup)')(format='.') @@ -492,7 +492,7 @@ a#configure-testing-module But that would lead to tons more configuration in order to support the other components within `AppModule` that have nothing to do with `BannerComponent`. -a#create-component +#create-component :marked `TestBed.createComponent` creates an instance of `BannerComponent` to test. The method returns a `ComponentFixture`, a handle on the test environment surrounding the created component. @@ -516,7 +516,7 @@ a#create-component :markdown These tests ask the `DebugElement` for the native HTML element to satisfy their expectations. -a#detect-changes +#detect-changes :marked ### _detectChanges_: Angular change detection under test @@ -540,7 +540,7 @@ a#detect-changes It gives the tester an opportunity to investigate the state of the component _before Angular initiates data binding or calls lifecycle hooks_. -a#auto-detect-changes +#auto-detect-changes :marked ### Automatic change detection Some testers prefer that the Angular test environment run change detection automatically. @@ -570,7 +570,7 @@ a(href="#top").to-top Back to top .l-hr -a#component-with-dependency +#component-with-dependency :marked # Test a component with a dependency Components often have service dependencies. @@ -605,7 +605,7 @@ a#component-with-dependency and its tests: +makeExample('testing/ts/app/welcome.component.spec.ts', 'user-service-stub')(format='.') -a#injected-service-reference +#injected-service-reference :marked ## Referencing injected services The tests need access to the injected (stubbed) `UserService`. @@ -641,7 +641,7 @@ a#injected-service-reference .alert.is-important :marked Use the component's own injector to get the component's injected service. -a#welcome-spec-setup +#welcome-spec-setup :marked Here's the complete, preferred `beforeEach`: +makeExample('testing/ts/app/welcome.component.spec.ts', 'setup', 'app/welcome.component.spec.ts')(format='.') @@ -658,7 +658,7 @@ a(href="#top").to-top Back to top .l-hr -a#component-with-async-service +#component-with-async-service :marked # Test a component with an async service Many services return values asynchronously. @@ -677,7 +677,7 @@ a#component-with-async-service They should emulate such calls. The setup in this `app/shared/twain.component.spec.ts` shows one way to do that: +makeExample('testing/ts/app/shared/twain.component.spec.ts', 'setup', 'app/shared/twain.component.spec.ts (setup)')(format='.') -a#service-spy +#service-spy :marked ### Spying on the real service @@ -709,7 +709,7 @@ a#service-spy The test must become an "async test" ... like the third test -a#async +#async :marked ## The _async_ function in _it_ @@ -731,7 +731,7 @@ a#async Some functions called within a test (such as `fixture.whenStable`) continue to reveal their asynchronous behavior. Consider also the [_fakeAsync_](#fake-async) alternative which affords a more linear coding experience. -a#when-stable +#when-stable :marked ## _whenStable_ The test must wait for the `getQuote` promise to resolve. @@ -754,8 +754,8 @@ a#when-stable The test kicks off another round of change detection (`fixture.detechChanges`) which tells Angular to update the DOM with the quote. The `getQuote` helper method extracts the display element text and the expectation confirms that the text matches the test quote. -a#fakeAsync -a#fake-async +#fakeAsync +#fake-async :marked ## The _fakeAsync_ function @@ -776,8 +776,8 @@ a#fake-async There are limitations. For example, you cannot make an XHR call from within a `fakeAsync`. -a#tick -a#tick-first-look +#tick +#tick-first-look :marked ## The _tick_ function Compare the third and fourth tests. Notice that `fixture.whenStable` is gone, replaced by `tick()`. @@ -795,7 +795,7 @@ a#tick-first-look To more fully appreciate the improvement, imagine a succession of asynchronous operations, chained in a long sequence of promise callbacks. -a#jasmine-done +#jasmine-done :marked ## _jasmine.done_ @@ -819,7 +819,7 @@ a(href="#top").to-top Back to top .l-hr -a#component-with-external-template +#component-with-external-template :marked # Test a component with an external template The `TestBed.createComponent` is a synchronous method. @@ -847,7 +847,7 @@ a#component-with-external-template The `app/dashboard/dashboard-hero.component.spec.ts` demonstrates the pre-compilation process: +makeExample('testing/ts/app/dashboard/dashboard-hero.component.spec.ts', 'compile-components', 'app/dashboard/dashboard-hero.component.spec.ts (compileComponents)')(format='.') -a#async-in-before-each +#async-in-before-each :marked ## The _async_ function in _beforeEach_ @@ -855,7 +855,7 @@ a#async-in-before-each The `async` function arranges for the tester's code to run in a special _async test zone_ that hides the mechanics of asynchronous execution, just as it does when passed to an [_it_ test)(#async). -a#compile-components +#compile-components :marked ## _compileComponents_ In this example, `Testbed.compileComponents` compiles one component, the `DashboardComponent`. @@ -884,7 +884,7 @@ a#compile-components .l-hr -a#component-with-inputs-outputs +#component-with-inputs-outputs :marked # Test a component with inputs and outputs A component with inputs and outputs typically appears inside the view template of a host component. @@ -971,7 +971,7 @@ a#component-with-inputs-outputs .l-hr -a#component-inside-test-host +#component-inside-test-host :marked # Test a component inside a test host component @@ -1015,7 +1015,7 @@ a(href="#top").to-top Back to top .l-hr -a#routed-component +#routed-component :marked # Test a routed component @@ -1041,7 +1041,7 @@ a#routed-component The following test clicks the displayed hero and confirms (with the help of a spy) that `Router.navigateByUrl` is called with the expected url. +makeExample('testing/ts/app/dashboard/dashboard.component.spec.ts', 'navigate-test', 'app/dashboard/dashboard.component.spec.ts (navigate test)')(format='.') -a#inject +#inject :marked ## The _inject_ function @@ -1083,7 +1083,7 @@ a(href="#top").to-top Back to top .l-hr -a#routed-component-w-param +#routed-component-w-param :marked # Test a routed component with parameters @@ -1117,7 +1117,7 @@ a#routed-component-w-param By now you know how to stub the `Router` and a data service. Stubbing the `ActivatedRoute` would follow the same pattern except for a complication: the `ActivatedRoute.params` is an _Observable_. -a#stub-observable +#stub-observable :marked ### _Observable_ test double @@ -1148,7 +1148,7 @@ a#stub-observable :marked The router stubs in this chapter are meant to inspire you. Create your own stubs to fit your testing needs. -a#observable-tests +#observable-tests :marked ### _Observable_ tests Here's a test demonstrating the component's behavior when the observed `id` refers to an existing hero: @@ -1177,7 +1177,7 @@ a#observable-tests .l-hr -a#page-object +#page-object :marked # Use a _page_ object to simplify setup @@ -1214,24 +1214,23 @@ figure.image-display a(href="#top").to-top Back to top .l-hr -a#router-outlet-component +#router-outlet-component :marked # Test a _RouterOutlet_ component The `AppComponent` displays routed components in a ``. It also displays a navigation bar with anchors and their `RouterLink` directives. -a#app-component-html +#app-component-html +makeExample('testing/ts/app/app.component.html', '', 'app/app.component.html')(format='.') :marked The component class does nothing. +makeExample('testing/ts/app/app.component.ts', '', 'app/app.component.ts')(format='.') -.l-sub-section - :marked - This component may not seem worth testing but it's instructive to show how to test it. + :marked Unit tests can confirm that the anchors are wired properly without engaging the router. + See why this is worth doing [below](#why-stubbed-routerlink-tests). -a#stub-component +#stub-component :marked ### Stubbing unneeded components @@ -1251,7 +1250,7 @@ a#stub-component The component stubs are essential. Without them, the Angular compiler doesn't recognize the `` and `` tags and throws an error. -a#router-link-stub +#router-link-stub :marked ### Stubbing the _RouterLink_ @@ -1263,8 +1262,8 @@ a#router-link-stub Clicking the anchor should trigger the `onClick` method which sets the telltale `navigatedTo` property. Tests can inspect that property to confirm the expected _click-to-navigation_ behavior. -a#by-directive -a#inject-directive +#by-directive +#inject-directive :marked ### _By.directive_ and injected directives @@ -1278,7 +1277,7 @@ a#inject-directive 1. You can use the component's dependency injector to get an attached directive because Angular always adds attached directives to the component's injector. -a#app-component-tests +#app-component-tests :marked Here are some tests that leverage this setup: +makeExample('testing/ts/app/app.component.spec.ts', 'tests', 'app/app.component.spec.ts (selected tests)')(format='.') @@ -1295,10 +1294,28 @@ a#app-component-tests This is a skill you may need to test a more sophisticated component, one that changes the display, re-calculates parameters, or re-arranges navigation options when the user clicks the link. +#why-stubbed-routerlink-tests +:marked + ### What good are these tests? + + Stubbed `RouterLink` tests can confirm that a component with links and an outlet is setup properly, + that the component has the links it should have and + that they are all pointing in the expected direction. + These tests do not concern whether the app will succeed in navigating to the target component when the user clicks a link. + + Stubbing the RouterLink and RouterOutlet is the best option for such limited testing goals. + Relying on the real router would make them brittle. + They could fail for reasons unrelated to the component. + For example, a navigation guard could prevent an unauthorized user from visiting the `HeroListComponent`. + That's not the fault of the `AppComponent` and no change to that component could cure the failed test. + + A _different_ battery of tests can explore whether the application navigates as expected + in the presence of conditions that influence guards such as whether the user is authenticated and authorized. + A future chapter update will explain how to write such tests with the `RouterTestingModule`. a(href="#top").to-top Back to top .l-hr -a#shallow-component-test +#shallow-component-test :marked # "Shallow component tests" with *NO\_ERRORS\_SCHEMA* @@ -1332,7 +1349,7 @@ a(href="#top").to-top Back to top .l-hr -a#attribute-directive +#attribute-directive :marked # Test an attribute directive @@ -1392,8 +1409,8 @@ a(href="#top").to-top Back to top .l-hr -a#isolated-tests -a#testing-without-atp +#isolated-tests +#testing-without-atp :marked # Testing without the Angular Testing Platform @@ -1423,7 +1440,7 @@ a#testing-without-atp Write _Angular_ tests to validate the part as it interacts with Angular, updates the DOM, and collaborates with the rest of the application. -a#isolated-service-tests +#isolated-service-tests :marked ## Services Services are good candidates for isolated unit testing. @@ -1474,7 +1491,7 @@ a#isolated-service-tests Use the Angular Testing Platform when writing tests that validate how a service interacts with components _within the Angular runtime environment_. -a#isolated-pipe-tests +#isolated-pipe-tests :marked ## Pipes Pipes are easy to test without the Angular Testing Platform (ATP). @@ -1500,7 +1517,7 @@ a#isolated-pipe-tests Consider adding ATP component tests such as this one. +makeExample('testing/ts/app/hero/hero-detail.component.spec.ts', 'title-case-pipe', 'app/hero/hero-detail.component.spec.ts (pipe test)') -a#isolated-component-tests +#isolated-component-tests :marked ## Components @@ -1537,7 +1554,7 @@ a(href="#top").to-top Back to top .l-hr -a#atp-api +#atp-api :marked # Angular Testing Platform APIs @@ -1629,7 +1646,7 @@ table .l-hr -a#testbed-class-summary +#testbed-class-summary :marked # _TestBed_ Class Summary The `TestBed` class is a principle feature of the _Angular Testing Platform_. @@ -1659,7 +1676,7 @@ code-example(format="." language="javascript"). }; :marked -a#testbed-methods +#testbed-methods :marked The `TestBed` API consists of static class methods that either update or reference a _global_ instance of the`TestBed`. @@ -1677,7 +1694,7 @@ table td :marked The testing shims (`karma-test-shim`, `browser-test-shim`) - establish the [initial test environment](#a#testbed-initTestEnvironment) and a default testing module. + establish the [initial test environment](##testbed-initTestEnvironment) and a default testing module. The default testing module is configured with basic declaratives and some Angular service substitutes (e.g. `DebugDomRender`) that every tester needs. @@ -1771,7 +1788,7 @@ table A few of the `TestBed` instance methods are not covered by static `TestBed` _class_ methods. These are rarely needed. -a#component-fixture-api-summary +#component-fixture-api-summary :marked ## The _ComponentFixture_ @@ -1782,7 +1799,7 @@ a#component-fixture-api-summary The `ComponentFixture` properties and methods provide access to the component, its DOM representation, and aspects of its Angular environment. -a#component-fixture-properties +#component-fixture-properties :marked ### _ComponentFixture_ properties @@ -1820,7 +1837,7 @@ table component that has the `ChangeDetectionStrategy.OnPush` or the component's change detection is under your programmatic control. -a#component-fixture-methods +#component-fixture-methods :marked ### _ComponentFixture_ methods @@ -1887,7 +1904,7 @@ table :marked Trigger component destruction. -a#debug-element-details +#debug-element-details :marked ### _DebugElement_ @@ -2003,7 +2020,7 @@ table Dictionary of objects associated with template local variables (e.g. `#foo`), keyed by the local variable name. -a#query-predicate +#query-predicate :marked The `DebugElement.query(predicate)` and `DebugElement.queryAll(predicate)` methods take a predicate that filters the source element's subtree for matching `DebugElement`. @@ -2020,7 +2037,7 @@ a#query-predicate +makeExample('testing/ts/app/hero/hero-list.component.spec.ts', 'by', 'app/hero/hero-list.component.spec.ts')(format=".") -a#renderer-tests +#renderer-tests :marked Many custom application directives inject the `Renderer` and call one of its `set...` methods. @@ -2068,7 +2085,7 @@ a(href="#top").to-top Back to top .l.hr - a#faq + #faq .l-main-section :marked ## FAQ: Frequently Asked Questions @@ -2106,7 +2123,7 @@ a(href="#top").to-top Back to top .l-hr -a#q-spec-file-location +#q-spec-file-location :marked ### Why put specs next to the things they test? @@ -2120,7 +2137,7 @@ a#q-spec-file-location .l-hr -a#q-specs-in-test-folder +#q-specs-in-test-folder :marked ### When would I put specs in a test folder?