Skip to main content

How to write a Unit Test with Jest: Same test suites with different data

💻 Tech

For our React Native iOS app, we choose Jest for testing.
The reason is pretty simple: it’s developed by Facebook officially (then fully supported and pervasive.)

Luckily, I found similarity between Jest and Spock, another testing framework I’m familiar to.
Both of them can keep duplicating the same test suites with different data concisely.
We can write down the data table in the test files like this:

str       | expected
${null}   | ${true}
${""}     | ${true}
${"word"} | ${false}

In this article, you will find how to write the same test suites with different data in Jest 🚀

Installing Jest

Firstly, add Jest to your React Native project by hitting this command.

yarn add --dev jest

If you are using npm, hit:

npm install --save-dev jest

Then add the following section to your package.json file:

{
  "scripts": {
    "test": "jest"
  }
}

Understanding Examples

Nextly, create these two files in the same directory.

export function isEmpty(str) {
    return (!str || 0 === str.length);
}

The file above is a simple validation method which evaluates whether a passed string value is “empty” or not.
Only a string value that its length is one or more would NOT be evaluated as “empty”.

describe('isEmpty method with the argument', () => {
    const validate = require('./validate');

    describe.each`
        str       | expected
        ${null}   | ${true}
        ${""}     | ${true}
        ${"word"} | ${false}
    `('$str', ({str, expected}) => {
        test(`returns ${expected}`, () => {
            expect(validate.isEmpty(str)).toBe(expected)
        });
    });
});

This is the test file for validate.js file.
Let’s understand what are the codes doing line by line.

At the first line:

describe('isEmpty method with the argument', () => {

the description of the test suites with different data is implemented.
The string, isEmpty method will be shown in the console when the test is done and you’ll found what tests have done by seeing it.

The second line imports the class we want to test.

    const validate = require('./validate');

At the fourth line to the eighth line:

    describe.each`
        str       | expected
        ${null}   | ${true}
        ${""}     | ${true}
        ${"word"} | ${false}

the data table is set.

Because in this test, I’d like to test three cases.

  1. When null is passed, the method returns true
  2. When empty string passed, the method returns true
  3. When a string contains at least one character passed, the method returns false

str would be the argument for the method and expected is the expected value the method returns.

Finally, at the ninth to the thirteenth line, the actual test is implemented.

    `('$str', ({str, expected}) => {
        test(`returns ${expected}`, () => {
            expect(validate.isEmpty(str)).toBe(expected)
        });
    });

'$str' will also be a shown message when the test is done.
Since the tests will be executed multiple times and the value changes, by setting $str , the value of str in each test suites will be shown.

({str, expected}) is passing the values in the data table.

returns ${expected} is also a message and the value of expected in each test suites.

And last but not least, this defines what the test will do 😎

            expect(validate.isEmpty(str)).toBe(expected)

This defines that when isEmpty method is run with str , it must return expected.

Result

After understanding all, hit yarn start!
The result would be like this.

PASS  validate.test.js
 isEmpty method with the argument
   null
     ✓ returns true (6ms)
   ""
     ✓ returns true (1ms)
   "word"
     ✓ returns false (1ms)
Test Suites: 1 passed, 1 total
Tests:       3 passed, 3 total

References

Tell me what you think of this article! 👉️ @curryisdrink