789 lines
19 KiB
Markdown
789 lines
19 KiB
Markdown
# Testing Utility APIs
|
|
|
|
This page describes the most useful Angular testing features.
|
|
|
|
The Angular testing utilities include the `TestBed`, the `ComponentFixture`, and a handful of functions that control the test environment.
|
|
The [_TestBed_](#testbed-api-summary) and [_ComponentFixture_](#component-fixture-api-summary) classes are covered separately.
|
|
|
|
Here's a summary of the stand-alone functions, in order of likely utility:
|
|
|
|
<table>
|
|
<tr>
|
|
<th>
|
|
Function
|
|
</th>
|
|
<th>
|
|
Description
|
|
</th>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td style="vertical-align: top">
|
|
<code>waitForAsync</code>
|
|
</td>
|
|
|
|
<td>
|
|
|
|
Runs the body of a test (`it`) or setup (`beforeEach`) function within a special _async test zone_.
|
|
See [discussion above](guide/testing-components-scenarios#waitForAsync).
|
|
|
|
</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td style="vertical-align: top">
|
|
<code>fakeAsync</code>
|
|
</td>
|
|
|
|
<td>
|
|
|
|
Runs the body of a test (`it`) within a special _fakeAsync test zone_, enabling
|
|
a linear control flow coding style. See [discussion above](guide/testing-components-scenarios#fake-async).
|
|
|
|
</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td style="vertical-align: top">
|
|
<code>tick</code>
|
|
</td>
|
|
|
|
<td>
|
|
|
|
Simulates the passage of time and the completion of pending asynchronous activities
|
|
by flushing both _timer_ and _micro-task_ queues within the _fakeAsync test zone_.
|
|
|
|
<div class="alert is-helpful">
|
|
|
|
The curious, dedicated reader might enjoy this lengthy blog post,
|
|
["_Tasks, microtasks, queues and schedules_"](https://jakearchibald.com/2015/tasks-microtasks-queues-and-schedules/).
|
|
|
|
</div>
|
|
|
|
Accepts an optional argument that moves the virtual clock forward
|
|
by the specified number of milliseconds,
|
|
clearing asynchronous activities scheduled within that timeframe.
|
|
See [discussion above](guide/testing-components-scenarios#tick).
|
|
|
|
</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td style="vertical-align: top">
|
|
<code>inject</code>
|
|
</td>
|
|
|
|
<td>
|
|
|
|
Injects one or more services from the current `TestBed` injector into a test function.
|
|
It cannot inject a service provided by the component itself.
|
|
See discussion of the [debugElement.injector](guide/testing-components-scenarios#get-injected-services).
|
|
|
|
</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td style="vertical-align: top">
|
|
<code>discardPeriodicTasks</code>
|
|
</td>
|
|
|
|
<td>
|
|
|
|
When a `fakeAsync()` test ends with pending timer event _tasks_ (queued `setTimeOut` and `setInterval` callbacks),
|
|
the test fails with a clear error message.
|
|
|
|
In general, a test should end with no queued tasks.
|
|
When pending timer tasks are expected, call `discardPeriodicTasks` to flush the _task_ queue
|
|
and avoid the error.
|
|
|
|
</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td style="vertical-align: top">
|
|
<code>flushMicrotasks</code>
|
|
</td>
|
|
|
|
<td>
|
|
|
|
When a `fakeAsync()` test ends with pending _micro-tasks_ such as unresolved promises,
|
|
the test fails with a clear error message.
|
|
|
|
In general, a test should wait for micro-tasks to finish.
|
|
When pending microtasks are expected, call `flushMicrotasks` to flush the _micro-task_ queue
|
|
and avoid the error.
|
|
|
|
</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td style="vertical-align: top">
|
|
<code>ComponentFixtureAutoDetect</code>
|
|
</td>
|
|
|
|
<td>
|
|
|
|
A provider token for a service that turns on [automatic change detection](guide/testing-components-scenarios#automatic-change-detection).
|
|
|
|
</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td style="vertical-align: top">
|
|
<code>getTestBed</code>
|
|
</td>
|
|
|
|
<td>
|
|
|
|
Gets the current instance of the `TestBed`.
|
|
Usually unnecessary because the static class methods of the `TestBed` class are typically sufficient.
|
|
The `TestBed` instance exposes a few rarely used members that are not available as
|
|
static methods.
|
|
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
|
|
{@a testbed-class-summary}
|
|
## _TestBed_ class summary
|
|
|
|
The `TestBed` class is one of the principal Angular testing utilities.
|
|
Its API is quite large and can be overwhelming until you've explored it,
|
|
a little at a time. Read the early part of this guide first
|
|
to get the basics before trying to absorb the full API.
|
|
|
|
The module definition passed to `configureTestingModule`
|
|
is a subset of the `@NgModule` metadata properties.
|
|
|
|
<code-example language="javascript">
|
|
type TestModuleMetadata = {
|
|
providers?: any[];
|
|
declarations?: any[];
|
|
imports?: any[];
|
|
schemas?: Array<SchemaMetadata | any[]>;
|
|
};
|
|
</code-example>
|
|
|
|
{@a metadata-override-object}
|
|
|
|
Each override method takes a `MetadataOverride<T>` where `T` is the kind of metadata
|
|
appropriate to the method, that is, the parameter of an `@NgModule`,
|
|
`@Component`, `@Directive`, or `@Pipe`.
|
|
|
|
<code-example language="javascript">
|
|
type MetadataOverride<T> = {
|
|
add?: Partial<T>;
|
|
remove?: Partial<T>;
|
|
set?: Partial<T>;
|
|
};
|
|
</code-example>
|
|
|
|
{@a testbed-methods}
|
|
{@a testbed-api-summary}
|
|
|
|
The `TestBed` API consists of static class methods that either update or reference a _global_ instance of the `TestBed`.
|
|
|
|
Internally, all static methods cover methods of the current runtime `TestBed` instance,
|
|
which is also returned by the `getTestBed()` function.
|
|
|
|
Call `TestBed` methods _within_ a `beforeEach()` to ensure a fresh start before each individual test.
|
|
|
|
Here are the most important static methods, in order of likely utility.
|
|
|
|
<table>
|
|
<tr>
|
|
<th>
|
|
Methods
|
|
</th>
|
|
<th>
|
|
Description
|
|
</th>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td style="vertical-align: top">
|
|
<code>configureTestingModule</code>
|
|
</td>
|
|
|
|
<td>
|
|
|
|
The testing shims (`karma-test-shim`, `browser-test-shim`)
|
|
establish the [initial test environment](guide/testing) and a default testing module.
|
|
The default testing module is configured with basic declaratives and some Angular service substitutes that every tester needs.
|
|
|
|
Call `configureTestingModule` to refine the testing module configuration for a particular set of tests
|
|
by adding and removing imports, declarations (of components, directives, and pipes), and providers.
|
|
|
|
</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td style="vertical-align: top">
|
|
<code>compileComponents</code>
|
|
</td>
|
|
|
|
<td>
|
|
|
|
Compile the testing module asynchronously after you've finished configuring it.
|
|
You **must** call this method if _any_ of the testing module components have a `templateUrl`
|
|
or `styleUrls` because fetching component template and style files is necessarily asynchronous.
|
|
See [above](guide/testing-components-scenarios#compile-components).
|
|
|
|
After calling `compileComponents`, the `TestBed` configuration is frozen for the duration of the current spec.
|
|
|
|
</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td style="vertical-align: top">
|
|
<code>createComponent<T></code>
|
|
</td>
|
|
|
|
<td>
|
|
|
|
Create an instance of a component of type `T` based on the current `TestBed` configuration.
|
|
After calling `compileComponent`, the `TestBed` configuration is frozen for the duration of the current spec.
|
|
|
|
</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td style="vertical-align: top">
|
|
<code>overrideModule</code>
|
|
</td>
|
|
<td>
|
|
|
|
Replace metadata for the given `NgModule`. Recall that modules can import other modules.
|
|
The `overrideModule` method can reach deeply into the current testing module to
|
|
modify one of these inner modules.
|
|
|
|
</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td style="vertical-align: top">
|
|
<code>overrideComponent</code>
|
|
</td>
|
|
|
|
<td>
|
|
|
|
Replace metadata for the given component class, which could be nested deeply
|
|
within an inner module.
|
|
|
|
</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td style="vertical-align: top">
|
|
<code>overrideDirective</code>
|
|
</td>
|
|
|
|
<td>
|
|
|
|
Replace metadata for the given directive class, which could be nested deeply
|
|
within an inner module.
|
|
|
|
</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td style="vertical-align: top">
|
|
<code>overridePipe</code>
|
|
</td>
|
|
<td>
|
|
|
|
Replace metadata for the given pipe class, which could be nested deeply
|
|
within an inner module.
|
|
|
|
</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td style="vertical-align: top">
|
|
{@a testbed-inject}
|
|
<code>inject</code>
|
|
</td>
|
|
|
|
<td>
|
|
|
|
Retrieve a service from the current `TestBed` injector.
|
|
|
|
The `inject` function is often adequate for this purpose.
|
|
But `inject` throws an error if it can't provide the service.
|
|
|
|
What if the service is optional?
|
|
|
|
The `TestBed.inject()` method takes an optional second parameter,
|
|
the object to return if Angular can't find the provider
|
|
(`null` in this example):
|
|
|
|
<code-example path="testing/src/app/demo/demo.testbed.spec.ts" region="testbed-get-w-null" header="app/demo/demo.testbed.spec.ts"></code-example>
|
|
|
|
After calling `TestBed.inject`, the `TestBed` configuration is frozen for the duration of the current spec.
|
|
|
|
</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td style="vertical-align: top">
|
|
{@a testbed-initTestEnvironment}
|
|
<code>initTestEnvironment</code>
|
|
</td>
|
|
<td>
|
|
|
|
Initialize the testing environment for the entire test run.
|
|
|
|
The testing shims (`karma-test-shim`, `browser-test-shim`) call it for you
|
|
so there is rarely a reason for you to call it yourself.
|
|
|
|
You may call this method _exactly once_. If you must change
|
|
this default in the middle of your test run, call `resetTestEnvironment` first.
|
|
|
|
Specify the Angular compiler factory, a `PlatformRef`, and a default Angular testing module.
|
|
Alternatives for non-browser platforms are available in the general form
|
|
`@angular/platform-<platform_name>/testing/<platform_name>`.
|
|
|
|
</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td style="vertical-align: top">
|
|
<code>resetTestEnvironment</code>
|
|
</td>
|
|
<td>
|
|
|
|
Reset the initial test environment, including the default testing module.
|
|
|
|
</td>
|
|
</tr>
|
|
</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}
|
|
|
|
## The _ComponentFixture_
|
|
|
|
The `TestBed.createComponent<T>`
|
|
creates an instance of the component `T`
|
|
and returns a strongly typed `ComponentFixture` for that component.
|
|
|
|
The `ComponentFixture` properties and methods provide access to the component,
|
|
its DOM representation, and aspects of its Angular environment.
|
|
|
|
{@a component-fixture-properties}
|
|
|
|
### _ComponentFixture_ properties
|
|
|
|
Here are the most important properties for testers, in order of likely utility.
|
|
|
|
<table>
|
|
<tr>
|
|
<th>
|
|
Properties
|
|
</th>
|
|
<th>
|
|
Description
|
|
</th>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td style="vertical-align: top">
|
|
<code>componentInstance</code>
|
|
</td>
|
|
|
|
<td>
|
|
|
|
The instance of the component class created by `TestBed.createComponent`.
|
|
|
|
</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td style="vertical-align: top">
|
|
<code>debugElement</code>
|
|
</td>
|
|
|
|
<td>
|
|
|
|
The `DebugElement` associated with the root element of the component.
|
|
|
|
The `debugElement` provides insight into the component and its DOM element during test and debugging.
|
|
It's a critical property for testers. The most interesting members are covered [below](#debug-element-details).
|
|
|
|
</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td style="vertical-align: top">
|
|
<code>nativeElement</code>
|
|
</td>
|
|
|
|
<td>
|
|
|
|
The native DOM element at the root of the component.
|
|
|
|
</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td style="vertical-align: top">
|
|
<code>changeDetectorRef</code>
|
|
</td>
|
|
|
|
<td>
|
|
|
|
The `ChangeDetectorRef` for the component.
|
|
|
|
The `ChangeDetectorRef` is most valuable when testing a
|
|
component that has the `ChangeDetectionStrategy.OnPush` method
|
|
or the component's change detection is under your programmatic control.
|
|
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
|
|
{@a component-fixture-methods}
|
|
|
|
### _ComponentFixture_ methods
|
|
|
|
The _fixture_ methods cause Angular to perform certain tasks on the component tree.
|
|
Call these method to trigger Angular behavior in response to simulated user action.
|
|
|
|
Here are the most useful methods for testers.
|
|
|
|
<table>
|
|
<tr>
|
|
<th>
|
|
Methods
|
|
</th>
|
|
<th>
|
|
Description
|
|
</th>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td style="vertical-align: top">
|
|
<code>detectChanges</code>
|
|
</td>
|
|
|
|
<td>
|
|
|
|
Trigger a change detection cycle for the component.
|
|
|
|
Call it to initialize the component (it calls `ngOnInit`) and after your
|
|
test code, change the component's data bound property values.
|
|
Angular can't see that you've changed `personComponent.name` and won't update the `name`
|
|
binding until you call `detectChanges`.
|
|
|
|
Runs `checkNoChanges` afterwards to confirm that there are no circular updates unless
|
|
called as `detectChanges(false)`;
|
|
|
|
</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td style="vertical-align: top">
|
|
<code>autoDetectChanges</code>
|
|
</td>
|
|
|
|
<td>
|
|
|
|
Set this to `true` when you want the fixture to detect changes automatically.
|
|
|
|
When autodetect is `true`, the test fixture calls `detectChanges` immediately
|
|
after creating the component. Then it listens for pertinent zone events
|
|
and calls `detectChanges` accordingly.
|
|
When your test code modifies component property values directly,
|
|
you probably still have to call `fixture.detectChanges` to trigger data binding updates.
|
|
|
|
The default is `false`. Testers who prefer fine control over test behavior
|
|
tend to keep it `false`.
|
|
|
|
</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td style="vertical-align: top">
|
|
<code>checkNoChanges</code>
|
|
</td>
|
|
|
|
<td>
|
|
|
|
Do a change detection run to make sure there are no pending changes.
|
|
Throws an exceptions if there are.
|
|
</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td style="vertical-align: top">
|
|
<code>isStable</code>
|
|
</td>
|
|
|
|
<td>
|
|
|
|
If the fixture is currently _stable_, returns `true`.
|
|
If there are async tasks that have not completed, returns `false`.
|
|
|
|
</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td style="vertical-align: top">
|
|
<code>whenStable</code>
|
|
</td>
|
|
|
|
<td>
|
|
|
|
Returns a promise that resolves when the fixture is stable.
|
|
|
|
To resume testing after completion of asynchronous activity or
|
|
asynchronous change detection, hook that promise.
|
|
See [above](guide/testing-components-scenarios#when-stable).
|
|
|
|
</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td style="vertical-align: top">
|
|
<code>destroy</code>
|
|
</td>
|
|
|
|
<td>
|
|
|
|
Trigger component destruction.
|
|
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
|
|
{@a debug-element-details}
|
|
|
|
#### _DebugElement_
|
|
|
|
The `DebugElement` provides crucial insights into the component's DOM representation.
|
|
|
|
From the test root component's `DebugElement` returned by `fixture.debugElement`,
|
|
you can walk (and query) the fixture's entire element and component subtrees.
|
|
|
|
Here are the most useful `DebugElement` members for testers, in approximate order of utility:
|
|
|
|
<table>
|
|
<tr>
|
|
<th>
|
|
Member
|
|
</th>
|
|
<th>
|
|
Description
|
|
</th>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td style="vertical-align: top">
|
|
<code>nativeElement</code>
|
|
</td>
|
|
|
|
<td>
|
|
|
|
The corresponding DOM element in the browser (null for WebWorkers).
|
|
|
|
</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td style="vertical-align: top">
|
|
<code>query</code>
|
|
</td>
|
|
|
|
<td>
|
|
|
|
Calling `query(predicate: Predicate<DebugElement>)` returns the first `DebugElement`
|
|
that matches the [predicate](#query-predicate) at any depth in the subtree.
|
|
|
|
</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td style="vertical-align: top">
|
|
<code>queryAll</code>
|
|
</td>
|
|
|
|
<td>
|
|
|
|
Calling `queryAll(predicate: Predicate<DebugElement>)` returns all `DebugElements`
|
|
that matches the [predicate](#query-predicate) at any depth in subtree.
|
|
|
|
</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td style="vertical-align: top">
|
|
<code>injector</code>
|
|
</td>
|
|
|
|
<td>
|
|
|
|
The host dependency injector.
|
|
For example, the root element's component instance injector.
|
|
|
|
</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td style="vertical-align: top">
|
|
<code>componentInstance</code>
|
|
</td>
|
|
|
|
<td>
|
|
|
|
The element's own component instance, if it has one.
|
|
|
|
</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td style="vertical-align: top">
|
|
<code>context</code>
|
|
</td>
|
|
|
|
<td>
|
|
|
|
An object that provides parent context for this element.
|
|
Often an ancestor component instance that governs this element.
|
|
|
|
When an element is repeated within `*ngFor`, the context is an `NgForRow` whose `$implicit`
|
|
property is the value of the row instance value.
|
|
For example, the `hero` in `*ngFor="let hero of heroes"`.
|
|
|
|
</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td style="vertical-align: top">
|
|
<code>children</code>
|
|
</td>
|
|
|
|
<td>
|
|
|
|
The immediate `DebugElement` children. Walk the tree by descending through `children`.
|
|
|
|
<div class="alert is-helpful">
|
|
|
|
`DebugElement` also has `childNodes`, a list of `DebugNode` objects.
|
|
`DebugElement` derives from `DebugNode` objects and there are often
|
|
more nodes than elements. Testers can usually ignore plain nodes.
|
|
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td style="vertical-align: top">
|
|
<code>parent</code>
|
|
</td>
|
|
<td>
|
|
|
|
The `DebugElement` parent. Null if this is the root element.
|
|
|
|
</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td style="vertical-align: top">
|
|
<code>name</code>
|
|
</td>
|
|
|
|
<td>
|
|
|
|
The element tag name, if it is an element.
|
|
|
|
</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td style="vertical-align: top">
|
|
<code>triggerEventHandler</code>
|
|
</td>
|
|
<td>
|
|
|
|
Triggers the event by its name if there is a corresponding listener
|
|
in the element's `listeners` collection.
|
|
The second parameter is the _event object_ expected by the handler.
|
|
See [above](guide/testing-components-scenarios#trigger-event-handler).
|
|
|
|
If the event lacks a listener or there's some other problem,
|
|
consider calling `nativeElement.dispatchEvent(eventObject)`.
|
|
|
|
</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td style="vertical-align: top">
|
|
<code>listeners</code>
|
|
</td>
|
|
|
|
<td>
|
|
|
|
The callbacks attached to the component's `@Output` properties and/or the element's event properties.
|
|
|
|
</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td style="vertical-align: top">
|
|
<code>providerTokens</code>
|
|
</td>
|
|
|
|
<td>
|
|
|
|
This component's injector lookup tokens.
|
|
Includes the component itself plus the tokens that the component lists in its `providers` metadata.
|
|
|
|
</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td style="vertical-align: top">
|
|
<code>source</code>
|
|
</td>
|
|
|
|
<td>
|
|
|
|
Where to find this element in the source component template.
|
|
|
|
</td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td style="vertical-align: top">
|
|
<code>references</code>
|
|
</td>
|
|
|
|
<td>
|
|
|
|
Dictionary of objects associated with template local variables (e.g. `#foo`),
|
|
keyed by the local variable name.
|
|
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
|
|
{@a query-predicate}
|
|
|
|
The `DebugElement.query(predicate)` and `DebugElement.queryAll(predicate)` methods take a
|
|
predicate that filters the source element's subtree for matching `DebugElement`.
|
|
|
|
The predicate is any method that takes a `DebugElement` and returns a _truthy_ value.
|
|
The following example finds all `DebugElements` with a reference to a template local variable named "content":
|
|
|
|
<code-example path="testing/src/app/demo/demo.testbed.spec.ts" region="custom-predicate" header="app/demo/demo.testbed.spec.ts"></code-example>
|
|
|
|
The Angular `By` class has three static methods for common predicates:
|
|
|
|
- `By.all` - return all elements.
|
|
- `By.css(selector)` - return elements with matching CSS selectors.
|
|
- `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" header="app/hero/hero-list.component.spec.ts"></code-example>
|