Unit Testing Tool ‐ JasmineJS - JUCSE49-Mavericks/Smart-Class-Routine-Management-System GitHub Wiki

Overview

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.

Why Use Jasmine?

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.

How to Use Jasmine?

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.

Jasmine zip file structure


Jasmine - Environment Setup

In this chapter, we will discuss the step-by-step procedure of how to set up a Jasmine-based BDD testing application.

Step-by-Step Procedure

Step 1: Access the Official Jasmine Website

Go to the official website of Jasmine: https://jasmine.github.io/

Step 2: Select the Latest Version

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.

Step 3: Navigate to the Download Section

Go to the Download section of the homepage and click on the standalone release page.

Step 4: Download the Jasmine Standalone Zip File

Once you are redirected to the GitHub release page, download the Zip file from there.

Step 5: Extract the Jasmine Standalone Folder

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

Step 6: Integrate Jasmine into Your Web Application

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

Using Jasmine with Node.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).

Installation

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

Initialize a Project

To initialize a project for Jasmine, create a spec directory and configuration JSON file:

npx jasmine init

Generate Examples

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.

Configuration

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

Running Specs

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"

Filtering Specs

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

Using ES Modules

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.

CLI Options

  • 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

Using the Library

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();

Reporters

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');

A Simple Example Using the Library

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.


Writing Text & Execution

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.

Step 1: Create a Web Application in Your IDE

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

Step 2: Include the Jasmine Lib File into the Application

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.

Specrunner HTML File

Step 3: Create a JavaScript File

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'; 
}; 

Step 4: Create a Test Case

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'); 
   }); 

});

Step 5: Add References to the Output File

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>

Step 6: Execute by Running SpecRunner.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

Step 7: Understand the Failure Case

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.


BDD Architecture

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

Step-by-Step Process of the BDD Framework

Step 1: Start

In this phase, we will make our environment ready for the Jasmine application.

Step 2: Write a Failing Test

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.

Step 3: Write Code to Make It Pass

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.

Step 4: Refactor

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.

Step 5: Stop

If everything is going well, your application should be complete and functioning. This step marks the end of the BDD application development.

Example

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

Working Principle

  • 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 and Lib 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, and Lib as inputs and displays the result in a browser.


Building Blocks of Test

In this chapter, we will discuss the building blocks of tests in Jasmine.

Suite Block

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.

calculator.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; 
   }, 
};

CalCulatorSpec.js

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

Nested Suites Block

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.

NestedSpec.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 
});

nested.js

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

Describe Block

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); 
   });     
});

IT Block

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); 
   });     
});

Expect Block

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.


Matchers

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:

  1. Inbuilt Matchers
  2. Custom Matchers

Inbuilt Matcher

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.

Example: Inbuilt Matchers

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.

Custom Matchers

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.

Example: Custom Matchers

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


Skip Block

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.

Skipping Spec

To skip a specific spec, we can place an "x" just before the it statement.

Example: Skipping Spec

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

Skipping Suite

Similarly, you can disable an entire suite by using "x" before the describe block. This technique is known as Skipping Suite.

Example: 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.


Equality Check

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.

toEqual()

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.

Example: toEqual()

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

not.toEqual()

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.

Example: not.toEqual()

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.

toBe()

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).

Example: toBe()

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.

not.toBe()

As seen earlier, not negates the toBe() matcher. It fails when the expected result matches the actual output of the function or JavaScript file.

Example: not.toBe()

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


Boolean Check

Apart from equality checks, Jasmine provides methods to check Boolean conditions as well. Below are some methods that help us check Boolean conditions.

toBeTruthy()

The toBeTruthy() matcher is used in Jasmine to check whether the result is true.

Example: toBeTruthy()

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

toBeFalsy()

The toBeFalsy() matcher works similarly to the toBeTruthy() method. It checks whether the output is false, while toBeTruthy() checks for true.

Example: toBeFalsy()

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


Sequential Check

Jasmine provides different methods to check the sequentiality of JavaScript outputs. The following examples illustrate how to implement sequential checks using Jasmine.

toContain()

The toContain() matcher allows us to check whether a specific element is part of an array or some other sequential objects.

Example: toContain()

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

toBeCloseTo()

The toBeCloseTo() matcher checks whether the actual value is close to the expected value.

Example: toBeCloseTo()

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

toMatch()

The toMatch() matcher works on string variables and is helpful for finding whether a specific substring is present in the expected output.

Example: toMatch()

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


Null Check

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.

toBeDefined()

The toBeDefined() matcher checks whether a variable in the code is defined.

Example: toBeDefined()

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

toBeUndefined()

The toBeUndefined() matcher checks whether a variable is undefined. It works in the opposite way to toBeDefined().

Example: toBeUndefined()

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

toBeNull()

As the name suggests, the toBeNull() matcher checks for null values.

Example: toBeNull()

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


Inequality Check

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:

toBeGreaterThan()

As the name suggests, the toBeGreaterThan() matcher checks if a value is greater than a specified number.

Example: toBeGreaterThan()

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.

Modified Example: toBeGreaterThan()

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

toBeLessThan()

The toBeLessThan() matcher checks if a value is less than a specified number. It behaves oppositely to the toBeGreaterThan() matcher.

Example: toBeLessThan()

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:

Modified Example: toBeLessThan()

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


Not a Number Check

Jasmine provides a special matcher to check for Not a Number (NaN) values, which is the toBeNaN() matcher.

Example: toBeNaN()

In the following example, we will modify our customerMatcher.js file to check for NaN values.

Checking NaN

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

Example: Expecting a Number Not to Be NaN

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


Exception Check

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.

Example: toThrow()

In this example, we will create a function that deliberately throws an exception.

Code: Throwing an Error

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

Example: Failing the toThrow() Test

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

Any Matcher

The any matcher is used when we are uncertain about the exact output type. The following example demonstrates how to use this matcher.

Code: Using Any 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

Example: Failing the Any Matcher Test

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


beforeEach()

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.

Example: Using beforeEach()

In the following example, we will demonstrate how to use beforeEach() to set up a variable before each spec runs.

Code: Using beforeEach()

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.

Output

Since currentVal is set to 5 before the expectation block is executed, the test will pass and generate a green output.

BeforeEach Output Screenshot


afterEach()

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.

Example: Using afterEach()

In the following example, we will demonstrate how to use afterEach() to modify a variable after each spec runs.

Code: Using afterEach()

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.

Output

In the second spec, currentVal is now 5, so the expectation will also pass, yielding a green output.

AfterEach Output Screenshot


Spies

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.

spyOn()

The spyOn() method is built into the Jasmine library and enables you to spy on a specific piece of code.

Example: Using spyOn()

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

createSpy()

Another way to implement spying functionality is by using createSpy().

Example: 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

⚠️ **GitHub.com Fallback** ⚠️