In software engineering, collaboration is key. Therefore, it is important to integrate collaboration into all aspects of the engineering processes during development.
In light of it, Behavior-Driven Development (BDD) is a process that encourages collaboration among developers, quality assurance experts, and customer representatives in a software project.
To achieve effective collaboration amongst development teams, BDD combines general techniques and principles of Test-Driven Development (TDD) to provide collaborative tools for software teams.
Therefore, since BDD is an extension of TDD, it requires tools that integrate the principles of BDD and the extensions of Test-Driven Development. That’s exactly where Jasmine — the open-source JavaScript-based BDD testing framework comes in.
In this Jasmine unit testing tutorial, we will explain the basics of testing with Jasmine and discuss different Jasmine and testing concepts such as test suites, spies, specifications, expectations, matchers, etc. Additionally, you’ll learn from a practical example of writing unit tests with Jasmine to check bugs in your code.
So, let’s get started!
What is Jasmine framework?
Jasmine is a popular open-source JavaScript-based testing framework for unit testing JavaScript applications. It follows a BDD procedure to ensure that each line of JavaScript code is appropriately tested.
In addition, Jasmine has over 15.5k stars and is used by over 2.6m projects on GitHub. It has a strong community of developers, and great documentation is available if you get stuck.
In the next section of this Jasmine unit testing tutorial, we will explore what Jasmine is used for and what type of project you can integrate with Jasmine. You can learn more about the Jasmine framework through this blog on Jest vs Mocha vs Jasmine.
What is the Jasmine framework used for
With over 2.6m projects using Jasmine as their collaborative testing framework. It is clear that software testing remains vital, and Jasmine has gained industry recognition.
In 2000, JsUnit was the available automation testing framework for JavaScript applications, and later, this framework got upgraded to Jasmine.
Angular developers favor Jasmine because it is included natively in Angular projects. In addition, the key value proposition of Jasmine is that it’s easy to set up and write tests.
In the next section of this Jasmine unit testing tutorial, we will elucidate how to use Jasmine. We will discuss the different ways to install, configure, and start using Jasmine to perform your automated testing and BDD.
How to use Jasmine
Now that the fundamentals are out let’s get our hands dirty. Let’s see how to go from zero to hero with Jasmine's unit testing.
There are different ways to install, configure and start using Jasmine in your projects. Let’s explore these different ways.
- Using Standalone Jasmine
- Using Jasmine as a Library
- Using Jasmine via CLI
- Jasmine for browsers
Jasmine is available in different programming languages and can be used to test different microservices written in different languages.
However, this Jasmine unit testing tutorial will focus on JavaScript and explore how to perform Selenium automation testing with the Jasmine framework.
Using Standalone Jasmine
The standalone distribution allows you to run your specs in a web browser. You can start by downloading the latest version from the release page and extracting the file to your preferred location inside the project you want to test.
The extracted file will contain many default files, folders, and sample test cases to get you started:
- /src : This folder contains the source files you want to test. You can delete this folder if your project’s folder is set up differently
- /lib : This folder contains the core Jasmine files and should not be deleted
- /spec : It contains the tests you will write
- SpecRunnner.html : This file is used as a test runner. You run your specs by launching this file in your browser
The code snippet below is the default content of the SpecRunner.html file:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Jasmine Spec Runner v3.2.1</title>
<link rel="shortcut icon" type="image/png" href="lib/jasmine-3.2.1/jasmine_favicon.png">
<link rel="stylesheet" href="lib/jasmine-3.2.1/jasmine.css">
<script src="lib/jasmine-3.2.1/jasmine.js"></script>
<script src="lib/jasmine-3.2.1/jasmine-html.js"></script>
<script src="lib/jasmine-3.2.1/boot.js"></script>
<!-- include source files here... -->
<script src="src/Player.js"></script>
<script src="src/Song.js"></script>
<!-- include spec files here... -->
<script src="spec/SpecHelper.js"></script>
<script src="spec/PlayerSpec.js"></script>
</head>
<body>
</body>
</html>
Most importantly, you can change the source location of the /src and /spec folders to locate your actual source and test files.
Using Jasmine as a Library
You can use Jasmine as a library in your project. The jasmine
module is a command line interface and code for running Jasmine specs with Node.js.
- You can install Jasmine using npm in your project
npm install -Dev jasmine
- Next, you can run the
init
command to initialize and set up Jasmine in your local project.
npx jasmine init
- Lastly, you can load it into your project with your configurations:
var Jasmine = require('jasmine');
var jasmine = new Jasmine();
jasmine.loadConfigFile('spec/support/jasmine.json');
jasmine.execute();
The configuration can be loaded from any location. Also, you can create a custom configuration to fix your project requirements.
Using Jasmine via CLI
- To use this approach, we will install Jasmine globally into our machine, allowing us to use Jasmine across different projects by installing again.
npm install -g jasmine
- In some cases, you may need to run the command with
sudo
when installing npm packages. - Now, we can create a folder for your project and navigate inside it:
mkdir my-jasmine-project & cd ./my-jasmine-project
- Next, run the initialized command to setup Jasmine in your new project:
npx jasmine init
- The command will create the jasmine folder and some default configurations. The most important file is the
jasmine.json
file, which contains the configurations. You can customize the file to fit your project structures.
{
"spec_dir": "spec",
"spec_files": [
"**/*[sS]pec.?(m)js"
],
"helpers": [
"helpers/**/*.?(m)js"
],
"env": {
"stopSpecOnExpectationFailure": false,
"random": true
}
}
Below is the list of some of the important configurations inside the jasmine.json
configuration file.
- spec_dir : It specifies where Jasmine looks for test files
-
spec_files : It specifies the patterns of test files. All the javascript test files will default end with
.spec.js
or contain the wordspec.
- helpers : The helper folder is where Jasmine looks for helper files. These files are executed before specs and can be used to define custom matchers
- stopSpecOnExpectionFailure : This tells Jasmine to stop execution if any test fails. This works if the configuration is set to true
- random : Jasmine will pseudo-randomly run the test cases when set to true
You can find more CLI options from the official documentation when running the Jasmine commands. Below are some of the useful CLI options:
- — config: The config option is used to specify the relative path to where the configuration file is located.
- — no-color: This option turns off colors in spec output.
- — filter: The filter option is used to run only the specs that match a given string.
Set Jasmine as your test script in your package.json file:
“scripts”: { “test”: “jasmine” }
Jasmine for browsers
You can also use Jasmine in the browser, if you’re working on the frontend, you can install Jasmine into your project and test out your frontend projects.
- Run the following command to add Jasmine to your package.json: npm install — save-dev jasmine-browser-runner jasmine-core Here is the screenshot of the output
- Initialize Jasmine in your project: npx jasmine-browser-runner init
- Set Jasmine as your test script in your package.json file: “scripts”: { “test”: “jasmine” } Moreover, choosing a specific approach depends on your project requirements and use cases. Is any approach still using Jasmine as your BDD?
- Finally, to run your test, use the NPM command below: npm test
In this section of this Jasmine unit testing tutorial, we explore different methods to set up Jasmine for your testing needs. In the next section of this Jasmine unit testing tutorial, we will understand the Jasmine testing framework deeper and explore the general keywords used in Jasmine and software testing.
Understanding Jasmine's testing framework
This section will explore the basic elements of Jasmine's testing, such as suites, specs, expectations, matchers, spies, etc.
We will start by creating a demo project that will enable us to practically learn and understand the different elements used in Jasmine testing.
The snippet above is a simple Fibonacci series computation. We will use it to understand the different elements of Jasmine's testing.
function fibonacci(num, memo) {
memo = memo || {};
if (memo[num]) return memo[num];
if (num <= 1) return 1;
return (memo[num] = fibonacci(num - 1, memo) + fibonacci(num - 2, memo));
}
module.exports = {
fibonacci: fibonacci,
}
Suites
A suite is a group of specs or test cases. It’s used to test a group of features or behavior of the JavaScript code. It’s usually encapsulated by an object/class or a function. You can define a suite of test cases using the describe
block.
The describe
block takes two required parameters — a string for the suite name and a function that implements the actual code of the test suite.
Let’s explore an example of our first Jasmine test suite:
describe('Test Helpers', function () {
/**
* Add all your related test cases here
*
*/
});
With the describe
block, you can group related blocks for better organizing and accurately describing test cases.
describe('Test Helpers', function () {
/**
* Add all your related test cases here
*
*/
});
describe('Test Authentication', function () {
/**
* Add all your related test cases here
*
*/
});
Excluding a suite can be done by adding x
to the describe
function for instance xdiscribe()
. This will temporarily disable a suite making all the specs within the disabled describe
block marked as pending and not executed in the report.
Specs
A spec declares a specific test that belongs to a test suite. This is achieved by calling the Jasmine global function it()
, which takes two parameters. The spec title and a function that implements the actual test case.
A spec may contain one or more expectations used to determine the correctness of the test. Each expectation is simply an assertion that can return true or false. When an expectation returns true, the spec is passed but fails when the expectation returns false.
Here is how to declare a spec:
describe('Test Helpers', function () {
it('should calculate Fibonacci series', function () {
/*...*/
});
});
We can also exclude individual specs from execution by adding x to the xit() function. Jasmine will ignore this particular test and also ignore reporting it.
Expectations
Expectations are created using the expect function. They take a value called the actual. The actual value is compared with a matcher function and returns the falsity or truthy of the comparison.
You can chain many expect() functions with multiple matchers to obtain different results from your test cases.
Here is a simple example of using the except function for comparison:
describe('Test Helpers', function () {
it('should calculate Fibonacci series', function () {
const fib = Fibonnaci(4);
expect(fib).toEqual(3);
});
});
Expectations can come in different formats depending on your use cases and the type of matchers you decide to use to obtain your result.
Matchers and Custom Matchers
Jasmine provides a rich set of built-in matchers. Let’s explore some important ones:
- toBe(): It’s used for testing identity.
- toBeNull(): It’s used for testing for null.
- toBeUndefined()/toBeDefined(): It’s used for testing for undefined and not undefined, respectively.
- toBeNaN(): It’s used for testing for NaN (Not a Number).
- toBeFalsy()/toBeTruthy(): It tests falseness and truthfulness, respectively.
- toEqual: It’s used for testing for equality.
You can find the full list of matchers from the docs.
The code snippet below shows a simple implementation of our specs with some of the matchers.
describe('Test Helpers', function () {
it('should calculate Fibonacci series', function () {
const fib = Fibonnaci(4);
expect(fib).toEqual(5);
expect(fib).toBeDefined();
expect(fib).toBeNaN().toBeFalsy();
});
});
Jasmine provides the ability to define your custom matcher to satisfy your use case. You can create a custom assertion function not covered by the built-in matcher.
Using beforeEach and afterEach
Jasmine provides two global functions for initializing and cleaning your specs. They are the beforeEach and afterEach functions.
- The
beforeEach
function is called once before each spec in the suite. - The afterEach function is called once before each spec in the suite.
For instance, if you need to initial variables to use in each of your test suites, you can simply add the initialization process inside the beforeEach
function, and it will be initialized on every test case. Also, you can reset any variable of your choice using the afterEach
function.
In the next section of this Jasmine unit testing tutorial, we will explore how to set up the Jasmine testing environment and configure Jasmine to work with our demo project setup.
How to set up the Jasmine test environment?
In the previous section of this Jasmine unit testing tutorial, we discussed the different ways to use Jasmine in your project. In this section, we will learn how to initialize your testing environment and configure Jasmine to work with our project setup.
We are going to use Jasmine as a library in this demo project. The jasmine
module is a command line interface and code for running Jasmine specs with Node.js.
- You can install Jasmine using npm in your project:
npm install –Dev jasmine
- Next, you can run the
init
command to initialize and set up Jasmine in your local project.
npx jasmine init
- The command will create a
spec
folder. Open the./spec
folder and add all your test files. In addition, the configuration file is also found in this folder; you can configure it from there. Moreover, the configuration can be loaded from any location; also you can create a custom configuration to fix your project requirements.
Here is the default configuration file:
{
"spec_dir": "spec",
"spec_files": [
"**/*[sS]pec.?(m)js"
],
"helpers": [
"helpers/**/*.?(m)js"
],
"env": {
"stopSpecOnExpectationFailure": false,
"random": true
}
}
After configuring the file, add the testing script to your package.json file and use the test command to run your test cases.
"scripts": {
"test": "jasmine"
}
Lastly, use the following to run your test suites:
npm run test
In the next section of this Jasmine unit testing tutorial, we will follow these steps to test the registration form demo Node.js application we have created for this Jasmine unit testing tutorial.
How to test Node.js applications with Jasmine?
In this Jasmine unit testing tutorial section, we will build and test a registration form in Node.js using Express and Jasmine.
- First, we will create a new project or clone from this repository.
- Open the
index.html
file and add the following code if you created a new project.
<h1>Registration form</h1>
<div class="form-container">
<form name="registerForm" method="POST">
<label for="firstName">First Name *</label>
<input
type="text"
id="firstName"
name="firstName"
placeholder="John"
required
/>
<p class="error-message"></p>
<label for="lastName">Last Name *</label>
<input type="text" id="lastName" placeholder="Doe" required />
<p class="error-message"></p>
<label for="e-mail">E-mail address *</label>
<input
type="text"
id="e-mail"
placeholder="john-doe@net.com"
required
/>
<p class="error-message"></p>
<label for="phoneNumber">Phone Number</label>
<input
type="text"
id="phoneNumber"
maxlength="9"
pattern=".{9,}"
required
title="9 characters length"
placeholder="223587972"
/>
<p class="error-message"></p>
<label for="country">Country</label>
<input type="text" id="country" placeholder="United Kingdom" />
<p class="error-message"></p>
<label for="password">Password *</label>
<input
type="password"
id="password"
pattern=".{8,}"
required
title="8 characters minimum"
/>
<p class="error-message"></p>
<p class="password-rules">
Your password should contain at least 8 characters and 1 number.
</p>
</form>
- Next, add a
style.css
file and style your form to look presentable, or copy the CSS style file from the repository for this project. - If everything is properly set up, you should be presented with a well-formatted HTML page inspired by the Aliens’ Registration Form with validation.
- Next, we will create different test files to test the different input validation functions and test the Express server post request to make sure we have the expected result.
- Lastly, we will add more validation functions to the helper.js file we created earlier. Here are some of the functions we added.
/*first name input validation*/
function FirstName(fname) {
var letters = /^[A-Za-z]+$/;
if (fname.match(letters)) {
return true;
} else {
return false;
}
}
/*last name input validation*/
function LastName(lname) {
var letters = /^[A-Za-z]+$/;
if (lname.match(letters)) {
text = '';
return true;
} else {
return false;
}
}
/*email address input validation*/
function Email(email) {
var mailformat = /^w+([.-]?w+)*@w+([.-]?w+)*(.w{2,3})+$/;
var atpos = email.indexOf('@');
var dotpos = email.lastIndexOf('.');
if (email.match(mailformat) || (atpos > 1 && dotpos - atpos > 2)) {
return true;
} else {
return false;
}
}
/*phone number validation*/
function PhoneNumber(pnumber) {
var numbers = /^[0-9]+$/;
if (pnumber.match(numbers)) {
return true;
} else {
return false;
}
}
/*country input validation*/
function Country(country) {
var letters = /^[A-Za-z]+$/;
if (country.match(letters)) {
return true;
} else {
return false;
}
}
/*validate password*/
function Password(password) {
var illegalChars = /[W_]/; // allow only letters and numbers
if (illegalChars.test(password)) {
return false;
} else if (password.search(/[0-9]+/) == -1) {
return false;
} else {
return true;
}
}
The code snippet is already self-explanatory with the use of comments. We are validating different inputs for each param passed to the individual functions.
Creating the test files
First, we will create the validations.spec.js
file inside the newly created spec
folder and add the following codes to cover the Validation test suites.
const {
validateCountry,
validatePassword,
validatePhoneNumber,
validateEmail,
validateLastName
} = require('../helpers');
describe('Validation Helpers', function () {
it('should validate country', function () {
const country = validateCountry('nigeria');
expect(country).toEqual(true);
});
it('should validate acceptable password', function () {
const password = validatePassword('Password1');
expect(password).toEqual(true);
});
it('should validate wrong password', function () {
const password = validatePassword('Password');
expect(password).toEqual(false);
});
it('should validate good PhoneNumber', function () {
const password = validatePhoneNumber('081456552232');
expect(password).toEqual(true);
});
it('should validate empty PhoneNumber', function () {
const password = validatePhoneNumber('');
expect(password).toEqual(false);
});
it('should validate good email', function () {
const email = validateEmail('test@test.com');
expect(email).toEqual(true);
});
it('should validate empty email', function () {
const email = validateEmail('');
expect(email).toEqual(false);
});
it('should validate good last name', function () {
const lastName = validateLastName('Solomon');
expect(lastName).toEqual(true);
});
});
The code snippet above uses the different concepts we have explained above to create a test suite for making sure our validation methods work as expected.
Running Jasmine Test
Lastly, we will run the test to see if it passes or not. Type the following command into your root terminal.
npm run test
If your test is successful, you should see three 12 cases passed, as shown in this figure.
In this section of this Jasmine unit testing tutorial, we have demonstrated how to configure and structure software testing with Node.js using the latest Jasmine testing library. We have also learned how to write a basic unit test.
BDD encourages collaboration even in software testing, and Jasmine's testing framework builds on these principles to deliver a collaborative testing environment for the software engineering team.
Software testing is a very important aspect of software development. It ensures that the software under test meets the intended requirement, is defect-free, and is free of errors and bugs.
In this Jasmine unit testing tutorial, we discussed the overview of Jasmine and how it implements BDD principles. We explored the different ways to use Jasmine in your JavaScript projects and elucidate the different elements of the Jasmine testing framework.
In this Selenium JavaScript tutorial, we implemented a simple registration form demo Node.js application using Expressjs. Lastly, we use Jasmine to implement the JavaScript unit testing method to validate users’ input to ensure it’s in the correct format.
Originally published at https://www.lambdatest.com.
Top comments (0)