Category Archives: Jest

Jest (a little bit more)

We’ve covered rudimentary use of Jest as part of React testing, also in a stand alone, now let’s look a little more in depth at common testing requirements.

Unit Test

We write tests using Jest like this

test('Some test description', () => {
});

Note: there are various aliases such as “it”, “fit”, “xit” or “xtest” that can be used in place of “test”.

Obviously the “Some test description” text should be something meaningful, i.e. what is being tested, any specific inputs and what’s the expectation. Ofcourse how much or how little you write as a description is upto the developer. I tend to write what method is being tested, with any special conditions and expected outcome simply because when the tests run I get a good set of information on what’s working and what’s not, however this is down to the developer’s specific tastes.

We can group tests together within a describe function which may allow you to reduce the verbosity of your test descriptions as well as logically group tests, for example

describe('fetch component', () => {
    test("missing URL, expect empty response", () => {
    });

    test("missing invalid, expect error", () => {
    });
});

Note: there are a couple of aliases such as “fdescribe” and “xdescribe” which can be used in place of “describe”.

The output of the Jest test runner would be something like this

fetch component
   √ missing URL
   √ missing invalid

Timeout

The test function also accepts a third argument which can be a timeout (specified in milliseconds). The default timeout is 5 seconds. So for example

test("missing URL, expect empty response", () => {
}, 100);

Paramterized tests

Jest supports paramterized tests using the each function, so for example

test.each`
   input         | output
   ${1}          | ${10} 
   ${5}          | ${50} 
   ${10}         | ${100} 
  `("should return $output when $input is used", ({input, output}) => {
   expect(input * 10).toBe(output);
});

Using a “table”-like layout of data, the first row made up of column names which map to the input(s) and output along with subsequent rows of inputs and outputs to match against delimited using the pipe | operator.

You can also pass in arrays instead of a table structure, i.e.

test.each([[1, 10], [5, 50], [10, 100]])
   (`should return %i when %i is used`, (input, output) => {
   expect(input * 10).toBe(output);
});

We can also supply parameters using the each function of describe meaning we can pass the same parameters through multiple tests. Here’s an example of the above two way of passing parameterized data, but using describe

describe.each`
  input         | output
  ${1}          | ${10} 
  ${5}          | ${50} 
  ${10}         | ${100} 
  `("multiplication with input $input, output $output", ({input, output}) => {

  test("should match", () => {
    expect(input * 10).toBe(output);
  });
})  

describe.each([[1, 10], [5, 50], [10, 100]])
(`multiplication %i, %i`, (input, output) => {

  test("should match", () => {
    expect(input * 10).toBe(output);
  });
});

Only run these tests

During development we might wish to turn off tests whilst we work on a specific set of tests, we can use the only function on either describe or test to basically just run those tests with only specified. For example the following syntax (followed by the normal describe and test parameters)

describe.only 
describe.only.each
test.only
test.only.each

Skipping tests

We can run only certain tests and the opposite (i.e. run all tests except these), skipping tests using the skip

describe.skip
describe.skip.each
test.skip
test.skip.each

Todo

With @types/jest version 24 the todo function was added to test. With this we might have ideas for our tests and want to quickly create stub methods, so we would write

test.todo('multiple number test');

No function should be supplied to a todo test and the Jest tester runner will show the test as a “todo” test within it’s output.

Lifecycle functions

Most unit testing frameworks include the ability to carry out some process before or after a test, for example setting up a test and cleanup, Jest is no different – including beforeAll, beforeEach, afterAll and afterEach functions.

As the names suggest, beforeAll and afterAll are invoked before the tests start and after the tests all complete, respectively. As you’ll have worked out beforeEach and afterEach will be invoked before and after each test is run, respectively.

All life cycle functions accept a function to invoke and an optional timeout.

Expectations

Obviously these previously mentioned tests will all succeed unless we include expectations/assertions. Jest includes the expect function which you’ll often pass the value your system under test returned (or set) along with a function such as toBe which is what you expect the value to be, for using our previous multiplication test

expect(input * 10).toBe(output);

There’s a whole host of functions around expect listed here “Expect”.

Unit testing and React

If you’ve created a React application using yarn, you’ll actually have the script for yarn test as well as App.test.tsx for running unit tests against React code (i.e. capable of running against tsx/jsx files etc.).

Jest is used for unit testing by default, but if you need to install Jest yourself simple run

yarn add --dev jest

The test script (within package.json) will execute react-scripts test but if we want to add our own script you could add

"jest": "jest --watch"

–watch will allow jest to monitor file changes and rerun tests automatically.

Create a folder off of your src folder (it can be at any depth) named __tests__ and within this we’ll add a simple .js file (or .ts) named files, for example number.test.js which we’ll create as a simple demonstration of writing tests and running the test runner. We should use either .test. or .spec. within the filename.

Within my number.test.js file I have the following

export function getNumber() {
    return 1234;
}

test('Test 1', () => {
    expect(getNumber()).toEqual(123);
});

test('Test 2', () => {
    expect(getNumber()).toEqual(1234);
});

Note: we can use “it” instead of “test” in the above

Obviously we’d normally not have the actually function we want to test within the test file, this is solely for simplicity of writing this post.

As you can see, each test comes with a string which is the name/description of the test, followed by a function which is executed by the test runner. Obviously in the above code “Test 1” will fail and “Test 2” will pass, so let’s run the test runner and see.

Like other test frameworks, we have functions to assert/expect certain values within our tests.

If you’ve added the script now run yarn jest or use yarn test. The Jest test runner will run and remain running, watching for file/test changes. Select the “a” option to run all tests after executing the jest script.

From the test runner (jest) you might wish to filter file name by regex, simply running tests against the __test__ folder.