Test Expectations

Tests follow a pattern called Arrange, Act, and Assert (AAA).

  • Arrange: This means setting up the world for our test. For example, we might need to prepare some dummy data or log in as a user.

  • Act: This is where we take the action we want to test.

  • Assert: This is where we test the expected result of the action. The expectation decides whether the test passes or fails.

Jasmine syntax

Jasmine test suites are wrapped in a function called describe. It takes two arguments: the title for the test suite and an anonymous function containing the unit tests. Each test is wrapped in a function called it. This function takes two arguments: a description and an anonymous function containing the unit test. Jasmine provides matchers called toBe, toEqual, and toBeNull which are used to check the result of the unit test.

  • toBe: Checks if the result is identical to the expected value.
  • toEqual: Has the same value, or the same properties, as the expected value.
  • toBeNull: Checks if the result is null.

Our first test

Let’s look at our first Jasmine test for a function that formats prices. In the test, we call the function with the value of 150. Then, we use the expect method to test that the result is the value we expect, such as $1.50. Click the “Run” button below to run our first Jasmine test.

// Function we want to test
function formatCurrency(valueInCents)
{
    const price = (valueInCents / 100).toFixed(2).toString();

    return '$' + price;
}

// Test suite
describe('Currency test', () => {
    it('formats a price', () => {
        const formatted = formatCurrency(150);

        expect(formatted).toEqual('$1.50');
    });
});
The toEqual expectation

The toEqual and toBe expectations

What is the difference between the toEqual and toBe expectations? For primitive types, like strings and numbers, these two expectations behave in the same way. The difference is when we compare objects. The toEqual expectation checks if the keys and values are the same, while toBe checks if we have a reference to the same object. Take a look at the example below. The function works how we expect, but the test will fail. Can you find a way to fix the test to make it pass?

// Function we want to test
function save(user)
{
    // Make a call to the API here
    return user;
}

// Test suite
describe('Save test', () => {
    it('saves a user', () => {
        const user = {
            name: 'Jane Doe',
            email: 'jane@example.com'
        };

        const result = save(user);

        expect(result).toBe({
            name: 'Jane Doe',
            email: 'jane@example.com'
        });
    });
});
Comparing toEqual and toBe

There are a couple of solutions for this. When the save function runs, it returns a reference to the user object. So, we can use toBe to write a test where we expect that the result will be a reference to the user object.

const user = {
name: 'Jane Doe',
email: 'jane@example.com'
};
const result = save(user);
expect(result).toBe(user);

Alternatively, we can use the toEqual expectation, which is less strict. It goes through each key/value pair in the object and makes sure they match the expected value.

const user = {
name: 'Jane Doe',
email: 'jane@example.com'
};
const result = save(user);
expect(result).toEqual({
name: 'Jane Doe',
email: 'jane@example.com'
});

The .not expectation

We can already do a lot using the toEqual and toBe expectations we’ve seen so far. Jasmine offers quite a few more expectations that will be helpful from time to time, such as the .not expectation. We can chain .not to negate the expectation after it. Take a look at the example below where the reverse function is used to reverse a string on line 10. We expect that the result, which has been reversed, should not equal the original string.

// Function we want to test
function reverse(value)
{
    return value.split("").reverse().join("");
}

// Test suite
describe('Reverse test', () => {
    it('reverse a string', () => {
        const result = reverse("Hello world");

        expect(result).not.toEqual("Hello world");
    });
});
Using .not to negate an expectation

Here’s another example, where we have a clone function. We use .not to test if our function returns a copy of the original object. The clone function copies all the key/value pairs into a new object. Our test ensures that the result object is a new object rather than a reference to the original object.

Your task is to add another expectation to check if the result object has the same key/value pairs as the original.

  1. Try adding another expectation on line 19.

  2. Rerun the code to make sure your new expectation passes.

// Function we want to test
function clone(value)
{
    return JSON.parse(JSON.stringify(value));
}

// Test suite
describe('Clone test', () => {
    it('copies an object', () => {
        const user = {
            name: 'Jane Doe',
            email: 'jane@example.com'
        };

        const result = clone(user);

        expect(result).not.toBe(user);

        // Your code here
    });
});
Checking object properties

The toBeNull expectation

Another useful expectation is toBeNull. Here’s an example with a getSetting method that returns a value. Our test checks if the result is a null value.

// Function we want to test
function getSetting()
{
    return 'some-value';
}

// Test suite
describe('Settings test', () => {
    it('fetches a value from the settings', () => {
        let result = null;

        result = getSetting();

        expect(result).not.toBeNull();
    });
});
The toBeNull expectation

Comparisons

When testing number values, we can use the comparison methods toBeGreaterThan and toBeLessThan. These can be helpful for testing boundary conditions.

Coding exercise

We have a function that takes a string and converts it into uppercase. Using Jasmine, write a test that calls the function with a test value and verifies the result.

// Function we want to test
function capitalize(value)
{
  return value.toUpperCase();
}

// Your code goes here
Coding exercise

You can see the solution to the problem above by clicking on the “Show Solution” button below.

We now know how to write expectations that check a condition to determine whether the test should pass or fail.