Hardware FixRecommendedDevice not working? Your driver may be the problemCheck updates for common hardware issues.Fix DriversOctober DealsAmazon USOctober deal check: compare before you payAmazon US: current deals, useful picks and tech finds.Check DealsWindows FixRecommendedWindows errors stealing your time? Find the fix fastScan stability, cleanup and performance issues.Fix Now×
Skip to content
World desk5 min

How to Create Angular Component Harnesses for Testing

A component harness is a class that lets Angular tests interact with a component through user-level methods. Here is when to create one, how to write a minimal ComponentHarness, and how to load it in TestBed, including overlays.
Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Create a harness when a component is shared, interactive, and exercised by tests in more than one place. The harness is a class that extends ComponentHarness, identifies its component with a static hostSelector, and exposes user-level actions such as “click the greet button” instead of raw DOM queries. Tests then load the harness through a loader rather than reaching into the markup. The API described here ships in the Angular CDK (@angular/cdk), and the steps below follow Angular’s current component harness documentation.

When a component deserves a harness

Angular’s guidance is that harnesses pay off most for shared components with user interaction, such as reusable widgets and component libraries. A page component used in only one place is a weaker candidate, because its tests and its implementation change together anyway. A harness can still help there if the same interaction API is needed in both unit tests and end-to-end tests.

As an Amazon Associate I earn from qualifying purchases.

A component is a strong candidate when:

  • It appears in several features or is published from a component library.
  • Users click, type, select, or open it, so tests need to perform actions and read results.
  • The same DOM queries are repeated across many spec files.
  • The same interactions must run in a TestBed unit test and in a browser test.

A component is a weak candidate when it is a one-off page with trivial markup, or when a test only checks a single static label that a plain query already reads clearly.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Why not query the DOM directly?

Direct queries tie every spec to the current template structure and CSS classes. When a designer renames a class or wraps a button in a new element, many tests break for reasons unrelated to behavior. A harness moves those selectors into one class. Consumer tests call methods that describe what a user does, so a template change usually means editing the harness once rather than every spec.

Angular describes the idea this way: “A component harness is a class that allows tests to interact with components the way an end user does via a supported API.” The framework states the benefits as insulation from implementation details, readability, and portability across test environments. Those are qualitative benefits; Angular does not publish a measured reduction in maintenance time.

Create a minimal harness

  1. Install the CDK in the workspace with ng add @angular/cdk. The harness API is part of the @angular/cdk package.
  2. Create a harness file beside the component, for example greeting.harness.ts.
  3. Declare a class that extends ComponentHarness and set a static hostSelector to the component’s selector (here, app-greeting).
  4. Add private locators with locatorFor and expose user-level methods that use them.
  5. Add a static with method that returns a HarnessPredicate, so tests can filter instances by content. Angular says most harnesses should provide one.
import {ComponentHarness, HarnessPredicate} from '@angular/cdk/testing';

export class GreetingHarness extends ComponentHarness {
  static hostSelector = 'app-greeting';

  private getButton = this.locatorFor('button');
  private getMessage = this.locatorFor('p.message');

  static with(options: {text?: string} = {}): HarnessPredicate<GreetingHarness> {
    return new HarnessPredicate(GreetingHarness, options)
      .addOption('text', options.text,
        (harness, text) => HarnessPredicate.stringMatches(harness.getMessageText(), text));
  }

  async clickGreet(): Promise<void> {
    await (await this.getButton()).click();
  }

  async getMessageText(): Promise<string> {
    return (await this.getMessage()).text();
  }
}

Keep the public surface about behavior. A method such as clickGreet() survives a markup change; a method that returns a raw element for the caller to query does not offer much over the DOM itself.

Load the harness in a TestBed test

In a unit test, create the fixture, build a loader from it, and then query. Loader methods such as getHarness and getAllHarnesses are asynchronous, so each call must be awaited.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
import {TestBed} from '@angular/core/testing';
import {TestbedHarnessEnvironment} from '@angular/cdk/testing/testbed';
import {GreetingComponent} from './greeting.component';
import {GreetingHarness} from './greeting.harness';

