Getting started

In this chapter, we will be learning about the initial steps of testing, and we write a simple test case to demonstrate how testing works. Let's get started by cloning the project.

Please run the following command in your favorite command-line program. This will clone the repository on your local machine:

> git clone https://github.com/mohammedzamakhan/ngx-behance

Before we run our test, let's open up a test and understand some basics about Jasmine testing. Let's look at the behance.service.spec.ts file, which looks as follows:

import { TestBed } from '@angular/core/testing';
import { BehanceService } from './behance.service';
import { HttpClientTestingModule } from '@angular/common/http/testing';

describe('BehanceService', () => {
beforeEach(() => TestBed.configureTestingModule({
imports: [HttpClientTestingModule]
}));

it('should be created', () => {
const service: BehanceService = TestBed.get(BehanceService);
expect(service).toBeTruthy();
});
});

The describe function is used to group multiple test cases. Here, we will group all the tests that are related to BehanceService in our describe block. The next thing we will see is beforeEach, which is inside the describe block. The function inside beforeEach runs before all the test cases in describe run. Similarly, Jasmine provides the afterEach, beforeAll, and afterAll methods. The afterEach method runs after each test block runs. If you want to speed things up, you can use beforeAll and afterAll if all the test blocks run some common code before all the tests. We need to be careful when we use beforeAll and afterAll as we cannot reset behavior between multiple tests. We then have the it function, which is used to define a single test case. In our test case, we can use expect to test the expected behavior with the actual behavior. In the preceding code, we have used a matcher called toBeTruthy to check whether the service value is available. There are a lot of different matchers that can be used, some of which are described here, in the Jasmine documents: https://jasmine.github.io/api/edge/matchers.html.

Now that we understand some of the basics of Jasmine testing, let's run the default tests that are generated by the Angular CLI using the following command:

> ng test

This should compile the application and open a browser to run all the test cases. The tests of the application can be found in the *.spec.ts files in the application. After the command finishes running in the browser, you should see that a total of 7 specs (test cases) ran, and that 5 of them failed. This is because the Angular CLI added test cases for the code and then we modified the code for our application but never updated the test cases:

Let's fix all of the errors first, either by changing the tests to pass or by completely deleting that test case. Let's go from top to bottom.

The first test that failed says, AppComponent should have as title 'ngx-behance'. Let's check the test case first before fixing it. We will see that the failure happened because of the following code in the app.component.spec.ts file:

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

In this test case, it's getting an instance of the component and saving it in the app variable, checking whether the title property is equal to ngx-behance. However, when we check our app.component.ts file, we don't have any properties or methods in it. So, let's go ahead and delete this test case altogether.

Let's move to the next test case which says, AppComponent should render title in h1 tag. This test failed because of the following code:

it('should render title in a h1 tag', () => {
const fixture = TestBed.createComponent(AppComponent);
fixture.detectChanges();
const compiled = fixture.debugElement.nativeElement;
expect(compiled.querySelector('h1').textContent).toContain('Welcome to
ngx-behance!
');
});

In this test case, we use debugElement to get access to nativeElement, and then we use querySelector to get access to the h1 tag's textContent, which contains 'Welcome to ngx-behance!'. However, when we check our app.component.html file, we don't find any h1 tags—but we do find an anchor tag that has a textContent of 'Angular Behance'. Let's update our test case to consider that:

it('should render title in a h1 tag', () => {
...

expect(compiled.querySelector('a').textContent).toContain('Angular
Behance
');
});

Now, when you check the browser that runs your test cases, you should see that out of 6 tests, 3 of them failed.

Let's look at the next failed test, that is, BehanceService should be created. Now, if we see an error, we should also see the reason for its failure:

Error: StaticInjectorError(DynamicTestModule)[HttpClient]:         StaticInjectorError(Platform: core)[HttpClient]: 
NullInjectorError: No provider for HttpClient!

From this, we can see that it failed because it could not find the HttpClient service, which should have been injected into the service when it was being created in our test file. In our application, we provide HttpClientModule to our AppModule, but since test cases have to run individually, we need to inject a module into it. We will be injecting HttpClientTestingModule here, which is provided by the Angular team for testing the HttpClient module, in behance.service.spec.ts file:

import { TestBed } from '@angular/core/testing';
import { HttpClientTestingModule } from '@angular/common/http/testing';

import { BehanceService } from './behance.service';

describe('BehanceService', () => {
beforeEach(() => TestBed.configureTestingModule({
imports: [HttpClientTestingModule]
}
));

...

});

This should result in reducing the test failure count to 2. Now, let's check the next failure:

HomeComponent should create
Failed: Template parse errors: Can't bind to 'routerLink' since it isn't a known property of 'a'. (" <div class="row">

This test failed because we used routerLink, which is part of RoutingModule. Similar to HttpClientModule, we need to include a module that can understand routerLink. Again, Angular provides a RouterTestingModule, which we can include in the spec file of our HomeComponent:

...
import { RouterTestingModule } from '@angular/router/testing';

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

beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [ RouterTestingModule ],
declarations: [ HomeComponent ]
})
.compileComponents();
}));
...
});

Now, when we check the browser, we will still have two test failures; the HomeComponent test case failed again because of HttpClient. This happened because HomeComponent uses BehanceService, which in turn uses HttpClient. Let's include HttpClientTestingModule in our HomeComponent, along with RouterTestingModule. Once added, you should only see one test case failing.

This time, our PostComponent failed upon creation because of the following error:

Failed: Template parse errors: The pipe 'colorNamer' could not be found ("of post.colors"> <span class="label label-default label-pill pull-xs-right">{{[ERROR ->]color | colorNamer}}</span> </span>

That means that we have used a pipe called colorNamer, which it couldn't find. Let's declare the pipe in TestingModule and include RouterTestingModule and HttpClientTestingModule since our PostComponent uses routerLink as well as BehanceService:

import { ColorNamerPipe } from '../color-namer.pipe';

beforeEach
(async(() => {
TestBed.configureTestingModule({
imports: [HttpClientTestingModule, RouterTestingModule],
declarations: [ PostComponent, ColorNamerPipe ]
})
.compileComponents();
}));

Now, our Karma spec should show all of our test cases passing:

Now that we have understood the basic structure of Jasmine, how it works, and all our existing test cases have passed, let's focus on testing all of the classes and functions/methods. 

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset