Component tests render a component's actual template and verify both its behavior and its rendered output. This lesson covers TestBed, ComponentFixture, and common DOM assertion patterns.
What Is a Component Test?
A component test uses Angular's TestBed to create a real instance of a component along with its template, rendered into a detached DOM tree. This lets you assert on rendered output, simulate user interaction, and verify inputs/outputs, closer to how the component actually behaves in a real app than a pure unit test of the class alone.
ComponentFixture, returned by TestBed.createComponent(), is the main object you interact with: it exposes the component instance, its native DOM element, and methods to trigger change detection.
describe('CounterComponent', () => {
let fixture: ComponentFixture<CounterComponent>;
beforeEach(() => {
TestBed.configureTestingModule({ imports: [CounterComponent] });
fixture = TestBed.createComponent(CounterComponent);
fixture.detectChanges();
});
it('increments the count when the button is clicked', () => {
const button = fixture.nativeElement.querySelector('button');
button.click();
fixture.detectChanges();
expect(fixture.nativeElement.textContent).toContain('1');
});
});
Because CounterComponent is standalone, it's added to imports rather than declarations in the testing module.
TestBed.createComponent() creates a ComponentFixture wrapping a real component instance and its rendered DOM.
fixture.detectChanges() must be called to apply bindings after setting inputs or triggering state changes.
fixture.nativeElement gives raw DOM access; fixture.debugElement gives Angular-aware querying via By.css()/By.directive().
Standalone components go in the testing module's imports, not declarations.
Component Testing Cheatsheet
Common assertions and interactions in component tests.
Task
Example
Create a component fixture
TestBed.createComponent(MyComponent)
Apply bindings
fixture.detectChanges()
Set an input directly
fixture.componentInstance.value = 'x'
Query the DOM (raw)
fixture.nativeElement.querySelector('.class')
Query the DOM (Angular-aware)
fixture.debugElement.query(By.css('.class'))
Simulate a click
button.click() then fixture.detectChanges()
Spy on an output
fixture.componentInstance.saved.subscribe(spy)
Testing Inputs and Outputs
Component tests can set inputs directly on fixture.componentInstance (bypassing a host template) and subscribe to outputs to assert they emit the expected value in response to interaction.
it('emits ratingChange when a star is clicked', () => {
const fixture = TestBed.createComponent(RatingComponent);
fixture.componentInstance.max = 5;
fixture.detectChanges();
const emitted: number[] = [];
fixture.componentInstance.ratingChange.subscribe((v: number) => emitted.push(v));
const fifthStar = fixture.nativeElement.querySelectorAll('button')[4];
fifthStar.click();
expect(emitted).toEqual([5]);
});
Testing With a Wrapper Host Component
For components that need to be tested more like they're actually used, receiving inputs via real property binding, a small test-only host component wrapping the component under test gives a more realistic setup.
Just like unit tests for services, component tests use TestBed's providers array to substitute real dependencies (like an API service) with test doubles, keeping the test fast and focused on the component's own logic.
Forgetting to call fixture.detectChanges() after changing an input or triggering a state change, then asserting on stale DOM.
Testing a standalone component by adding it to declarations instead of imports in the testing module.
Reaching for real services (like real HttpClient calls) in component tests instead of mocking dependencies.
Over-relying on brittle CSS selectors for querying the DOM instead of stable test attributes or By.directive().
Key Takeaways
Component tests render a real component and template using TestBed and ComponentFixture.
fixture.detectChanges() must be called to apply bindings after any state change during a test.
Inputs can be set directly, or more realistically through a small test-only host component.
Mock injected service dependencies to keep component tests fast and focused.
Pro Tip
For components with meaningful input/output-driven behavior, prefer wrapping them in a small host test component over setting fixture.componentInstance properties directly, it exercises the component the way it's actually used in real templates and catches binding-related bugs a direct property assignment would miss.
You now understand component testing. Next, learn about End-to-End (E2E) Testing for verifying complete user flows in a real browser.