it('shows the greeting after the button is clicked', async () => {
  const fixture = TestBed.createComponent(GreetingComponent);
  const loader = TestbedHarnessEnvironment.loader(fixture);

  const greeting = await loader.getHarness(GreetingHarness);
  await greeting.clickGreet();

  expect(await greeting.getMessageText()).toBe('Hello');
});

The expected text in this example is illustrative. To pick a specific instance among several, pass the predicate instead of the class, for example loader.getHarness(GreetingHarness.with({text: 'Hello'})).

Find overlays and elements outside the fixture

A fixture loader only searches inside the component under test. Dialogs, menus, and snackbars that the CDK attaches to document.body are outside that root, so a fixture loader cannot see them. Choose the loader that matches where the host element lives.

Loader Use when Example
TestbedHarnessEnvironment.loader(fixture) The harness host is inside the fixture’s component tree. A GreetingHarness on app-greeting rendered by the tested component.
TestbedHarnessEnvironment.documentRootLoader(fixture) The host is attached outside the fixture root, such as an overlay appended to document.body. A harness for a dialog component that opens from a button in the tested component.
TestbedHarnessEnvironment.harnessForFixture(fixture, HarnessType) The harness host is the fixture’s root element itself. A harness for the component being tested, when that component’s own element is the host.
const overlayLoader = TestbedHarnessEnvironment.documentRootLoader(fixture);
const dialog = await overlayLoader.getHarness(DialogHarness);

Other test environments

Angular’s guide shows one harness working across environments: the TestBed environment for unit tests and the Selenium WebDriver environment for end-to-end tests. The same harness class is reused; only the loader changes. In a WebDriver test, create the loader from the WebDriver client and the document root.

Environment Typical context Loader setup
TestBed harness environment Angular unit tests Start from a ComponentFixture; use the fixture loader or the document-root loader depending on where the element is attached.
Selenium WebDriver harness environment Browser-based end-to-end tests Create the loader from the WebDriver client and the document root.
Custom HarnessEnvironment A test runner or driver that Angular does not provide Implement an environment-specific TestElement and subclass HarnessEnvironment.

Writing a custom environment

You need a custom environment only when neither built-in fits your runner. The work has two parts. First, provide a TestElement implementation for your driver. Its operations are asynchronous because some drivers cannot interact with DOM elements synchronously. Second, subclass HarnessEnvironment and implement its abstract behavior. If your runner’s key codes differ from Angular’s TestKey values, map them inside your environment so that harness keyboard actions behave the same way.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Common mistakes

  • Forgetting to await. Loader queries and harness methods return promises; an unawaited call makes the assertion read a stale or pending value.
  • Using the fixture loader for overlays. If the element is attached to document.body, use the document-root loader.
  • Mismatched host selector. If hostSelector does not match the component’s selector, the loader cannot find the component.
  • Exposing selectors instead of behavior. Methods that only return raw elements keep tests coupled to the DOM.
  • Harnessing everything. A one-off page component with a single assertion gains little from a harness.

Angular’s documentation covers these concepts and API behavior well enough for an introductory setup. It does not pin a specific Angular or CDK version, so confirm the import paths and test runner setup against the versions in your project before copying the code.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

Leave a Reply

Your email address will not be published. Required fields are marked *

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

More from the Wire

  1. World desk4 min
    How to Spot an AI Voice Scam Before Sending MoneyDon’t rely on how a caller sounds. Pause, call back through a known number, and verify the emergency with another trusted person before sending money.
  2. Mountain View desk4 min
    Google’s SynthID Detector: How to Check AI-Generated Images, Video and AudioGoogle’s SynthID Detector looks for an embedded watermark in supported images, video and audio. Here is what its results do—and do not—show.
  3. Redmond desk20 min
    How to create a link to File or Folder in Windows 11Windows 11 gives you several ways to point to a file or folder without moving or duplicating it. You can create a desktop shortcut,…
Recommended PC Tool
Recommended PC Tool
Crashes, No Sound, or Screen Glitches?Free driver scan
Windows Errors? Fix Them Before They SpreadFree repair scan

Two free Windows tools

One Free Minute Could Fix That PC

Before you go - each of these free tools takes about a minute and tackles what quietly slows a Windows PC down.

Special offer. View Outbyte info, uninstall instructions, EULA, and Privacy Policy.