Aliasger Jaffer
Aliasger Jaffer's Blog

Aliasger Jaffer's Blog

Testing a simple angular component

Testing a simple angular component

Correctly set up your test and check the html output value

Aliasger Jaffer's photo
Aliasger Jaffer
·Oct 5, 2021·

3 min read

In my previous posts, I have talked about testing angular services. In this post, I want to start with a simple component.

Below is the typescript file - notice that the component takes a single string input.

import {Component, Input} from "@angular/core";

@Component({
  selector: 'app-hello',
  templateUrl: './hello.component.html'
})
export class HelloComponent {
  @Input() greeting = 'Hello World';
}

The html file is quite straight forward:

<h1>{{greeting}}</h1>

To test this component, we need to:

  1. Configure our TestBed and provide it with the module definition to use.
  2. Get our test fixture - sometimes also called as the test context.
  3. Get our component instance from the fixture
  4. Get our debug element from the fixture

We will set all the above points within the beforeEach function. To store our fixture, component and debug element objects, we will also create a global variable.

describe('HelloComponent', () => {
  let component: HelloComponent;
  let fixture: ComponentFixture<HelloComponent>;
  let el: DebugElement;
  beforeEach(waitForAsync (() => {
    TestBed.configureTestingModule({
      declarations: [HelloComponent]
    }).compileComponents().then(() => {
      fixture = TestBed.createComponent(HelloComponent);
      component = fixture.componentInstance;
      el = fixture.debugElement;
    });
  }));
});

We use the waitForAsync function so that the beforeEach block does not complete and instead, wait for any asynchronous work to complete first. Also, because a component is made up of the typescript and html template files (i.e, using templateUrl), we need to compile our component. Once the compilation has completed, we use the promise API to then get our fixture.

We can check and see if we get a component:

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

Below is a test to confirm that a change of the input variable updates the html template with the expected output:

```typescript it('should show new greeting when passed a greeting', () => { component.greeting = 'Hi test!'; fixture.detectChanges(); const h1 = el.query(By.css('h1')); expect(h1.nativeElement.innerText).toBe('Hi test!'); });

Our spec above does the following:

  1. Using the component instance, access it's greeting input property and set it to a new value of 'Hi test!'.
  2. Call the fixture.detectChanges() method to force change detection. Without this line, our html output will not reflect the new greeting variable value.
  3. Using the debugElement instance, query for an element. The Query function takes in a predicate - the good news is that the platform-browser package provides us with a number of predicates to use with the query function. In our case, we are asking to be returned a debugElement that matches the css selector of 'h1'.
  4. Run the expect statement. Check if the native element (the actual h1 element) has an innerText with the value matching our string we provided to the component's greeting input.

In my next post, we will test a component with a query string and using angular's AppRoutingModule.