How to perform Unit testing for Angular apps?
By Sandra Felice, Community Contributor - April 21, 2023
Angular is an open-source, JavaScript framework written using TypeScript. It was originally aimed to develop Single Page Applications which use HTML syntax to express the application’s components clearly. It is maintained by Google.
Angular as a framework provides a few advantages while also providing a standard structure for developers. It is designed for web, desktop, and mobile platforms.
Read More: Angular vs AngularJS
What is Angular Unit testing?
Angular Unit testing is the process of testing small and isolated pieces of code (modules) in your Angular application. This provides an added advantage to the users as they can add any new features without breaking any other part of their application.
Jasmine and Karma frameworks are used for Unit Testing of the Angular applications.
Why Angular Unit Testing is important?
Angular Unit Testing ensures that the piece of code under test works as intended. Unit Testing helps uncover bugs caused due to errors in code, such as Syntax Errors, at the early stages of testing. It helps the team gain confidence that the code works well in an isolated environment. This paves the way to other types of testing where these modules of codes are checked for combined utility.
Read More: The Ultimate AngularJS Testing Guide
Angular Unit Testing with Jasmine and Karma
Jasmine is a free and open-source Behavior Driven Development (BDD) framework. It can run on any JavaScript-enabled platform. It attempts to describe tests in a human-readable form so that even people other than the devs can understand the test case. Jasmine does not require DOM. This makes jasmine-core bear low overhead and no external dependencies.
Using Jasmine, one can perform test cases similar to user behavior on a website. It is very beneficial for front-end testing. It includes the responsiveness testing of UI across various devices with different resolutions. One can also automate user behavior with custom delay and wait time for simulating the actual user behavior. Jasmine has extensive community support and comprehensive documentation which makes it easy to use.
Karma is a task runner for our tests. It allows the users to execute their Jasmine test codes in multiple real-time browsers from the command line. This command-line also displays the result of the tests. It watches the files for changes and re-runs the tests automatically. By default, Angular runs on Karma.
Read More: Unit Testing Frameworks in Selenium
How to create an Angular test App?
There are certain prerequisites required before starting with the testing, the first being to write a basic test app.
In order to incorporate Jasmine and Karma, it is advised to use Angular CLI (Node.js) to create your Angular App. This also lets us create a simple Jasmine spec file named the same as the App file but ending in .spec.ts
To create and build a new Angular app, use the following command in your Angular CLI:
ng new simpleApp
This command will create a new sample Angular App called simpleApp. Once the App is created, go to the parent directory of your app and run the below command to run your app in the browser.
Cd simpleApp ng serve
After running the command, CLI will look like this.
Your newly created Angular App will look like this when you open it via http://localhost:4200/
How to write a Unit Test in Angular?
The Angular testing package includes two utilities called TestBed and async. TestBed is the main utility package. (Please see the app.component.spec.ts file below)
There are three main methods in this test file:
- describe() – It’s a suite of Test scripts that calls a global Jasmine function with two parameters: a string and a function. It also consists of beforeEach block.
- it() – It’s the smallest unit test case that is written to be executed, which calls a global Jasmine function with two parameters: a string and a function. Multiple it() statements can be written inside the describe()
- expect() – Every it() statement has a expect() function which takes a value and expects a return in true form
When the sample angular App is created, the test script file is also created alongside. It ends with .spec.ts. Below is what the initial test script file app.component.spec.ts looks like:
import { TestBed } from '@angular/core/testing'; import { AppComponent } from './app.component'; describe('AppComponent', () => { beforeEach(async () => { await 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 'SimpleApp'`, () => { const fixture = TestBed.createComponent(AppComponent); const app = fixture.componentInstance; expect(app.title).toEqual('SimpleApp'); }); it('should render title', () => { const fixture = TestBed.createComponent(AppComponent); fixture.detectChanges(); const compiled = fixture.nativeElement as HTMLElement; expect(compiled.querySelector('.content span')?.textContent).toContain('SimpleApp app is running!'); }); });
In the above code, there are three it() functions that equal three Unit test cases. Now, let’s run the above Unit test cases by using the following command in CLI:
ng test
The CLI will look like this:
A successful test will look something like this in the browser:
Read More: Unit Testing in JavaScript: A Tutorial
How to write a Negative Unit Test in Angular?
Now, let’s rewrite the above app.component.spec.ts file to showcase what a failed test will look like:
import { TestBed } from '@angular/core/testing'; import { AppComponent } from './app.component'; describe('AppComponent', () => { beforeEach(async () => { await 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 'SimpleApp'`, () => { const fixture = TestBed.createComponent(AppComponent); const app = fixture.componentInstance; expect(app.title).toEqual('FreeApp'); }); it('should render title', () => { const fixture = TestBed.createComponent(AppComponent); fixture.detectChanges(); const compiled = fixture.nativeElement as HTMLElement; expect(compiled.querySelector('.content span')?.textContent).toContain('SimpleApp app is running!'); }); });
The second it() function has been modified to have the title as FreeApp. This would result in a negative test since the title of our sample app is SimpleApp.
The CLI will look like this:
A failed test will look like this in the browser:
Similarly, multiple components can be created in your angular app, which will have their own test file that can be used to perform Unit testing.
Conclusion
Jasmine is a testing framework that supports BDD. The tests are written in Test Suites which can contain one or more Test Specs and Test Expectations. We can run Jasmine tests in any browser using a command-line tool called Karma. Karma takes care of handling the process of creating HTML files, opening browsers, running the tests, and returning the results of those tests in the CLI.
Read More: Best Practices for Unit Testing
If Angular CLI is used to manage the Angular projects, it will automatically support Jasmine and Karma Configurations. All you need in order to test your application is to type the command ng test.
As far as possible, run tests on real browsers and devices to ensure that software is verified under real user conditions.
BrowserStack offers a Cloud Selenium Grid of 3000+ real browsers and devices for testing purposes. It also offers Cypress testing on 30+ real browsers versions. Simply sign up, choose the required device-browser-OS combination, and start testing websites for free.