style: fix whitespace and indentation in the testing guide (#21669)

PR Close #21669
This commit is contained in:
Igor Minar 2018-08-07 15:52:48 -07:00 committed by Kara Erickson
parent ebf508fcd0
commit 74518c4b2e
2 changed files with 373 additions and 371 deletions

View File

@ -6,8 +6,8 @@ This guide offers tips and techniques for unit and integration testing Angular a
The guide presents tests of a sample CLI application that is much like the [_Tour of Heroes_ tutorial](tutorial). The guide presents tests of a sample CLI application that is much like the [_Tour of Heroes_ tutorial](tutorial).
The sample application and all tests in this guide are available for inspection and experimentation: The sample application and all tests in this guide are available for inspection and experimentation:
* <live-example embedded-style>Sample app</live-example> - <live-example embedded-style>Sample app</live-example>
* <live-example stackblitz="specs">Tests</live-example> - <live-example stackblitz="specs">Tests</live-example>
<hr> <hr>
@ -84,7 +84,7 @@ The test file extension **must be `.spec.ts`** so that tooling can identify it a
</div> </div>
The `app.component.ts` and `app.component.spec.ts` files are siblings in the same folder. The `app.component.ts` and `app.component.spec.ts` files are siblings in the same folder.
The root file names (`app.component`) are the same for both files. The root file names (`app.component`) are the same for both files.
Adopt these two conventions in your own projects for _every kind_ of test file. Adopt these two conventions in your own projects for _every kind_ of test file.
@ -153,7 +153,7 @@ when you use the `TestBed` testing utility to provide and create services.
#### Angular _TestBed_ #### Angular _TestBed_
The `TestBed` is the most important of the Angular testing utilities. The `TestBed` is the most important of the Angular testing utilities.
The `TestBed` creates a dynamically-constructed Angular _test_ module that emulates The `TestBed` creates a dynamically-constructed Angular _test_ module that emulates
an Angular [@NgModule](guide/ngmodules). an Angular [@NgModule](guide/ngmodules).
@ -403,11 +403,11 @@ respond to user input and gestures, or integrate with its parent and child compo
None of the _class-only_ tests above can answer key questions about how the None of the _class-only_ tests above can answer key questions about how the
components actually behave on screen. components actually behave on screen.
* Is `Lightswitch.clicked()` bound to anything such that the user can invoke it? - Is `Lightswitch.clicked()` bound to anything such that the user can invoke it?
* Is the `Lightswitch.message` displayed? - Is the `Lightswitch.message` displayed?
* Can the user actually select the hero displayed by `DashboardHeroComponent`? - Can the user actually select the hero displayed by `DashboardHeroComponent`?
* Is the hero name displayed as expected (i.e, in uppercase)? - Is the hero name displayed as expected (i.e, in uppercase)?
* Is the welcome message displayed by the template of `WelcomeComponent`? - Is the welcome message displayed by the template of `WelcomeComponent`?
These may not be troubling questions for the simple components illustrated above. These may not be troubling questions for the simple components illustrated above.
But many components have complex interactions with the DOM elements But many components have complex interactions with the DOM elements
@ -625,7 +625,7 @@ For example, the component might render first on the server as part of a strateg
If it doesn't support `querySelector`, the previous test could fail. If it doesn't support `querySelector`, the previous test could fail.
The `DebugElement` offers query methods that work for all supported platforms. The `DebugElement` offers query methods that work for all supported platforms.
These query methods take a _predicate_ function that returns `true` when a node in the `DebugElement` tree matches the selection criteria. These query methods take a _predicate_ function that returns `true` when a node in the `DebugElement` tree matches the selection criteria.
You create a _predicate_ with the help of a `By` class imported from a You create a _predicate_ with the help of a `By` class imported from a
library for the runtime platform. Here's the `By` import for the browser platform: library for the runtime platform. Here's the `By` import for the browser platform:
@ -645,10 +645,10 @@ The following example re-implements the previous test with
Some noteworthy observations: Some noteworthy observations:
* The `By.css()` static method selects `DebugElement` nodes - The `By.css()` static method selects `DebugElement` nodes
with a [standard CSS selector](https://developer.mozilla.org/en-US/docs/Web/Guide/CSS/Getting_started/Selectors "CSS selectors"). with a [standard CSS selector](https://developer.mozilla.org/en-US/docs/Web/Guide/CSS/Getting_started/Selectors 'CSS selectors').
* The query returns a `DebugElement` for the paragraph. - The query returns a `DebugElement` for the paragraph.
* You must unwrap that result to get the paragraph element. - You must unwrap that result to get the paragraph element.
When you're filtering by CSS selector and only testing properties of a browser's _native element_, the `By.css` approach may be overkill. When you're filtering by CSS selector and only testing properties of a browser's _native element_, the `By.css` approach may be overkill.
@ -706,6 +706,7 @@ Your instinct is to write a test that immediately inspects the `<h1>` like this:
</code-example> </code-example>
_That test fails_ with the message: _That test fails_ with the message:
```javascript ```javascript
expected '' to contain 'Test Tour of Heroes'. expected '' to contain 'Test Tour of Heroes'.
``` ```
@ -739,7 +740,6 @@ the component _before Angular initiates data binding and calls [lifecycle hooks]
Here's another test that changes the component's `title` property _before_ calling `fixture.detectChanges()`. Here's another test that changes the component's `title` property _before_ calling `fixture.detectChanges()`.
<code-example <code-example
path="testing/src/app/banner/banner.component.spec.ts" path="testing/src/app/banner/banner.component.spec.ts"
region="after-change"> region="after-change">
@ -1051,6 +1051,7 @@ The test must wait at least one full turn of the JavaScript engine before the
value becomes available. The test must become _asynchronous_. value becomes available. The test must become _asynchronous_.
{@a fake-async} {@a fake-async}
#### Async test with _fakeAsync()_ #### Async test with _fakeAsync()_
The following test confirms the expected behavior when the service returns an `ErrorObservable`. The following test confirms the expected behavior when the service returns an `ErrorObservable`.
@ -1061,6 +1062,7 @@ The following test confirms the expected behavior when the service returns an `E
</code-example> </code-example>
Note that the `it()` function receives an argument of the following form. Note that the `it()` function receives an argument of the following form.
```javascript ```javascript
fakeAsync(() => { /* test body */ })` fakeAsync(() => { /* test body */ })`
``` ```
@ -1261,7 +1263,6 @@ But it is occasionally necessary.
For example, you can't call `async` or `fakeAsync` when testing For example, you can't call `async` or `fakeAsync` when testing
code that involves the `intervalTimer()` or the RxJS `delay()` operator. code that involves the `intervalTimer()` or the RxJS `delay()` operator.
Here are two mover versions of the previous test, written with `done()`. Here are two mover versions of the previous test, written with `done()`.
The first one subscribes to the `Observable` exposed to the template by the component's `quote` property. The first one subscribes to the `Observable` exposed to the template by the component's `quote` property.
@ -1393,7 +1394,6 @@ A _hot_ observable is already producing values _before_ you subscribe to it.
The [_Router.events_](api/router/Router#events) observable, The [_Router.events_](api/router/Router#events) observable,
which reports router activity, is a _hot_ observable. which reports router activity, is a _hot_ observable.
RxJS marble testing is a rich subject, beyond the scope of this guide. RxJS marble testing is a rich subject, beyond the scope of this guide.
Learn about it on the web, starting with the Learn about it on the web, starting with the
[official documentation](https://github.com/ReactiveX/rxjs/blob/master/doc/writing-marble-tests.md). [official documentation](https://github.com/ReactiveX/rxjs/blob/master/doc/writing-marble-tests.md).
@ -1439,9 +1439,9 @@ Here's the component's full definition:
While testing a component this simple has little intrinsic value, it's worth knowing how. While testing a component this simple has little intrinsic value, it's worth knowing how.
You can use one of these approaches: You can use one of these approaches:
* Test it as used by `DashboardComponent`. - Test it as used by `DashboardComponent`.
* Test it as a stand-alone component. - Test it as a stand-alone component.
* Test it as used by a substitute for `DashboardComponent`. - Test it as used by a substitute for `DashboardComponent`.
A quick look at the `DashboardComponent` constructor discourages the first approach: A quick look at the `DashboardComponent` constructor discourages the first approach:
@ -1561,6 +1561,7 @@ which is perfectly fine for _this component_.
</code-example> </code-example>
{@a click-helper} {@a click-helper}
#### _click()_ helper #### _click()_ helper
Clicking a button, an anchor, or an arbitrary HTML element is a common test task. Clicking a button, an anchor, or an arbitrary HTML element is a common test task.
@ -1756,10 +1757,11 @@ by manipulating the `ActivatedRoute` injected into the component's constructor.
You know how to spy on the `Router` and a data service. You know how to spy on the `Router` and a data service.
You'll take a different approach with `ActivatedRoute` because You'll take a different approach with `ActivatedRoute` because
* `paramMap` returns an `Observable` that can emit more than one value
during a test. - `paramMap` returns an `Observable` that can emit more than one value
* You need the router helper function, `convertToParamMap()`, to create a `ParamMap`. during a test.
* Other _routed components_ tests need a test double for `ActivatedRoute`. - You need the router helper function, `convertToParamMap()`, to create a `ParamMap`.
- Other _routed components_ tests need a test double for `ActivatedRoute`.
These differences argue for a re-usable stub class. These differences argue for a re-usable stub class.
@ -1778,8 +1780,8 @@ This sample puts `ActivatedRouteStub` in `testing/activated-route-stub.ts`.
<div class="alert is-helpful"> <div class="alert is-helpful">
Consider writing a more capable version of this stub class with Consider writing a more capable version of this stub class with
the [_marble testing library_](#marble-testing). the [_marble testing library_](#marble-testing).
</div> </div>
@ -1895,7 +1897,7 @@ The rest are stubs.
{@a no-errors-schema} {@a no-errors-schema}
#### *NO\_ERRORS\_SCHEMA* #### _NO_ERRORS_SCHEMA_
In the second approach, add `NO_ERRORS_SCHEMA` to the `TestBed.schemas` metadata. In the second approach, add `NO_ERRORS_SCHEMA` to the `TestBed.schemas` metadata.
@ -1924,7 +1926,7 @@ in the component's template that matter for tests.
The `NO_ERRORS_SCHEMA` approach is the easier of the two but don't overuse it. The `NO_ERRORS_SCHEMA` approach is the easier of the two but don't overuse it.
The `NO_ERRORS_SCHEMA` also prevents the compiler from telling you about the missing The `NO_ERRORS_SCHEMA` also prevents the compiler from telling you about the missing
components and attributes that you omitted inadvertently or misspelled. components and attributes that you omitted inadvertently or misspelled.
You could waste hours chasing phantom bugs that the compiler would have caught in an instant. You could waste hours chasing phantom bugs that the compiler would have caught in an instant.
@ -1997,12 +1999,12 @@ A little more setup triggers the initial data binding and gets references to the
Three points of special interest: Three points of special interest:
1. You can locate the anchor elements with an attached directive using `By.directive`. 1. You can locate the anchor elements with an attached directive using `By.directive`.
1. The query returns `DebugElement` wrappers around the matching elements. 1. The query returns `DebugElement` wrappers around the matching elements.
1. Each `DebugElement` exposes a dependency injector with the 1. Each `DebugElement` exposes a dependency injector with the
specific instance of the directive attached to that element. specific instance of the directive attached to that element.
The `AppComponent` links to validate are as follows: The `AppComponent` links to validate are as follows:
@ -2077,11 +2079,11 @@ But there's plenty of template complexity even in this simple form.
Tests that exercise the component need ... Tests that exercise the component need ...
* to wait until a hero arrives before elements appear in the DOM. - to wait until a hero arrives before elements appear in the DOM.
* a reference to the title text. - a reference to the title text.
* a reference to the name input box to inspect and set it. - a reference to the name input box to inspect and set it.
* references to the two buttons so they can click them. - references to the two buttons so they can click them.
* spies for some of the component and router methods. - spies for some of the component and router methods.
Even a small form such as this one can produce a mess of tortured conditional setup and CSS element selection. Even a small form such as this one can produce a mess of tortured conditional setup and CSS element selection.
@ -2187,8 +2189,8 @@ Error: ViewDestroyedError: Attempt to use a destroyed view
A typical approach is to divide the setup logic into two separate `beforeEach()` functions: A typical approach is to divide the setup logic into two separate `beforeEach()` functions:
1. An async `beforeEach()` that compiles the components 1. An async `beforeEach()` that compiles the components
1. A synchronous `beforeEach()` that performs the remaining setup. 1. A synchronous `beforeEach()` that performs the remaining setup.
To follow this pattern, import the `async()` helper with the other testing symbols. To follow this pattern, import the `async()` helper with the other testing symbols.
@ -2293,10 +2295,10 @@ which means you can also specify `providers` and `imports`.
The `HeroDetailComponent` requires a lot of help despite its small size and simple construction. The `HeroDetailComponent` requires a lot of help despite its small size and simple construction.
In addition to the support it receives from the default testing module `CommonModule`, it needs: In addition to the support it receives from the default testing module `CommonModule`, it needs:
* `NgModel` and friends in the `FormsModule` to enable two-way data binding. - `NgModel` and friends in the `FormsModule` to enable two-way data binding.
* The `TitleCasePipe` from the `shared` folder. - The `TitleCasePipe` from the `shared` folder.
* Router services (which these tests are stubbing). - Router services (which these tests are stubbing).
* Hero data access services (also stubbed). - Hero data access services (also stubbed).
One approach is to configure the testing module from the individual pieces as in this example: One approach is to configure the testing module from the individual pieces as in this example:
@ -2423,7 +2425,7 @@ The [override metadata object](#metadata-override-object) is a generic defined a
A metadata override object can either add-and-remove elements in metadata properties or completely reset those properties. A metadata override object can either add-and-remove elements in metadata properties or completely reset those properties.
This example resets the component's `providers` metadata. This example resets the component's `providers` metadata.
The type parameter, `T`, is the kind of metadata you'd pass to the `@Component` decorator: The type parameter, `T`, is the kind of metadata you'd pass to the `@Component` decorator:
<code-example format="." language="javascript"> <code-example format="." language="javascript">
selector?: string; selector?: string;
@ -2523,20 +2525,20 @@ Here are some tests of this component:
A few techniques are noteworthy: A few techniques are noteworthy:
* The `By.directive` predicate is a great way to get the elements that have this directive _when their element types are unknown_. - The `By.directive` predicate is a great way to get the elements that have this directive _when their element types are unknown_.
* The <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/:not">`:not` pseudo-class</a> - The <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/:not">`:not` pseudo-class</a>
in `By.css('h2:not([highlight])')` helps find `<h2>` elements that _do not_ have the directive. in `By.css('h2:not([highlight])')` helps find `<h2>` elements that _do not_ have the directive.
`By.css('*:not([highlight])')` finds _any_ element that does not have the directive. `By.css('*:not([highlight])')` finds _any_ element that does not have the directive.
* `DebugElement.styles` affords access to element styles even in the absence of a real browser, thanks to the `DebugElement` abstraction. - `DebugElement.styles` affords access to element styles even in the absence of a real browser, thanks to the `DebugElement` abstraction.
But feel free to exploit the `nativeElement` when that seems easier or more clear than the abstraction. But feel free to exploit the `nativeElement` when that seems easier or more clear than the abstraction.
* Angular adds a directive to the injector of the element to which it is applied. - Angular adds a directive to the injector of the element to which it is applied.
The test for the default color uses the injector of the second `<h2>` to get its `HighlightDirective` instance The test for the default color uses the injector of the second `<h2>` to get its `HighlightDirective` instance
and its `defaultColor`. and its `defaultColor`.
* `DebugElement.properties` affords access to the artificial custom property that is set by the directive. - `DebugElement.properties` affords access to the artificial custom property that is set by the directive.
<hr> <hr>
@ -2579,13 +2581,13 @@ Consider adding component tests such as this one:
Debug specs in the browser in the same way that you debug an application. Debug specs in the browser in the same way that you debug an application.
1. Reveal the karma browser window (hidden earlier). 1. Reveal the karma browser window (hidden earlier).
1. Click the **DEBUG** button; it opens a new browser tab and re-runs the tests. 1. Click the **DEBUG** button; it opens a new browser tab and re-runs the tests.
1. Open the browser's “Developer Tools” (`Ctrl-Shift-I` on windows; `Command-Option-I` in OSX). 1. Open the browser's “Developer Tools” (`Ctrl-Shift-I` on windows; `Command-Option-I` in OSX).
1. Pick the "sources" section. 1. Pick the "sources" section.
1. Open the `1st.spec.ts` test file (Control/Command-P, then start typing the name of the file). 1. Open the `1st.spec.ts` test file (Control/Command-P, then start typing the name of the file).
1. Set a breakpoint in the test. 1. Set a breakpoint in the test.
1. Refresh the browser, and it stops at the breakpoint. 1. Refresh the browser, and it stops at the breakpoint.
<figure> <figure>
<img src='generated/images/guide/testing/karma-1st-spec-debug.png' alt="Karma debugging"> <img src='generated/images/guide/testing/karma-1st-spec-debug.png' alt="Karma debugging">
@ -2958,7 +2960,6 @@ Here are the most important static methods, in order of likely utility.
</tr> </tr>
</table </table
A few of the `TestBed` instance methods are not covered by static `TestBed` _class_ methods. A few of the `TestBed` instance methods are not covered by static `TestBed` _class_ methods.
These are rarely needed. These are rarely needed.
@ -3382,9 +3383,9 @@ The following example finds all `DebugElements` with a reference to a template l
The Angular `By` class has three static methods for common predicates: The Angular `By` class has three static methods for common predicates:
* `By.all` - return all elements. - `By.all` - return all elements.
* `By.css(selector)` - return elements with matching CSS selectors. - `By.css(selector)` - return elements with matching CSS selectors.
* `By.directive(directive)` - return elements that Angular matched to an instance of the directive class. - `By.directive(directive)` - return elements that Angular matched to an instance of the directive class.
<code-example path="testing/src/app/hero/hero-list.component.spec.ts" region="by" title="app/hero/hero-list.component.spec.ts" linenums="false"></code-example> <code-example path="testing/src/app/hero/hero-list.component.spec.ts" region="by" title="app/hero/hero-list.component.spec.ts" linenums="false"></code-example>
@ -3401,11 +3402,11 @@ The Angular `By` class has three static methods for common predicates:
It's a good idea to put unit test spec files in the same folder It's a good idea to put unit test spec files in the same folder
as the application source code files that they test: as the application source code files that they test:
* Such tests are easy to find. - Such tests are easy to find.
* You see at a glance if a part of your application lacks tests. - You see at a glance if a part of your application lacks tests.
* Nearby tests can reveal how a part works in context. - Nearby tests can reveal how a part works in context.
* When you move the source (inevitable), you remember to move the test. - When you move the source (inevitable), you remember to move the test.
* When you rename the source file (inevitable), you remember to rename the test file. - When you rename the source file (inevitable), you remember to rename the test file.
<hr> <hr>
@ -3424,6 +3425,7 @@ Of course specs that test the test helpers belong in the `test` folder,
next to their corresponding helper files. next to their corresponding helper files.
{@a q-e2e} {@a q-e2e}
#### Why not rely on E2E tests of DOM integration? #### Why not rely on E2E tests of DOM integration?
The component DOM tests described in this guide often require extensive setup and The component DOM tests described in this guide often require extensive setup and