Unit Testing Tool ‐ JasmineJS - JUCSE49-Mavericks/Smart-Class-Routine-Management-System GitHub Wiki
Author: Rubayed All Islam (RAI) - 370
Jasmine is an open-source JavaScript framework, capable of testing any kind of JavaScript application. Jasmine follows Behavior Driven Development (BDD) procedure to ensure that each line of JavaScript statement is properly unit tested. By following BDD procedure, Jasmine provides a small syntax to test the smallest unit of the entire application instead of testing it as a whole.
Following are the advantages of using Jasmine over other available JavaScript testing frameworks:
- Jasmine does not depend on any other JavaScript framework.
- Jasmine does not require any DOM.
- All the syntax used in Jasmine framework is clean and obvious.
- Jasmine is heavily influenced by Rspec, JS Spec, and Jspec.
- Jasmine is an open-source framework and easily available in different versions like stand-alone, ruby gem, Node.js, etc.
Jasmine is very easy to implement in any kind of development methodology. All you need to download is the standalone library files from the official website https://jasmine.github.io/ and implement the same in your application.
In this chapter, we will discuss the step-by-step procedure of how to set up a Jasmine-based BDD testing application.
Go to the official website of Jasmine: https://jasmine.github.io/
Click on any of the version links. It is preferable to use the most recent version, which is labeled as "Edge". You will be redirected to the homepage of the selected version.
Go to the Download section of the homepage and click on the standalone release page.
Once you are redirected to the GitHub release page, download the Zip file from there.
Unzip the downloaded jasmine-standalone-2.4.1
folder. You will see the following folder structure:
jasmine-standalone-2.4.1/
├── SpecRunner.html
├── lib/
│ └── jasmine-2.4.1/
├── spec/
│ └── your_spec.js
└── src/
└── your_code.js
Create a web application project in your favorite IDE (e.g., NetBeans, Visual Studio Code, etc.), and add the downloaded library files to the application. After adding the Jasmine framework, the directory structure of your application should resemble the following:
my-jasmine-project/
├── SpecRunner.html
├── lib/
│ └── jasmine-2.4.1/
├── spec/
│ └── my_spec.js
└── src/
└── my_code.js
The Jasmine module is a command line interface and supporting code for running Jasmine specs under Node.js. Jasmine 5.x supports Node versions 18, 20, and 22 (odd-numbered Node versions aren’t supported, but many of them work).
You can install Jasmine locally in your project using npm:
npm install --save-dev jasmine
With this local installation, you can invoke the CLI tool using npx
:
npx jasmine
Optionally, you can install Jasmine globally, but this is not recommended as it can lead to version mismatches across different projects:
npm install -g jasmine
To initialize a project for Jasmine, create a spec directory and configuration JSON file:
npx jasmine init
You can generate example spec and source files with the following command:
npx jasmine examples
At this point, you should be able to write your first test suite.
Customize spec/support/jasmine.json
to specify the source files and spec files for the Jasmine runner. You can use glob patterns to include or exclude files.
Example configuration:
{
"spec_dir": "spec",
"spec_files": [
"**/*[sS]pec.?(m)js",
"!**/*nospec.js"
],
"helpers": [
"helpers/**/*.?(m)js"
],
"env": {
"failSpecWithNoExpectations": false,
"stopSpecOnExpectationFailure": false,
"stopOnSpecFailure": false,
"random": false
}
}
You can also specify a different config file using the --config
command line argument or the JASMINE_CONFIG_PATH
environment variable:
jasmine JASMINE_CONFIG_PATH=relative/path/to/your/jasmine.json
jasmine --config=relative/path/to/your/jasmine.json
Once you have set up your jasmine.json
, you can execute all your specs by running:
jasmine
To run a specific spec or those in files matching a certain glob pattern:
npx jasmine spec/appSpec.js
npx jasmine "**/model/**/critical/**/*Spec.js"
You can filter specs based on their filename or a regex pattern:
npx jasmine "spec/**/critical/*Spec.js" # Single pattern
npx jasmine spec/currentSpec.js # Single file
npx jasmine --filter "adapter21*" # By spec name
Jasmine loads your code using dynamic import, compatible with both ES modules and CommonJS. A script is treated as an ES module if its name ends with .mjs
or if the package’s package.json
contains "type": "module"
.
You can configure Jasmine to load scripts using require
by adding "jsLoader": "require"
to your config file.
-
JASMINE_CONFIG_PATH: Specify a path to your configuration file.
JASMINE_CONFIG_PATH=spec/config/jasmine.json jasmine npx jasmine --config=spec/config/jasmine.json
-
--no-color: Turns off color in spec output.
npx jasmine --no-color
-
--filter: Only runs specs that match the given string.
npx jasmine --filter="a spec name"
-
--fail-fast: Stops execution after the first failure.
npx jasmine --fail-fast=true
-
--random: Runs specs in random order.
npx jasmine --random=true
-
--seed: Sets the randomization seed.
npx jasmine --seed=4321
-
--reporter: Sets the default reporter.
npm i --save-dev jasmine-ts-console-reporter npx jasmine --reporter=jasmine-ts-console-reporter
For more granular control over configuration, Jasmine can be used as a library:
const Jasmine = require('jasmine');
const jasmine = new Jasmine();
// Load configuration
jasmine.loadConfigFile('spec/support/jasmine.json');
// Load configuration from an object
jasmine.loadConfig({
spec_dir: 'spec',
spec_files: [
'appSpec.js',
'requests/**/*[sS]pec.js',
'utils/**/*[sS]pec.js'
],
helpers: [
'helpers/**/*.js'
]
});
// Custom completion handler
jasmine.exitOnCompletion = false;
const result = await jasmine.execute();
if (result.overallStatus === 'passed') {
console.log('All specs have passed');
} else {
console.log('At least one spec has failed');
}
// Running tests
jasmine.execute();
A default ConsoleReporter is included if no other reporters are added. You can configure it with configureDefaultReporter
:
jasmine.configureDefaultReporter({
timer: new jasmine.jasmine.Timer(),
print: function() {
process.stdout.write(arguments);
},
showColors: true
});
// Add custom reporter
const CustomReporter = require('./myCustomReporter');
jasmine.addReporter(new CustomReporter());
You can call execute()
to run the specs:
jasmine.execute();
You can optionally specify a list of spec file paths or a filter by spec name.
jasmine.execute(['fooSpec.js'], 'a spec name');
const Jasmine = require('jasmine');
const jasmine = new Jasmine();
jasmine.loadConfigFile('spec/support/jasmine.json');
jasmine.configureDefaultReporter({
showColors: false
});
jasmine.execute();
Your environment setup is now complete! You can now start writing and running your unit tests using the Jasmine framework.
In this chapter, we will create a Hello World app that will test our helloworld.js
file. Before developing the Hello World app, go back to the previous chapter and make sure that your environment is ready to be tested using Jasmine.
Here we are using NetBeans 8.1 to develop our Hello World app in Jasmine. In NetBeans, go to File → New Project → Html5/JS application and create a project. After creating the project, the project directory should look like the following screenshot. We named our project as Jasmine_Demo.
Jasmine_Demo/
├── src/
├── spec/
└── SpecRunner.html
After creating the demo project, all you need to do is include the unzipped folder of the Jasmine library in the Unit Tests folder of the created application. After adding all the library files to our application folder, the structure of our project will look as shown in the following screenshot.
Jasmine_Demo/
├── lib/
│ └── jasmine-2.4.1/
├── src/
├── spec/
└── SpecRunner.html
The files under the spec
and src
folders are demo files provided by the Jasmine team. Delete these files, as we are going to create our own test file and test case. While deleting those JavaScript files, we need to delete the reference to those files inside our output HTML file, which is SpecRunner.html
.
Following is the screenshot of the SpecRunner.html
file where the reference of different JavaScript files inside spec
and src
will be deleted.
In this step, we will create a JavaScript file named helloworld.js
under the src
folder. This is the file which we will test through Jasmine. After creating the JavaScript file, append the following code inside the file:
/*
* This is the JavaScript file that needs to be tested through Jasmine.
* Below is the helloworld function that will return 'Hello World'.
*/
var helloworld = function() {
return 'Hello World';
};
In this step, we will create another JavaScript file that will contain the test case for the above-mentioned JavaScript file. Go ahead and create a JavaScript file under the spec
folder and name it HelloWorldsSpec.js
. Add the following code into this file:
/*
* This is the file which will call our JavaScript file that needs to be tested.
* Each describe block is equivalent to one test case.
*/
describe("Hello World", function() {
it("should return Hello World", function() {
expect(helloworld()).toEqual('Hello World');
});
});
We successfully created our own file to be tested and the corresponding test case. We kept them under two different folders. In this step, we will modify SpecRunner.html
to include the reference to these two newly created files.
<!DOCTYPE html>
<html>
<head>
<meta charset = "utf-8">
<title>Jasmine Spec Runner v2.4.1</title>
<link rel = "shortcut icon" type = "image/png" href =
"lib/jasmine2.4.1/jasmine_favicon.png">
<link rel = "stylesheet" href = "lib/jasmine-2.4.1/jasmine.css">
<script src = "lib/jasmine-2.4.1/jasmine.js"></script>
<script src = "lib/jasmine-2.4.1/jasmine-html.js"></script>
<script src = "lib/jasmine-2.4.1/boot.js"></script>
<!-- Lines to be deleted
<script src = "src/Player.js"></script>
<script src = "src/Song.js"></script>
<script src = "spec/SpecHelper.js"></script>
<script src = "spec/PlayerSpec.js"></script> -->
<!-- Adding the reference of our newly created files -->
<script src = "src/helloworld.js"></script>
<script src = "spec/HelloWorldsSpec.js"></script>
</head>
<body>
</body>
</html>
This is the final step of our application development. Run SpecRunner.html
in any of your favorite browsers. The following screenshot will appear as a result. The green screen indicates success, whereas red indicates a failure in the test case.
Result Screenshot
So far, we have seen the success test case of the Hello World application. Now, let us see what happens when something goes wrong, and the test fails. To implement a failure case, we need to write a failure test case. To do the same, we are going to modify the helloworld.js
file using the following code:
var helloworld = function () {
return '';
};
We are not returning any string, whereas in the spec file, we are expecting the string "Hello World". The above code is definitely going to fail because our spec file is not getting the expected string as an output of the helloworld()
function. The following screenshot of the SpecRunner.html
file depicts the error with its red indicator.
Jasmine follows the Behavioral Driven Development (BDD) framework. Before learning the working principle of Jasmine, let us first understand what the BDD framework is.
The following flowchart depicts the different phases of the BDD framework.
BDD Framework Flowchart
In this phase, we will make our environment ready for the Jasmine application.
In this step, we will write our first test case. It is obvious that this test will fail because there is no file or function to be tested yet.
In this phase, we will create our JavaScript file or function that needs to be tested. This step is crucial as we need to ensure that all the test cases we wrote earlier will pass.
Refactor is a very important phase of the BDD model, where we need to create as many test cases as we can for the particular application or function.
If everything is going well, your application should be complete and functioning. This step marks the end of the BDD application development.
Now that we have some understanding of the working principles of the BDD framework, let’s see how Jasmine follows this framework for JavaScript testing.
As the following diagram depicts, we need to test Abc.js
using the Jasmine framework. SpecRunner.html
is the output file that will take Spec.js
(test case file), Abc.js
(file to be tested), and LIB
as inputs, run all the test cases present in the spec file, and render the result in the browser.
BDD Framework Example Diagram
-
Lib: These are the built-in JavaScript files that help test different functions and other JavaScript files used in the project.
-
Spec.js (Test Case File): This is the JavaScript file containing all the test cases needed to test any JavaScript function or file. In the BDD methodology, we write the test first, so this file is updated first. Initially, this will fail as there is no file or function present yet to test. The test case file can be refactored multiple times until all functionalities are successfully tested.
-
Abc.js (File to Be Tested): This file contains your functionalities, which will be unit tested using the
Spec.js
andLib
files. -
SpecRunner.html: This is a normal HTML file that renders the output of the unit test using embedded JavaScript code. It takes
Spec.js
,Abc.js
, andLib
as inputs and displays the result in a browser.
In this chapter, we will discuss the building blocks of tests in Jasmine.
Jasmine is a testing framework for JavaScript. A Suite is the basic building block of the Jasmine framework. The collection of similar types of test cases written for a specific file or function is known as a suite. It contains two other blocks: describe()
and it()
.
A Suite block can have only two parameters: the "name of the suite" and the "function declaration" that actually makes a call to the unit functionality to be tested.
In the following example, we will create a suite that will unit test the add
function in the add.js
file. In this example, our JS file is named calculator.js
and the corresponding Jasmine spec file is CalCulatorSpec.js
.
window.Calculator = {
currentVal: 0,
varAfterEachExample: 0,
add: function (num1) {
this.currentVal += num1;
return this.currentVal;
},
addAny: function () {
var sum = this.currentVal;
for (var i = 0; i < arguments.length; i++) {
sum += arguments[i];
}
this.currentVal = sum;
return this.currentVal;
},
};
describe("calculator", function() {
// Test case: 1
it("should retain the current value all the time", function () {
expect(Calculator.currentVal).toBeDefined();
expect(Calculator.currentVal).toEqual(0);
});
// Test case: 2
it("should add numbers", function() {
expect(Calculator.add(5)).toEqual(5);
expect(Calculator.add(5)).toEqual(10);
});
// Test case: 3
it("should add any number of numbers", function () {
expect(Calculator.addAny(1, 2, 3)).toEqual(6);
});
});
In this example, we have declared two functions. The add
function adds two numbers, and the addAny
function adds any number of arguments.
After creating this file, add it to SpecRunner.html
inside the head section. Upon successful execution, this will generate the following output.
Output Screenshot
A Suite block can contain other suite blocks inside it. The following example shows how we can create different suite blocks inside another suite block. We will create two JavaScript files: NestedSpec.js
and nested.js
.
describe("nested", function() {
// Starting of the first suite block
describe("Retaining values", function () {
// Test case: 1
it("should retain the current value all the time", function () {
expect(nested.currentVal).toBeDefined();
expect(nested.currentVal).toEqual(0);
});
}); // End of the suite block
// Second suite block
describe("Adding a single number", function () {
// Test case: 2
it("should add numbers", function() {
expect(nested.add(5)).toEqual(5);
expect(nested.add(5)).toEqual(10);
});
}); // End of the suite block
// Third suite block
describe("Adding different numbers", function () {
// Test case: 3
it("should add any number of numbers", function() {
expect(nested.addAny(1, 2, 3)).toEqual(6);
});
}); // End of the suite block
});
window.nested = {
currentVal: 0,
add: function (num1) {
this.currentVal += num1;
return this.currentVal;
},
addAny: function () {
var sum = this.currentVal;
for (var i = 0; i < arguments.length; i++) {
sum += arguments[i];
}
this.currentVal = sum;
return this.currentVal;
}
};
The above code will generate the result of running specRunner.html
after adding the file inside the head section.
SpecRunner Result Screenshot
The describe block is part of the Suite block. Like the Suite block, it contains two parameters: the "name of the describe block" and the "function declaration". The following is an example of a complete describe block:
describe("Adding a single number", function () {
it("should add numbers", function() {
expect(nested.add(5)).toEqual(5);
expect(nested.add(5)).toEqual(10);
});
});
The it block goes inside a describe block and contains each unit test case. Here's an example with multiple it
blocks inside one describe block:
describe("Adding a single number", function () {
// Test case: 1
it("should add numbers", function() {
expect(nested.add(5)).toEqual(5);
expect(nested.add(5)).toEqual(10);
});
// Test case: 2
it("should add numbers", function() {
expect(nested.addAny(1, 2, 3)).toEqual(6);
});
});
The expect block allows you to write your expectations for the function or JavaScript file under test. It comes inside the it
block. One it
block can have more than one expect
block.
In the following example, each expect
block is also known as a matcher. There are built-in matchers and user-defined matchers:
describe("Adding a single number", function () {
// Test case: 1
it("should add numbers", function() {
expect(nested.add(5)).toEqual(5);
expect(nested.add(5)).toEqual(10);
});
// Test case: 2
it("should add numbers", function() {
expect(nested.addAny(1, 2, 3)).toEqual(6);
});
});
In the upcoming chapters, we will explore various uses of different built-in methods of the expect block.
Jasmine is a testing framework, and its primary function is to compare the result of a JavaScript file or function with the expected result. Matchers in Jasmine are JavaScript functions that perform a Boolean comparison between an actual output and an expected output.
There are two types of matchers in Jasmine:
- Inbuilt Matchers
- Custom Matchers
The matchers that are included in the Jasmine framework by default are called inbuilt matchers. Users can easily use these matchers without any explicit definition.
The following example demonstrates how inbuilt matchers work in the Jasmine framework. We have already seen some matchers in the previous chapters.
describe("Adding a single number", function () {
// Example of toEqual() matcher
it("should add numbers", function() {
expect(nested.add(5)).toEqual(5);
expect(nested.add(5)).toEqual(10);
});
it("should add numbers", function() {
expect(nested.addAny(1, 2, 3)).toEqual(6);
});
});
In the above example, toEqual()
is the inbuilt matcher that compares the result of the add()
and addAny()
methods with the expected values passed to the toEqual()
matcher.
Matchers that are not part of the inbuilt system library of Jasmine are called custom matchers. These matchers need to be explicitly defined by the user.
describe('This custom matcher example', function() {
beforeEach(function() {
// Custom matcher should be added in beforeEach() function.
jasmine.addMatchers({
validateAge: function() {
return {
compare: function(actual, expected) {
var result = {};
result.pass = (actual >= 13 && actual <= 19);
result.message = 'Sorry, you are not a teen.';
return result;
}
};
}
});
});
it('Let\'s see whether you are a teen or not', function() {
var myAge = 14;
expect(myAge).validateAge();
});
it('Let\'s see whether you are a teen or not', function() {
var yourAge = 18;
expect(yourAge).validateAge();
});
});
In the above example, validateAge()
is defined as a custom matcher that validates whether the age falls within the teenage range (13 to 19). This custom matcher is defined inside the beforeEach()
block, and the matcher is then used within the it
blocks to test different age values.
After adding this JavaScript file to SpecRunner.html
and running it, the custom matcher will generate an output that validates the age based on the condition defined in validateAge()
.
Output Example: ValidateAge
Jasmine allows developers to skip one or more test cases. This functionality can be applied at the Spec level or the Suite level. Depending on where it is applied, this block can be called a Skipping Spec or a Skipping Suite, respectively.
In the following examples, we will learn how to skip a specific Spec or Suite using the "x"
character.
To skip a specific spec, we can place an "x"
just before the it
statement.
describe('This custom matcher example', function() {
beforeEach(function() {
// Adding custom matcher in beforeEach() function.
jasmine.addMatchers({
validateAge: function() {
return {
compare: function(actual, expected) {
var result = {};
result.pass = (actual >= 13 && actual <= 19);
result.message = 'Sorry, you are not a teen.';
return result;
}
};
}
});
});
it('Let\'s see whether you are a teen or not', function() {
var myAge = 14;
expect(myAge).validateAge();
});
xit('Let\'s see whether you are a teen or not', function() {
// Skipping this Spec
var yourAge = 18;
});
});
In this example, the second it
block is skipped using xit
. When this JavaScript code runs, Jasmine will notify the user that the specific spec block is disabled temporarily using "xit"
.
XIT Block Result Screenshot
Similarly, you can disable an entire suite by using "x"
before the describe
block. This technique is known as Skipping Suite.
xdescribe('This custom matcher example', function() {
// Skipping the entire describe block
beforeEach(function() {
// Adding custom matcher in beforeEach() function.
jasmine.addMatchers({
validateAge: function() {
return {
compare: function(actual, expected) {
var result = {};
result.pass = (actual >= 13 && actual <= 19);
result.message = 'Sorry, you are not a teen.';
return result;
}
};
}
});
});
it('Let\'s see whether you are a teen or not', function() {
var myAge = 14;
expect(myAge).validateAge();
});
it('Let\'s see whether you are a teen or not', function() {
var yourAge = 18;
expect(yourAge).validateAge();
});
});
In this example, the entire describe
block is skipped using xdescribe
. When the code is executed, Jasmine will display a message indicating that the suite is pending, meaning that both specs inside the suite are disabled.
Skipping Suite Result Screenshot
As shown in the message bar, it indicates that two spec blocks are in pending status, meaning they are disabled using the "x"
character.
In the upcoming chapters, we will discuss different types of Jasmine test scenarios.
Jasmine provides plenty of methods that help us check the equality of any JavaScript function and file. Below are some examples of how to check equality conditions.
The toEqual()
matcher is the simplest matcher in the inbuilt library of Jasmine. It checks whether the result of the operation given as an argument to this method matches with the expected result.
expectexam.js
window.expectexam = {
currentVal: 0,
};
ExpectSpec.js
describe("Different Methods of Expect Block", function () {
it("The Example of toEqual() method", function () {
// This will check whether the value of the variable
// currentVal is equal to 0 or not.
expect(expectexam.currentVal).toEqual(0);
});
});
On successful execution, these pieces of code will yield the expected output. Remember to add these files into the header section of SpecRunner.html
as directed in earlier examples.
toEquals Method Output Screenshot
The not.toEqual()
matcher works exactly opposite to toEqual()
. It is used when we need to check if a value does not match the output of any function.
ExpectSpec.js
describe("Different Methods of Expect Block", function () {
it("The Example of toEqual() method", function () {
expect(expectexam.currentVal).toEqual(0);
});
it("The Example of not.toEqual() method", function () {
// Negation testing
expect(expectexam.currentVal).not.toEqual(5);
});
});
expectexam.js
window.expectexam = {
currentVal: 0,
};
In the second expect block, we are checking whether the value of currentVal
is equal to 5. Since the value of currentVal
is zero, the test passes, and we receive a green output.
The toBe()
matcher works similarly to toEqual()
, but they are technically different. The toBe()
matcher checks for object identity (similar to the ===
operator in JavaScript), whereas toEqual()
checks for equivalency (similar to the ==
operator).
ExpectSpec.js
describe("Different Methods of Expect Block", function () {
it("The Example of toBe() method", function () {
expect(expectexam.name).toBe(expectexam.name1);
});
});
expectexam.js
window.expectexam = {
currentVal: 0,
name: "tutorialspoint",
name1: tutorialspoint
};
In this example, we added two new variables, name
and name1
. The difference between these two variables is that one is a string type and the other is not. The output will show an error, indicating that these two values are not equal.
expectExam Error Screenshot
If we turn both the name
and name1
variables into string type variables and run SpecRunner.html
again, the output will prove that toBe()
matches both the equivalency and the data type or object type of the variables.
As seen earlier, not
negates the toBe()
matcher. It fails when the expected result matches the actual output of the function or JavaScript file.
describe("Different Methods of Expect Block", function () {
it("The Example of not.toBe() method", function () {
expect(true).not.toBe(false);
});
});
In this example, Jasmine tries to match true
with false
. Since true
cannot be the same as false
, this test case will be valid and will pass.
toBe Method Output Screenshot
Apart from equality checks, Jasmine provides methods to check Boolean conditions as well. Below are some methods that help us check Boolean conditions.
The toBeTruthy()
matcher is used in Jasmine to check whether the result is true.
ExpectSpec.js
describe("Different Methods of Expect Block", function () {
it("The Example of toBeTruthy() method", function () {
expect(expectexam.exampleoftrueFalse(5)).toBeTruthy();
});
});
Expectexam.js
window.expectexam = {
exampleoftrueFalse: function (num) {
if (num < 10)
return true;
else
return false;
},
};
In this example, we are passing the number 5, which is smaller than 10. This test case will pass and give us the expected output.
toBeTruthy Method Output Screenshot
If we pass a number larger than 10, the green test will change to red. The output will indicate that the expected test case fails, stating "Expected false to be truthy."
toBeTruthy Error Screenshot
The toBeFalsy()
matcher works similarly to the toBeTruthy()
method. It checks whether the output is false, while toBeTruthy()
checks for true.
ExpectSpec.js
describe("Different Methods of Expect Block", function() {
it("The Example of toBeFalsy() method", function () {
expect(expectexam.exampleoftrueFalse(15)).toBeFalsy();
});
});
Expectexam.js
window.expectexam = {
exampleoftrueFalse: function (num) {
if (num < 10)
return true;
else
return false;
},
};
In this case, since we are passing a value greater than 10, the expected output will be false, and the test case will pass, resulting in a green indicator in the browser.
toBeFalsy Method Output Screenshot
Jasmine provides different methods to check the sequentiality of JavaScript outputs. The following examples illustrate how to implement sequential checks using Jasmine.
The toContain()
matcher allows us to check whether a specific element is part of an array or some other sequential objects.
customerMatcherSpec.js
describe("Different Methods of Expect Block", function () {
it("The Example of toContain() method", function () {
expect([1, 2, 3, 4]).toContain(3);
});
});
In this example, we check whether the number 3 is present in the array. The output will be green as 3 is indeed present in the array.
toContain Method Output Screenshot
If we change the value from 3 to 15 and run the test again, we will see a red output indicating that 15 does not belong to the array.
toContain Error Screenshot
The toBeCloseTo()
matcher checks whether the actual value is close to the expected value.
customerMatcherSpec.js
describe("Different Methods of Expect Block", function () {
it("Example of toBeCloseTo()", function () {
expect(12.34).toBeCloseTo(12.3, 1);
});
});
In this example, we are checking whether the actual result of 12.34
is close to the expected output 12.3
. Since this condition is satisfied, the output will be green. The second parameter of this method specifies the number of decimal places to compare.
toBeCloseTo Method Output Screenshot
If we modify the expected value to 15 and run SpecRunner.html
again:
describe("Different Methods of Expect Block", function () {
it("Example of toBeCloseTo()", function () {
expect(12.34).toBeCloseTo(15, 1);
});
});
In this case, since 15 is not close to 12.34, it will generate an error, resulting in a red output.
toBeCloseTo Error Screenshot
The toMatch()
matcher works on string variables and is helpful for finding whether a specific substring is present in the expected output.
customerMatcherSpec.js
describe("Different Methods of Expect Block", function () {
it("Example of toMatch()", function () {
expect("Jasmine tutorial in tutorials.com").toMatch(/com/);
});
});
This piece of code tests whether “com” is present in the expected string. Since "com" exists, it will generate a green output and pass the test.
toMatch Method Output Screenshot
If we change the expected output to look for a string that does not exist:
customerMatcherSpec.js
describe("Different Methods of Expect Block", function () {
it("Example of toMatch()", function () {
expect("Jasmine tutorial in tutorials.com").toMatch(/XYZ/);
});
});
In this case, since "XYZ" is not present in the expected string, it will throw an error and the output screen will be red.
toMatch Error Screenshot
Jasmine provides a variety of methods to check whether the actual output is null, defined, or undefined. In this chapter, we will learn how to implement different Jasmine methods to check these scenarios.
The toBeDefined()
matcher checks whether a variable in the code is defined.
customerMatcherSpec.js
currentVal = 0;
describe("Different Methods of Expect Block", function () {
it("Example of toBeDefined()", function () {
expect(currentVal).toBeDefined();
});
});
In this code, toBeDefined()
checks whether the variable currentVal
is defined in the system. Since currentVal
is defined as 0, this test will pass and generate a green output.
toBeDefined Method Output Screenshot
If we remove the line where currentVal
is defined and run the test again, we will see a red output, indicating that the test fails because we are expecting an undefined value to be defined.
toBeDefined Error Screenshot
The toBeUndefined()
matcher checks whether a variable is undefined. It works in the opposite way to toBeDefined()
.
customerMatcherSpec.js
describe("Different Methods of Expect Block", function () {
it("Example of toBeUndefined()", function () {
var undefineValue;
expect(undefineValue).toBeUndefined();
});
});
In this example, we verify whether the variable undefineValue
is actually undefined. After adding this file to SpecRunner.html
, we will receive a green output, indicating that the value is indeed not defined.
toBeUndefined Method Output Screenshot
If we define the variable with a value and run the test again, it should throw an error.
Updated Example: toBeUndefined()
describe("Different Methods of Expect Block", function () {
it("Example of toBeUndefined()", function () {
var undefineValue = 0;
expect(undefineValue).toBeUndefined();
});
});
This code will generate an error and produce a red output because undefineValue
has been defined as 0, and we are expecting it to be undefined.
toBeUndefined Error Screenshot
As the name suggests, the toBeNull()
matcher checks for null values.
customerMatcherSpec.js
describe("Different Methods of Expect Block", function () {
var value = null;
it("Example of toBeNull()", function () {
expect(value).toBeNull();
});
});
In this code, we explicitly set the variable value
to null. The toBeNull()
matcher will check this value and provide the result accordingly. The output will be green if the value is null.
toBeNull Method Output Screenshot
If we modify the variable to a defined value, the test will fail.
Updated Example: toBeNull()
describe("Different Methods of Expect Block", function () {
var value = "TutorialsPoint";
it("Example of toBeNull()", function () {
expect(value).toBeNull();
});
});
In this case, since value
is set to "TutorialsPoint", which is not null, this test will fail, resulting in a red output.
toBeNull Error Screenshot
In this chapter, we will learn about different matchers that help us check inequality conditions in JavaScript files. The following matchers are used for this purpose:
As the name suggests, the toBeGreaterThan()
matcher checks if a value is greater than a specified number.
customerMatcher.js
describe("Different Methods of Expect Block", function () {
var exp = 8;
it("Example of toBeGreaterThan()", function () {
expect(exp).toBeGreaterThan(5);
});
});
In this example, we expect the value of the variable exp
to be greater than 5. Since the value of exp
is 8, which is greater than 5, this code will generate a green output.
GreaterThan Method Output Screenshot
If we modify the value of exp
to 4 and run the test again, it should fail.
describe("Different Methods of Expect Block", function () {
var exp = 4;
it("Example of toBeGreaterThan()", function () {
expect(exp).toBeGreaterThan(5);
});
});
This code will fail because the value 4 is not greater than 5. The output will be red.
GreaterThan Error Screenshot
The toBeLessThan()
matcher checks if a value is less than a specified number. It behaves oppositely to the toBeGreaterThan()
matcher.
customerMatcher.js
describe("Different Methods of Expect Block", function () {
var exp = 4;
it("Example of toBeLessThan()", function() {
expect(exp).toBeLessThan(5);
});
});
In this example, we check whether the value of the variable exp
is less than 5. Since exp
is 4, this code will generate a green output.
LessThan Method Output Screenshot
To make this test fail, we can assign a larger number to the variable exp
. For example, if we set it to 25:
describe("Different Methods of Expect Block", function () {
var exp = 25;
it("Example of toBeLessThan()", function() {
expect(exp).toBeLessThan(5);
});
});
In this case, the test will fail because 25 is not less than 5, resulting in a red output.
LessThan Error Screenshot
Jasmine provides a special matcher to check for Not a Number (NaN) values, which is the toBeNaN()
matcher.
In the following example, we will modify our customerMatcher.js
file to check for NaN values.
customerMatcher.js
describe("Different Methods of Expect Block", function () {
it("Example of toBeNaN()", function () {
expect(0 / 0).toBeNaN();
});
});
In this code, we want to test the value of 0 / 0
, which is undefined and results in NaN. This test will pass and generate a green output.
toBeNaN Output Screenshot
Now, let’s modify the code to check whether a valid number results in NaN. We will assign a variable exp
to 25 and expect the result of dividing it by 5 to be NaN.
Modified Example: toBeNaN()
describe("Different Methods of Expect Block", function () {
var exp = 25;
it("Example of toBeNaN()", function () {
expect(exp / 5).toBeNaN();
});
});
In this case, since 25 / 5
equals 5 (which is a number), the test will fail and yield a red output, indicating that we incorrectly expected it to be NaN.
toBeNaN Output Error Screenshot
Apart from various computational matchers, Jasmine provides useful matchers to check for exceptions in a program. Below is an example of how to implement exception checking using Jasmine.
In this example, we will create a function that deliberately throws an exception.
var throwMeAnError = function() {
throw new Error();
};
describe("Different Methods of Expect Block", function() {
var exp = 25;
it("Hey, this will throw an Error", function() {
expect(throwMeAnError).toThrow();
});
});
In this code, the function throwMeAnError
throws an error. In the expect
block, we expect to catch this error using toThrow()
. If everything goes well, this code will yield a green output.
Exception Block Output Screenshot
To make this test case fail, we need to omit the throw
statement in the throwMeAnError
function.
var throwMeAnError = function() {
// throw new Error();
};
describe("Different Methods of Expect Block", function() {
var exp = 25;
it("Hey, this will throw an Error", function() {
expect(throwMeAnError).toThrow();
});
});
In this case, since we have commented out the line that throws the exception, the test will fail, resulting in a red output.
Exception Error Output Screenshot
The any
matcher is used when we are uncertain about the exact output type. The following example demonstrates how to use this matcher.
var addAny = function() {
var sum = this.currentVal;
for (var i = 0; i < arguments.length; i++) {
sum += arguments[i];
}
this.currentVal = sum;
return this.currentVal;
};
describe("Different Methods of Expect Block", function () {
it("Example of any()", function() {
expect(addAny(9, 9)).toEqual(jasmine.any(Number));
});
});
In this example, the addAny
function calculates the sum of the numbers provided as arguments. In the expect
block, we expect the result to be a number. Since 9 + 9
yields 18
, which is a number, the test will pass, generating a green output.
Any Method Output Screenshot
Now, let’s modify the code to expect a string type variable as the output of the addAny()
function.
var addAny = function() {
var sum = this.currentVal;
for (var i = 0; i < arguments.length; i++) {
sum += arguments[i];
}
this.currentVal = sum;
return this.currentVal;
};
describe("Different Methods of Expect Block", function () {
it("Example of any()", function () {
expect(addAny(9, 9)).toEqual(jasmine.any(String));
});
});
In this case, since addAny(9, 9)
returns 18
, which is not a string, this test will fail, producing a red output.
Any Error Output Screenshot
Another notable feature of Jasmine is the ability to execute code before and after each spec using the beforeEach()
and afterEach()
functions. This functionality is very useful for running common code in your tests.
In the following example, we will demonstrate how to use beforeEach()
to set up a variable before each spec runs.
var currentVal = 0;
beforeEach(function() {
currentVal = 5;
});
describe("Different Methods of Expect Block", function() {
it("after each function", function() {
expect(currentVal).toEqual(5);
});
});
In this example, we declare a variable currentVal
initialized to 0. However, before the execution of each spec, the beforeEach()
function sets currentVal
to 5.
Since currentVal
is set to 5 before the expectation block is executed, the test will pass and generate a green output.
BeforeEach Output Screenshot
Like beforeEach()
, the afterEach()
function in Jasmine works in a similar manner. It executes after the execution of each spec block, allowing you to clean up or reset states after tests run.
In the following example, we will demonstrate how to use afterEach()
to modify a variable after each spec runs.
var currentVal = 0;
afterEach(function() {
currentVal = 5;
});
describe("Different Methods of Expect Block", function() {
it("first call", function() {
expect(currentVal).toEqual(0);
});
it("second call", function() {
expect(currentVal).toEqual(5);
});
});
In this example, the variable currentVal
is initialized to 0. During the first spec, the expectation checks if currentVal
is 0, which passes. After this spec executes, the afterEach()
function runs and sets currentVal
to 5.
In the second spec, currentVal
is now 5, so the expectation will also pass, yielding a green output.
AfterEach Output Screenshot
Jasmine's spy functionality allows you to monitor function calls in your application. There are two primary methods for implementing spies in Jasmine: spyOn()
and createSpy()
. In this chapter, we will learn about both methodologies.
The spyOn()
method is built into the Jasmine library and enables you to spy on a specific piece of code.
spyJasmine.js
var Person = function() {};
Person.prototype.sayHelloWorld = function(dict) {
return dict.hello() + " " + dict.world();
};
var Dictionary = function() {};
Dictionary.prototype.hello = function() {
return "hello";
};
Dictionary.prototype.world = function() {
return "world";
};
spyJasmineSpec.js
describe("Example of Jasmine Spy using spyOn()", function() {
it('uses the dictionary to say "hello world"', function() {
var dictionary = new Dictionary();
var person = new Person();
spyOn(dictionary, "hello"); // Replace hello function with a spy
spyOn(dictionary, "world"); // Replace world function with another spy
person.sayHelloWorld(dictionary);
expect(dictionary.hello).toHaveBeenCalled();
// Not possible without the first spy
expect(dictionary.world).toHaveBeenCalled();
// Not possible without the second spy
});
});
In this code, we want the person
object to say “Hello world” by consulting the dictionary
object for the output. By using spyOn()
, we mimic the functionality of the hello
and world
functions. Therefore, we don't actually call the functions, but we can still check if they were called, showcasing the specialty of spies. This code will yield a green output.
spyOn Method Output Screenshot
Another way to implement spying functionality is by using createSpy()
.
spyJasmine.js
var Person = function() {};
Person.prototype.sayHelloWorld = function(dict) {
return dict.hello() + " " + dict.world();
};
var Dictionary = function() {};
Dictionary.prototype.hello = function() {
return "hello";
};
Dictionary.prototype.world = function() {
return "world";
};
spyJasmineSpec.js
describe("Example of Jasmine Spy using createSpy", function() {
it("can have a spy function", function() {
var person = new Person();
person.getName11 = jasmine.createSpy("Name spy");
person.getName11();
expect(person.getName11).toHaveBeenCalled();
});
});
In this spec file, we call the getName11()
function of the Person
object. Even though this function does not exist in spyJasmine.js
, we do not receive any errors, and the output is green, indicating success. In this example, the createSpy()
method mimics the functionality of getName11()
.
createSpy Output Screenshot