mirror of
https://github.com/angular/angular
synced 2026-05-24 09:28:37 +00:00
178 lines
27 KiB
Markdown
178 lines
27 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:
|
|
|
|
| Function | Details |
|
|
|:--- |:--- |
|
|
| `waitForAsync` | Runs the body of a test \(`it`\) or setup \(`beforeEach`\) function within a special *async test zone*. See [waitForAsync](guide/testing-components-scenarios#waitForAsync). |
|
|
| `fakeAsync` | Runs the body of a test \(`it`\) within a special *fakeAsync test zone*, enabling a linear control flow coding style. See [fakeAsync](guide/testing-components-scenarios#fake-async). |
|
|
| `tick` | 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 [tick](guide/testing-components-scenarios#tick). |
|
|
| `inject` | 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). |
|
|
| `discardPeriodicTasks` | When a `fakeAsync()` test ends with pending timer event *tasks* \(queued `setTimeOut` and `setInterval` callbacks\), the test fails with a clear error message. <br /> 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. |
|
|
| `flushMicrotasks` | When a `fakeAsync()` test ends with pending *micro-tasks* such as unresolved promises, the test fails with a clear error message. <br /> 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. |
|
|
| `ComponentFixtureAutoDetect` | A provider token for a service that turns on [automatic change detection](guide/testing-components-scenarios#automatic-change-detection). |
|
|
| `getTestBed` | 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. |
|
|
|
|
<a id="testbed-class-summary"></a>
|
|
|
|
## `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 format="javascript" language="javascript">
|
|
|
|
type TestModuleMetadata = {
|
|
providers?: any[];
|
|
declarations?: any[];
|
|
imports?: any[];
|
|
schemas?: Array<SchemaMetadata | any[]>;
|
|
};
|
|
|
|
</code-example>
|
|
|
|
<a id="metadata-override-object"></a>
|
|
|
|
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 format="javascript" language="javascript">
|
|
|
|
type MetadataOverride<T> = {
|
|
add?: Partial<T>;
|
|
remove?: Partial<T>;
|
|
set?: Partial<T>;
|
|
};
|
|
|
|
</code-example>
|
|
|
|
<a id="testbed-methods"></a>
|
|
<a id="testbed-api-summary"></a>
|
|
|
|
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.
|
|
|
|
| Methods | Details |
|
|
|:--- |:--- |
|
|
| `configureTestingModule` | 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. <br /> 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. |
|
|
| `compileComponents` | 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 [compileComponents](guide/testing-components-scenarios#compile-components). <br /> After calling `compileComponents`, the `TestBed` configuration is frozen for the duration of the current spec. |
|
|
| `createComponent<T>` | Create an instance of a component of type `T` based on the current `TestBed` configuration. After calling `createComponent`, the `TestBed` configuration is frozen for the duration of the current spec. |
|
|
| `overrideModule` | 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. |
|
|
| `overrideComponent` | Replace metadata for the given component class, which could be nested deeply within an inner module. |
|
|
| `overrideDirective` | Replace metadata for the given directive class, which could be nested deeply within an inner module. |
|
|
| `overridePipe` | Replace metadata for the given pipe class, which could be nested deeply within an inner module. |
|
|
|
|
|
<a id="testbed-inject"></a>
|
|
`inject` | 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. <br /> What if the service is optional? <br /> 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 header="app/demo/demo.testbed.spec.ts" path="testing/src/app/demo/demo.testbed.spec.ts" region="testbed-get-w-null"></code-example> After calling `TestBed.inject`, the `TestBed` configuration is frozen for the duration of the current spec. |
|
|
|
|
|
<a id="testbed-initTestEnvironment"></a>
|
|
`initTestEnvironment` | Initialize the testing environment for the entire test run. <br /> 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. <br /> Call this method *exactly once*. To change this default in the middle of a test run, call `resetTestEnvironment` first. <br /> 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>`. |
|
|
| `resetTestEnvironment` | Reset the initial test environment, including the default testing module. |
|
|
|
|
A few of the `TestBed` instance methods are not covered by static `TestBed` *class* methods.
|
|
These are rarely needed.
|
|
|
|
<a id="component-fixture-api-summary"></a>
|
|
|
|
## 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 id="component-fixture-properties"></a>
|
|
|
|
### `ComponentFixture` properties
|
|
|
|
Here are the most important properties for testers, in order of likely utility.
|
|
|
|
| Properties | Details |
|
|
|:--- |:--- |
|
|
| `componentInstance` | The instance of the component class created by `TestBed.createComponent`. |
|
|
| `debugElement` | The `DebugElement` associated with the root element of the component. <br /> 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). |
|
|
| `nativeElement` | The native DOM element at the root of the component. |
|
|
| `changeDetectorRef` | The `ChangeDetectorRef` for the component. <br /> 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. |
|
|
|
|
<a id="component-fixture-methods"></a>
|
|
|
|
### `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.
|
|
|
|
| Methods | Details |
|
|
|:--- |:--- |
|
|
| `detectChanges` | Trigger a change detection cycle for the component. <br /> 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`. <br /> Runs `checkNoChanges` afterwards to confirm that there are no circular updates unless called as `detectChanges(false)`; |
|
|
| `autoDetectChanges` | Set this to `true` when you want the fixture to detect changes automatically. <br /> 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. <br /> The default is `false`. Testers who prefer fine control over test behavior tend to keep it `false`. |
|
|
| `checkNoChanges` | Do a change detection run to make sure there are no pending changes. Throws an exceptions if there are. |
|
|
| `isStable` | If the fixture is currently *stable*, returns `true`. If there are async tasks that have not completed, returns `false`. |
|
|
| `whenStable` | Returns a promise that resolves when the fixture is stable. <br /> To resume testing after completion of asynchronous activity or asynchronous change detection, hook that promise. See [whenStable](guide/testing-components-scenarios#when-stable). |
|
|
| `destroy` | Trigger component destruction. |
|
|
|
|
<a id="debug-element-details"></a>
|
|
|
|
#### `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:
|
|
|
|
| Members | Details |
|
|
|:--- |:--- |
|
|
| `nativeElement` | The corresponding DOM element in the browser |
|
|
| `query` | Calling `query(predicate: Predicate<DebugElement>)` returns the first `DebugElement` that matches the [predicate](#query-predicate) at any depth in the subtree. |
|
|
| `queryAll` | Calling `queryAll(predicate: Predicate<DebugElement>)` returns all `DebugElements` that matches the [predicate](#query-predicate) at any depth in subtree. |
|
|
| `injector` | The host dependency injector. For example, the root element's component instance injector. |
|
|
| `componentInstance` | The element's own component instance, if it has one. |
|
|
| `context` | An object that provides parent context for this element. Often an ancestor component instance that governs this element. <br /> When an element is repeated within `*ngFor`, the context is an `NgForOf` whose `$implicit` property is the value of the row instance value. For example, the `hero` in `*ngFor="let hero of heroes"`. |
|
|
| `children` | 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> |
|
|
| `parent` | The `DebugElement` parent. Null if this is the root element. |
|
|
| `name` | The element tag name, if it is an element. |
|
|
| `triggerEventHandler` | 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 [triggerEventHandler](guide/testing-components-scenarios#trigger-event-handler). <br /> If the event lacks a listener or there's some other problem, consider calling `nativeElement.dispatchEvent(eventObject)`. |
|
|
| `listeners` | The callbacks attached to the component's `@Output` properties and/or the element's event properties. |
|
|
| `providerTokens` | This component's injector lookup tokens. Includes the component itself plus the tokens that the component lists in its `providers` metadata. |
|
|
| `source` | Where to find this element in the source component template. |
|
|
| `references` | Dictionary of objects associated with template local variables \(for example, `#foo`\), keyed by the local variable name. |
|
|
|
|
<a id="query-predicate"></a>
|
|
|
|
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 header="app/demo/demo.testbed.spec.ts" path="testing/src/app/demo/demo.testbed.spec.ts" region="custom-predicate"></code-example>
|
|
|
|
The Angular `By` class has three static methods for common predicates:
|
|
|
|
| Static method | Details |
|
|
|:--- |:--- |
|
|
| `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 header="app/hero/hero-list.component.spec.ts" path="testing/src/app/hero/hero-list.component.spec.ts" region="by"></code-example>
|
|
|
|
<!-- links -->
|
|
|
|
<!-- external links -->
|
|
|
|
<!-- end links -->
|
|
|
|
@reviewed 2023-09-07
|