The `TestBed.compileComponents()` method (see [below](#compile-components)) calls `XHR`
to read external template and css files during "just-in-time" compilation.
Write tests that call `compileComponents()` with the `waitForAsync()` utility.
Here's the previous `fakeAsync()` test, re-written with the `waitForAsync()` utility.
The [discussion below](#routing-component) covers testing components that require the router.
The immediate goal is to test the `DashboardHeroComponent`, not the `DashboardComponent`,
so, try the second and third options.
{@a dashboard-standalone}
#### Test _DashboardHeroComponent_ stand-alone
Here's the meat of the spec file setup.
This small test demonstrates how Angular tests can verify a component's visual
representation—something not possible with
[component class tests](guide/testing-components-basics#component-class-testing)—at
low cost and without resorting to much slower and more complicated end-to-end tests.
#### Clicking
Clicking the hero should raise a `selected` event that
the host component (`DashboardComponent` presumably) can hear:
`.
It has Angular properties and methods that abstract interaction with the native element.
This test calls the `DebugElement.triggerEventHandler` with the "click" event name.
The "click" event binding responds by calling `DashboardHeroComponent.click()`.
The Angular `DebugElement.triggerEventHandler` can raise _any data-bound event_ by its _event name_.
The second parameter is the event object passed to the handler.
The test triggered a "click" event with a `null` event object.
The test assumes (correctly in this case) that the runtime
event handler—the component's `click()` method—doesn't
care about the event object.
Other handlers are less forgiving. For example, the `RouterLink`
directive expects an object with a `button` property
that identifies which mouse button (if any) was pressed during the click.
The `RouterLink` directive throws an error if the event object is missing.
#### Click the element
The following test alternative calls the native element's own `click()` method,
which is perfectly fine for _this component_.
{@a click-helper}
#### _click()_ helper
Clicking a button, an anchor, or an arbitrary HTML element is a common test task.
Make that consistent and easy by encapsulating the _click-triggering_ process
in a helper such as the `click()` function below:
The first parameter is the _element-to-click_. If you wish, you can pass a
custom event object as the second parameter. The default is a (partial)
left-button mouse event object
accepted by many handlers including the `RouterLink` directive.
The `click()` helper function is **not** one of the Angular testing utilities.
It's a function defined in _this guide's sample code_.
All of the sample tests use it.
If you like it, add it to your own collection of helpers.
Here's the previous test, rewritten using the click helper.
{@a component-inside-test-host}
## Component inside a test host
The previous tests played the role of the host `DashboardComponent` themselves.
But does the `DashboardHeroComponent` work correctly when properly data-bound to a host component?
You could test with the actual `DashboardComponent`.
But doing so could require a lot of setup,
especially when its template features an `*ngFor` repeater,
other components, layout HTML, additional bindings,
a constructor that injects multiple services,
and it starts interacting with those services right away.
Imagine the effort to disable these distractions, just to prove a point
that can be made satisfactorily with a _test host_ like this one:
This test host binds to `DashboardHeroComponent` as the `DashboardComponent` would
but without the noise of the `Router`, the `HeroService`, or the `*ngFor` repeater.
The test host sets the component's `hero` input property with its test hero.
It binds the component's `selected` event with its `onSelected` handler,
which records the emitted hero in its `selectedHero` property.
Later, the tests will be able to easily check `selectedHero` to verify that the
`DashboardHeroComponent.selected` event emitted the expected hero.
The setup for the _test-host_ tests is similar to the setup for the stand-alone tests:
This testing module configuration shows three important differences:
1. It _declares_ both the `DashboardHeroComponent` and the `TestHostComponent`.
1. It _creates_ the `TestHostComponent` instead of the `DashboardHeroComponent`.
1. The `TestHostComponent` sets the `DashboardHeroComponent.hero` with a binding.
The `createComponent` returns a `fixture` that holds an instance of `TestHostComponent` instead of an instance of `DashboardHeroComponent`.
Creating the `TestHostComponent` has the side-effect of creating a `DashboardHeroComponent`
because the latter appears within the template of the former.
The query for the hero element (`heroEl`) still finds it in the test DOM,
albeit at greater depth in the element tree than before.
The tests themselves are almost identical to the stand-alone version:
Only the selected event test differs. It confirms that the selected `DashboardHeroComponent` hero
really does find its way up through the event binding to the host component.
{@a routing-component}
## Routing component
A _routing component_ is a component that tells the `Router` to navigate to another component.
The `DashboardComponent` is a _routing component_ because the user can
navigate to the `HeroDetailComponent` by clicking on one of the _hero buttons_ on the dashboard.
Routing is pretty complicated.
Testing the `DashboardComponent` seemed daunting in part because it involves the `Router`,
which it injects together with the `HeroService`.
Mocking the `HeroService` with a spy is a [familiar story](#component-with-async-service).
But the `Router` has a complicated API and is entwined with other services and application preconditions. Might it be difficult to mock?
Fortunately, not in this case because the `DashboardComponent` isn't doing much with the `Router`
This is often the case with _routing components_.
As a rule you test the component, not the router,
and care only if the component navigates with the right address under the given conditions.
Providing a router spy for _this component_ test suite happens to be as easy
as providing a `HeroService` spy.
The following test clicks the displayed hero and confirms that
`Router.navigateByUrl` is called with the expected url.
{@a routed-component-w-param}
## Routed components
A _routed component_ is the destination of a `Router` navigation.
It can be trickier to test, especially when the route to the component _includes parameters_.
The `HeroDetailComponent` is a _routed component_ that is the destination of such a route.
When a user clicks a _Dashboard_ hero, the `DashboardComponent` tells the `Router`
to navigate to `heroes/:id`.
The `:id` is a route parameter whose value is the `id` of the hero to edit.
The `Router` matches that URL to a route to the `HeroDetailComponent`.
It creates an `ActivatedRoute` object with the routing information and
injects it into a new instance of the `HeroDetailComponent`.
Here's the `HeroDetailComponent` constructor:
The `HeroDetail` component needs the `id` parameter so it can fetch
the corresponding hero via the `HeroDetailService`.
The component has to get the `id` from the `ActivatedRoute.paramMap` property
which is an `Observable`.
It can't just reference the `id` property of the `ActivatedRoute.paramMap`.
The component has to _subscribe_ to the `ActivatedRoute.paramMap` observable and be prepared
for the `id` to change during its lifetime.
The [ActivatedRoute in action](guide/router-tutorial-toh#activated-route-in-action) section of the [Router tutorial: tour of heroes](guide/router-tutorial-toh) guide covers `ActivatedRoute.paramMap` in more detail.
Tests can explore how the `HeroDetailComponent` responds to different `id` parameter values
by manipulating the `ActivatedRoute` injected into the component's constructor.
You know how to spy on the `Router` and a data service.
You'll take a different approach with `ActivatedRoute` because
- `paramMap` returns an `Observable` that can emit more than one value
during a test.
- You need the router helper function, `convertToParamMap()`, to create a `ParamMap`.
- Other _routed component_ tests need a test double for `ActivatedRoute`.
These differences argue for a re-usable stub class.
#### _ActivatedRouteStub_
The following `ActivatedRouteStub` class serves as a test double for `ActivatedRoute`.
Consider placing such helpers in a `testing` folder sibling to the `app` folder.
This sample puts `ActivatedRouteStub` in `testing/activated-route-stub.ts`.
Consider writing a more capable version of this stub class with
the [_marble testing library_](#marble-testing).
{@a tests-w-test-double}
#### Testing with _ActivatedRouteStub_
Here's a test demonstrating the component's behavior when the observed `id` refers to an existing hero:
The `createComponent()` method and `page` object are discussed [below](#page-object).
Rely on your intuition for now.
When the `id` cannot be found, the component should re-route to the `HeroListComponent`.
The test suite setup provided the same router spy [described above](#routing-component) which spies on the router without actually navigating.
This test expects the component to try to navigate to the `HeroListComponent`.
While this app doesn't have a route to the `HeroDetailComponent` that omits the `id` parameter, it might add such a route someday.
The component should do something reasonable when there is no `id`.
In this implementation, the component should create and display a new hero.
New heroes have `id=0` and a blank `name`. This test confirms that the component behaves as expected:
## Nested component tests
Component templates often have nested components, whose templates
may contain more components.
The component tree can be very deep and, most of the time, the nested components
play no role in testing the component at the top of the tree.
The `AppComponent`, for example, displays a navigation bar with anchors and their `RouterLink` directives.
While the `AppComponent` _class_ is empty,
you may want to write unit tests to confirm that the links are wired properly
to the `RouterLink` directives, perhaps for the reasons [explained below](#why-stubbed-routerlink-tests).
To validate the links, you don't need the `Router` to navigate and you don't
need the `
` to mark where the `Router` inserts _routed components_.
The `BannerComponent` and `WelcomeComponent`
(indicated by `` and ``) are also irrelevant.
Yet any test that creates the `AppComponent` in the DOM will also create instances of
these three components and, if you let that happen,
you'll have to configure the `TestBed` to create them.
If you neglect to declare them, the Angular compiler won't recognize the
``, ``, and `` tags in the `AppComponent` template
and will throw an error.
If you declare the real components, you'll also have to declare _their_ nested components
and provide for _all_ services injected in _any_ component in the tree.
That's too much effort just to answer a few simple questions about links.
This section describes two techniques for minimizing the setup.
Use them, alone or in combination, to stay focused on the testing the primary component.
{@a stub-component}
##### Stubbing unneeded components
In the first technique, you create and declare stub versions of the components
and directive that play little or no role in the tests.
The stub selectors match the selectors for the corresponding real components.
But their templates and classes are empty.
Then declare them in the `TestBed` configuration next to the
components, directives, and pipes that need to be real.
The `AppComponent` is the test subject, so of course you declare the real version.
The `RouterLinkDirectiveStub`, [described later](#routerlink), is a test version
of the real `RouterLink` that helps with the link tests.
The rest are stubs.
{@a no-errors-schema}
#### _NO_ERRORS_SCHEMA_
In the second approach, add `NO_ERRORS_SCHEMA` to the `TestBed.schemas` metadata.
The `NO_ERRORS_SCHEMA` tells the Angular compiler to ignore unrecognized elements and attributes.
The compiler will recognize the `` element and the `routerLink` attribute
because you declared a corresponding `AppComponent` and `RouterLinkDirectiveStub`
in the `TestBed` configuration.
But the compiler won't throw an error when it encounters ``, ``, or ``.
It simply renders them as empty tags and the browser ignores them.
You no longer need the stub components.
#### Use both techniques together
These are techniques for _Shallow Component Testing_ ,
so-named because they reduce the visual surface of the component to just those elements
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` also prevents the compiler from telling you about the missing
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.
The _stub component_ approach has another advantage.
While the stubs in _this_ example were empty,
you could give them stripped-down templates and classes if your tests
need to interact with them in some way.
In practice you will combine the two techniques in the same setup,
as seen in this example.
The Angular compiler creates the `BannerComponentStub` for the `` element
and applies the `RouterLinkStubDirective` to the anchors with the `routerLink` attribute,
but it ignores the `` and `` tags.
{@a routerlink}
## Components with _RouterLink_
The real `RouterLinkDirective` is quite complicated and entangled with other components
and directives of the `RouterModule`.
It requires challenging setup to mock and use in tests.
The `RouterLinkDirectiveStub` in this sample code replaces the real directive
with an alternative version designed to validate the kind of anchor tag wiring
seen in the `AppComponent` template.
The URL bound to the `[routerLink]` attribute flows in to the directive's `linkParams` property.
The `HostListener` wires the click event of the host element
(the `` anchor elements in `AppComponent`) to the stub directive's `onClick` method.
Clicking the anchor should trigger the `onClick()` method,
which sets the stub's telltale `navigatedTo` property.
Tests inspect `navigatedTo` to confirm that clicking the anchor
set the expected route definition.
Whether the router is configured properly to navigate with that route definition is a
question for a separate set of tests.
{@a by-directive}
{@a inject-directive}
#### _By.directive_ and injected directives
A little more setup triggers the initial data binding and gets references to the navigation links:
Three points of special interest:
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. Each `DebugElement` exposes a dependency injector with the
specific instance of the directive attached to that element.
The `AppComponent` links to validate are as follows:
{@a app-component-tests}
Here are some tests that confirm those links are wired to the `routerLink` directives
as expected:
The "click" test _in this example_ is misleading.
It tests the `RouterLinkDirectiveStub` rather than the _component_.
This is a common failing of directive stubs.
It has a legitimate purpose in this guide.
It demonstrates how to find a `RouterLink` element, click it, and inspect a result,
without engaging the full router machinery.
This is a skill you may need to test a more sophisticated component, one that changes the display,
re-calculates parameters, or re-arranges navigation options when the user clicks the link.
{@a why-stubbed-routerlink-tests}
#### What good are these tests?
Stubbed `RouterLink` tests can confirm that a component with links and an outlet is setup properly,
that the component has the links it should have, and that they are all pointing in the expected direction.
These tests do not concern whether the app will succeed in navigating to the target component when the user clicks a link.
Stubbing the RouterLink and RouterOutlet is the best option for such limited testing goals.
Relying on the real router would make them brittle.
They could fail for reasons unrelated to the component.
For example, a navigation guard could prevent an unauthorized user from visiting the `HeroListComponent`.
That's not the fault of the `AppComponent` and no change to that component could cure the failed test.
A _different_ battery of tests can explore whether the application navigates as expected
in the presence of conditions that influence guards such as whether the user is authenticated and authorized.
A future guide update will explain how to write such
tests with the `RouterTestingModule`.
{@a page-object}
## Use a _page_ object
The `HeroDetailComponent` is a simple view with a title, two hero fields, and two buttons.
But there's plenty of template complexity even in this simple form.
Tests that exercise the component need ...
- to wait until a hero arrives before elements appear in the DOM.
- a reference to the title text.
- a reference to the name input box to inspect and set it.
- references to the two buttons so they can click them.
- 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.
Tame the complexity with a `Page` class that handles access to component properties
and encapsulates the logic that sets them.
Here is such a `Page` class for the `hero-detail.component.spec.ts`
Now the important hooks for component manipulation and inspection are neatly organized and accessible from an instance of `Page`.
A `createComponent` method creates a `page` object and fills in the blanks once the `hero` arrives.
The [_HeroDetailComponent_ tests](#tests-w-test-double) in an earlier section demonstrate how `createComponent` and `page`
keep the tests short and _on message_.
There are no distractions: no waiting for promises to resolve and no searching the DOM for element values to compare.
Here are a few more `HeroDetailComponent` tests to reinforce the point.
{@a compile-components}
## Calling _compileComponents()_
You can ignore this section if you _only_ run tests with the CLI `ng test` command
because the CLI compiles the application before running the tests.
If you run tests in a **non-CLI environment**, the tests may fail with a message like this one:
Error: This test module uses the component BannerComponent
which is using a "templateUrl" or "styleUrls", but they were never compiled.
Please call "TestBed.compileComponents" before your test.
The root of the problem is at least one of the components involved in the test
specifies an external template or CSS file as
the following version of the `BannerComponent` does.
The test fails when the `TestBed` tries to create the component.
Recall that the app hasn't been compiled.
So when you call `createComponent()`, the `TestBed` compiles implicitly.
That's not a problem when the source code is in memory.
But the `BannerComponent` requires external files
that the compiler must read from the file system,
an inherently _asynchronous_ operation.
If the `TestBed` were allowed to continue, the tests would run and fail mysteriously
before the compiler could finished.
The preemptive error message tells you to compile explicitly with `compileComponents()`.
#### _compileComponents()_ is async
You must call `compileComponents()` within an asynchronous test function.
If you neglect to make the test function async
(e.g., forget to use `waitForAsync()` as described below),
you'll see this error message
Error: ViewDestroyedError: Attempt to use a destroyed view
A typical approach is to divide the setup logic into two separate `beforeEach()` functions:
1. An async `beforeEach()` that compiles the components
1. A synchronous `beforeEach()` that performs the remaining setup.
To follow this pattern, import the `waitForAsync()` helper with the other testing symbols.
#### The async _beforeEach_
Write the first async `beforeEach` like this.
The `waitForAsync()` helper function takes a parameterless function with the body of the setup.
The `TestBed.configureTestingModule()` method returns the `TestBed` class so you can chain
calls to other `TestBed` static methods such as `compileComponents()`.
In this example, the `BannerComponent` is the only component to compile.
Other examples configure the testing module with multiple components
and may import application modules that hold yet more components.
Any of them could be require external files.
The `TestBed.compileComponents` method asynchronously compiles all components configured in the testing module.
Do not re-configure the `TestBed` after calling `compileComponents()`.
Calling `compileComponents()` closes the current `TestBed` instance to further configuration.
You cannot call any more `TestBed` configuration methods, not `configureTestingModule()`
nor any of the `override...` methods. The `TestBed` throws an error if you try.
Make `compileComponents()` the last step
before calling `TestBed.createComponent()`.
#### The synchronous _beforeEach_
The second, synchronous `beforeEach()` contains the remaining setup steps,
which include creating the component and querying for elements to inspect.
You can count on the test runner to wait for the first asynchronous `beforeEach` to finish before calling the second.
#### Consolidated setup
You can consolidate the two `beforeEach()` functions into a single, async `beforeEach()`.
The `compileComponents()` method returns a promise so you can perform the
synchronous setup tasks _after_ compilation by moving the synchronous code
into a `then(...)` callback.
#### _compileComponents()_ is harmless
There's no harm in calling `compileComponents()` when it's not required.
The component test file generated by the CLI calls `compileComponents()`
even though it is never required when running `ng test`.
The tests in this guide only call `compileComponents` when necessary.
{@a import-module}
## Setup with module imports
Earlier component tests configured the testing module with a few `declarations` like this:
The `DashboardComponent` is simple. It needs no help.
But more complex components often depend on other components, directives, pipes, and providers
and these must be added to the testing module too.
Fortunately, the `TestBed.configureTestingModule` parameter parallels
the metadata passed to the `@NgModule` decorator
which means you can also specify `providers` and `imports`.
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:
- `NgModel` and friends in the `FormsModule` to enable two-way data binding.
- The `TitleCasePipe` from the `shared` folder.
- Router services (which these tests are stubbing).
- Hero data access services (also stubbed).
One approach is to configure the testing module from the individual pieces as in this example:
Notice that the `beforeEach()` is asynchronous and calls `TestBed.compileComponents`
because the `HeroDetailComponent` has an external template and css file.
As explained in [_Calling compileComponents()_](#compile-components) above,
these tests could be run in a non-CLI environment
where Angular would have to compile them in the browser.
#### Import a shared module
Because many app components need the `FormsModule` and the `TitleCasePipe`, the developer created
a `SharedModule` to combine these and other frequently requested parts.
The test configuration can use the `SharedModule` too as seen in this alternative setup:
It's a bit tighter and smaller, with fewer import statements (not shown).
{@a feature-module-import}
#### Import a feature module
The `HeroDetailComponent` is part of the `HeroModule` [Feature Module](guide/feature-modules) that aggregates more of the interdependent pieces
including the `SharedModule`.
Try a test configuration that imports the `HeroModule` like this one:
That's _really_ crisp. Only the _test doubles_ in the `providers` remain. Even the `HeroDetailComponent` declaration is gone.
In fact, if you try to declare it, Angular will throw an error because
`HeroDetailComponent` is declared in both the `HeroModule` and the `DynamicTestModule`
created by the `TestBed`.
Importing the component's feature module can be the easiest way to configure tests
when there are many mutual dependencies within the module and
the module is small, as feature modules tend to be.
{@a component-override}
## Override component providers
The `HeroDetailComponent` provides its own `HeroDetailService`.
It's not possible to stub the component's `HeroDetailService` in the `providers` of the `TestBed.configureTestingModule`.
Those are providers for the _testing module_, not the component. They prepare the dependency injector at the _fixture level_.
Angular creates the component with its _own_ injector, which is a _child_ of the fixture injector.
It registers the component's providers (the `HeroDetailService` in this case) with the child injector.
A test cannot get to child injector services from the fixture injector.
And `TestBed.configureTestingModule` can't configure them either.
Angular has been creating new instances of the real `HeroDetailService` all along!
These tests could fail or timeout if the `HeroDetailService` made its own XHR calls to a remote server.
There might not be a remote server to call.
Fortunately, the `HeroDetailService` delegates responsibility for remote data access to an injected `HeroService`.
The [previous test configuration](#feature-module-import) replaces the real `HeroService` with a `TestHeroService`
that intercepts server requests and fakes their responses.
What if you aren't so lucky. What if faking the `HeroService` is hard?
What if `HeroDetailService` makes its own server requests?
The `TestBed.overrideComponent` method can replace the component's `providers` with easy-to-manage _test doubles_
as seen in the following setup variation:
Notice that `TestBed.configureTestingModule` no longer provides a (fake) `HeroService` because it's [not needed](#spy-stub).
{@a override-component-method}
#### The _overrideComponent_ method
Focus on the `overrideComponent` method.
It takes two arguments: the component type to override (`HeroDetailComponent`) and an override metadata object.
The [override metadata object](guide/testing-utility-apis#metadata-override-object) is a generic defined as follows:
type MetadataOverride<T> = {
add?: Partial<T>;
remove?: Partial<T>;
set?: Partial<T>;
};
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.
The type parameter, `T`, is the kind of metadata you'd pass to the `@Component` decorator:
selector?: string;
template?: string;
templateUrl?: string;
providers?: any[];
...
{@a spy-stub}
#### Provide a _spy stub_ (_HeroDetailServiceSpy_)
This example completely replaces the component's `providers` array with a new array containing a `HeroDetailServiceSpy`.
The `HeroDetailServiceSpy` is a stubbed version of the real `HeroDetailService`
that fakes all necessary features of that service.
It neither injects nor delegates to the lower level `HeroService`
so there's no need to provide a test double for that.
The related `HeroDetailComponent` tests will assert that methods of the `HeroDetailService`
were called by spying on the service methods.
Accordingly, the stub implements its methods as spies:
{@a override-tests}
#### The override tests
Now the tests can control the component's hero directly by manipulating the spy-stub's `testHero`
and confirm that service methods were called.
{@a more-overrides}
#### More overrides
The `TestBed.overrideComponent` method can be called multiple times for the same or different components.
The `TestBed` offers similar `overrideDirective`, `overrideModule`, and `overridePipe` methods
for digging into and replacing parts of these other classes.
Explore the options and combinations on your own.