Angular Component DOM Testing - The Complete Guide For Beginners


Writing DOM tests for my Angular components looked overwhelming. But my frustration soon changed to glee when I discovered how simple it was.

Want to skip the read and starting writing code right away? Then click here.

How do you write DOM tests for your Angular components?

Maybe you're already writing unit tests for your classes but are beginning to realize that testing a component often involves more than just testing a class.

Why?

Because an Angular component interacts with the DOM as well as other components and visual pieces of your Angular applications.

A class test will only tell you how that specific class behaves. But it doesn't actually test if it is properly displaying.

That's where Angular component DOM tests come in.

They'll help you make sure that the component is rendering properly and that events like clicks are firing properly, how it responds to user input or how it integrates with child and parent components.

Since Angular is a dynamic front-end framework, it's common for a component to have complicated DOM interactions that dynamically render the page.

That's why we need DOM tests to verify that our component is behaving like it was designed to behave.

So how do we get started?

Using the automatically generated DOM tests to get started with a BOOM! 💥 💥 💥

Most Angular developers use the Angular CLI to create and manage their Angular application.

And one of the cool features of the Angular CLI is that when you create a component, it automatically generates some basic tests for you unless you specifically tell it not to. For example, after generating a new Angular application, you can open the app.component.spec.ts file and find these example DOM tests.

import { TestBed, async } from '@angular/core/testing';
import { AppComponent } from './app.component';

describe('AppComponent', () => {
  beforeEach(async(() => {
    TestBed.configureTestingModule({
      declarations: [
        AppComponent
      ],
    }).compileComponents();
  }));

  it('should create the app', () => {
    const fixture = TestBed.createComponent(AppComponent);
    const app = fixture.componentInstance;
    expect(app).toBeTruthy();
  });

  it(`should have as title 'hello-world'`, () => {
    const fixture = TestBed.createComponent(AppComponent);
    const app = fixture.componentInstance;
    expect(app.title).toEqual('hello-world');
  });

  it('should render title', () => {
    const fixture = TestBed.createComponent(AppComponent);
    fixture.detectChanges();
    const compiled = fixture.nativeElement;
    expect(compiled.querySelector('.content span').textContent).toContain('hello-world app is running!');
  });
});

As you can see in the code above, it uses the beforeEach to create and configure the component we're testing (more on this later).

Once we've got an instance of ourAngular component, we use a selector to get a reference to a specific HTML element inside the component and then run our expect(...) statements to test the state of the DOM.

The Angular CLI will also generate a few sample tests when you create a new component.

For example, if we generate a component called login...

ng generate component login

We'll get a login.component.spec.ts file that looks like this.

import { async, ComponentFixture, TestBed } from '@angular/core/testing';

import { LoginComponent } from './login.component';

describe('LoginComponent', () => {
  let component: LoginComponent;
  let fixture: ComponentFixture<LoginComponent>;

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      declarations: [ LoginComponent ]
    })
    .compileComponents();
  }));

  beforeEach(() => {
    fixture = TestBed.createComponent(LoginComponent);
    component = fixture.componentInstance;
    fixture.detectChanges();
  });

  it('should create', () => {
    expect(component).toBeTruthy();
  });
});

All this to say that the Angular CLI is a great companion when you're testing your Angular application.

It helps get you started by giving the basic set up and examples that will allow you to then focus on your specific testing needs.

Say, what is TestBed?

As you probably noticed in the testing examples above, we're using something called TestBed to create a testing module.

And if you're not familiar with TestBed, then you're probably wondering what it's for.

Well...

Before we can do DOM testing operations, we first have to set up the component and configure it. Once created, we'll give our tests a reference to this component.

But...

Often, a component has dependencies like services and modules that it requires to operate. And manually initializing a component's dependencies is like trying to chew leather with only 4 teeth.

This is where TestBed comes in.

Whenever you test a component you'll begin by creating a TestBed which is responsible to configure and initialize an environment to test our components.

And now that we know what TestBed is for, how do we write our very first DOM test?

Writing your very first Angular component DOM test. From scratch.

So, what do you need to know to write your first DOM test?

And how do you get started when you're lost?

Every Angular test starts with a describe function that's used to describe the piece of code that we're testing.

Like this...

describe('MyComponent', () => {
    // Set up and test here
});

The next step is to create the object we'll be testing, mock its dependencies and so forth.

It will look something like this.

describe('MyComponent', () => {
    let component: MyComponent;
    let fixture: ComponentFixture<MyComponent>;

    beforeEach(() => {
        fixture = TestBed.createComponent(LoginComponent);
        component = fixture.componentInstance;
        fixture.detectChanges();
    });
});

So what have we just done?

First, we declared a variable that will be the component we're testing. And we also declared a second variable that will be our ComponentFixture used to debug and test our component.

Then, we used the beforeEach function to do our set-up and initialization. This is a function that will be called every time a test is run. Its purpose is to avoid repetitive set up code.

Now, we've got everything ready to finally write our test!

We'll write an it test to describe what we expect our object (in this case an Angular component) to do.

describe('MyComponent', () => {
    let component: MyComponent;
    let fixture: ComponentFixture<MyComponent>;

    beforeEach(() => {
        fixture = TestBed.createComponent(LoginComponent);
        component = fixture.componentInstance;
        fixture.detectChanges();
    });

    it("H1 tag should be Hello World", () => {
    var h1: HTMLElement = fixture.nativeElement.querySelector("h1");
    expect(h1.textContent).toEqual("Hello World");  
  })
});

Tada!

We just wrote our first Angular DOM test by grabbing the H1 element inside our component and verifying that the text we expect is the text that is actually being displayed.

Simple?

Yeah. Angular DOM testing doesn't have to be hard.

Want to see some more advanced examples?

How to check for specific text

it('should render title', () => {
    const fixture = TestBed.createComponent(AppComponent);
    fixture.detectChanges();
    const compiled = fixture.nativeElement;
    expect(compiled.querySelector('.content span').textContent).toContain('hello-world app is running!');
  });

How to check for an attribute

it('image should have alt tag of "Login Image"', () => {
    let image: HTMLElement = fixture.nativeElement.querySelector("img");
    expect(image.getAttribute("alt")).toEqual("Login Image");
});

How to check image width and height

it('image should have width of 250px and height of 150px', () => {
    let image: HTMLElement = fixture.nativeElement.querySelector("img");
    expect(image.getAttribute("width")).toEqual("250px");
    expect(image.getAttribute("height")).toEqual("150px");
});

Conclusion

And that, my friend, is how to write DOM tests for your Angular component without breaking a sweat or popping a pimple.

Keep in mind that DOM tests can become brittle if you're not careful. So don't just blindly wield your new testing sword but use it wisely by properly testing the things that matter.

And as always, if you have any questions or comments don't hesitate to reach out.

signature

Angular Consultant

P.S. If you're one of those that likes to skip to the bottom (like me) then this article will show you how to...

  • Write your first Angular component DOM test.
  • How DOM testing is different from basic class testing.
  • Why basic class testing isn't good enough for an Angular component.
  • How to test an image and make sure it's the right width and height.
  • And how to juggle 3 monkeys with your feet and toes. Just kidding. 😆