In-depth Guides
Testing

Adding harness support for additional testing environments

Before you start

Tip: This guide assumes you've already read the component harnesses overview guide. Read that first if you're new to using component harnesses.

When does adding support for a test environment make sense?

To use component harnesses in the following environments, you can use Angular CDK's two built-in environments:

  • Unit tests
  • WebDriver end-to-end tests

To use a supported testing environment, read the Creating harnesses for your components guide.

Otherwise, to add support for other environments, you need to define how to interact with a DOM element and how DOM interactions work in your environment. Continue reading to learn more.

CDK Installation

The Component Dev Kit (CDK) is a set of behavior primitives for building components. To use the component harnesses, first install @angular/cdk from npm. You can do this from your terminal using the Angular CLI:

      
ng add @angular/cdk

Creating a TestElement implementation

Every test environment must define a TestElement implementation. The TestElement interface serves as an environment-agnostic representation of a DOM element. It enables harnesses to interact with DOM elements regardless of the underlying environment. Because some environments don't support interacting with DOM elements synchronously (e.g. WebDriver), all TestElement methods are asynchronous, returning a Promise with the result of the operation.

TestElement offers a number of methods to interact with the underlying DOM such as blur(), click(), getAttribute(), and more. See the TestElement API reference page for the full list of methods.

The TestElement interface consists largely of methods that resemble methods available on HTMLElement. Similar methods exist in most test environments, which makes implementing the methods fairly straightforward. However, one important difference to note when implementing the sendKeys method, is that the key codes in the TestKey enum likely differ from the key codes used in the test environment. Environment authors should maintain a mapping from TestKey codes to the codes used in the particular testing environment.

The UnitTestElement and SeleniumWebDriverElement implementations in Angular CDK serve as good examples of implementations of this interface.

Creating a HarnessEnvironment implementation

Test authors use HarnessEnvironment to create component harness instances for use in tests. HarnessEnvironment is an abstract class that must be extended to create a concrete subclass for the new environment. When supporting a new test environment, create a HarnessEnvironment subclass that adds concrete implementations for all abstract members.

HarnessEnvironment has a generic type parameter: HarnessEnvironment<E>. This parameter, E, represents the raw element type of the environment. For example, this parameter is Element for unit test environments.

The following are the abstract methods that must be implemented:

Method Description
abstract getDocumentRoot(): E Gets the root element for the environment (e.g. document.body).
abstract createTestElement(element: E): TestElement Creates a TestElement for the given raw element.
abstract createEnvironment(element: E): HarnessEnvironment Creates a HarnessEnvironment rooted at the given raw element.
abstract getAllRawElements(selector: string): Promise<E[]> Gets all of the raw elements under the root element of the environment matching the given selector.
abstract forceStabilize(): Promise<void> Gets a Promise that resolves when the NgZone is stable. Additionally, if applicable, tells NgZone to stabilize (e.g. calling flush() in a fakeAsync test).
abstract waitForTasksOutsideAngular(): Promise<void> Gets a Promise that resolves when the parent zone of NgZone is stable.

In addition to implementing the missing methods, this class should provide a way for test authors to get ComponentHarness instances. You should define a protected constructor and provide a static method called loader that returns a HarnessLoader instance. This allows test authors to write code like: SomeHarnessEnvironment.loader().getHarness(...). Depending on the needs of the particular environment, the class may provide several different static methods or require arguments to be passed. (e.g. the loader method on TestbedHarnessEnvironment takes a ComponentFixture, and the class provides additional static methods called documentRootLoader and harnessForFixture).

The TestbedHarnessEnvironment and SeleniumWebDriverHarnessEnvironment implementations in Angular CDK serve as good examples of implementations of this interface.

Handling auto change detection

In order to support the manualChangeDetection and parallel APIs, your environment should install a handler for the auto change detection status.

When your environment wants to start handling the auto change detection status it can call handleAutoChangeDetectionStatus(handler). The handler function will receive a AutoChangeDetectionStatus which has two properties isDisabled and onDetectChangesNow(). See the AutoChangeDetectionStatus API reference page for more information. If your environment wants to stop handling auto change detection status it can call stopHandlingAutoChangeDetectionStatus().