Test a Single Function

Testing user interfaces adds noise and complexity, so it’s best to test as much as you can without involving the user interface. Putting application logic in functions outside components lets us work more efficiently. In our word counter, we’ve already extracted the countWords function and placed it in a separate module:

 function​ countWords(text) {
 return​ text ? text.match(​/​​w​​+/g​).length : 0;
 }
 
 export​ ​default​ countWords;

This module exports the countWords function by default. It’s a good idea to test this logic on its own, as long as you’re testing meaningful functionality instead of implementation details.

Create a new __tests__ directory in the src directory. The directory name must start and end with two underscores to match the regular expression that Jest uses to locate the tests in the project directory. Then create a file named count.test.js in the __tests__ directory. To access the word count function, import the countWords function at the top of count.test.js:

 import​ countWords from ​'../countWords'​;

Pay attention to the path, as the countWords module is in the parent directory, so you must use two dots before the first slash to access the parent folder.

Now that you’ve got countWords in scope, call it and check that its output conforms to what you expect with the it, describe, and expect functions. These functions let you organize your test code and make assertions about the results. If you run test files with Jest, you can use them without importing them. Jest places them in scope automatically. Let’s test countWords.

Define individual tests by calling it. Each test asserts one or more properties of the objects under test with the expect function. If any of the assertions fails, Jest reports the entire test as failed, so to better understand failures, you’ll want to write more tests with fewer assertions per test rather than a few tests with a lot of assertions.

Let’s create a test to check that countWords correctly computes the number of words we pass in. The it function takes a string describing the test and a callback, which is the actual test. For the callback, you can use either the function keyword or arrow functions; arrow functions are faster to type, so that’s what we’ll use. In the callback, call expect to compare the return value of countWords with the expected result:

 it(​'counts the correct number of words'​, () => {
  expect(countWords(​'One two three'​)).toBe(3);
 });

This test verifies that countWords returns 3 when you pass it ’One two three’. We call countWords and pass its return value to expect. expect returns a wrapper with functions that let us check the return value. The function toBe checks simple values like numbers and strings; it’s equivalent to a comparison with the === operator.

If you’ve still got Jest running in the background, Jest runs the test automatically when you save the file; else, run npm test again. Jest finds your new test and prints something similar to this:

 PASS __tests__/count.test.js
  the counting function
  ✓ counts the correct number of words (3ms)
 
 Test Suites: 1 passed, 1 total
 Tests: 1 passed, 1 total
 Snapshots: 0 total
 Time: 1.381s
 Ran all test suites related to changed files.

The idea behind naming the test function it is that the test and its output should read like a description of what you’re testing. Since Jest prints the test descriptions when you run the tests, descriptive names help you understand what’s going on after a test fails. If error messages show up even if the test passes, your code might be generating console warnings. Read the messages to understand what’s going on and fix it.

Good tests check edge cases. When the user deletes all the text, countWords receives an empty string, so we are especially interested in the empty string input. Instead of stuffing a second assertion in the same test, create a separate test. In this way, Jest will report the two cases separately, so you’ll know immediately which one of the two has failed.

To make the test output more readable, group related tests in suites with the describe function. describe takes a string describing the suite and a callback that contains the test code. Suites enhance the test output as Jest groups the results of tests in the same suite. Choose the suite description carefully as Jest will print it on the console to identify the tests. Create a test suite for the wordCount function inside count.test.js:

»describe(​'the counting function'​, () => {
  it(​'counts the correct number of words'​, () => {
  expect(countWords(​'One two three'​)).toBe(3);
  });
»});

Create a new test within the same suite, but this time pass the empty string to countWords and ensure you get 0 for the length:

 it(​'counts the correct number of words'​, () => {
  expect(countWords(​'One two three'​)).toBe(3);
 });
 
»it(​'counts an empty string'​, () => {
» expect(countWords(​''​)).toBe(0);
»});

Once again, we call it with a description for the test case and a callback. Inside the callback, we pass the empty string to countWords and assert that the result length is 0 with toBe.

When the tests run again, notice that Jest now reports the results of the second test:

 PASS __tests__/count.test.js
  the counting function
  ✓ counts the correct number of words (2ms)
  ✓ counts an empty string
 
 Test Suites: 1 passed, 1 total
 Tests: 2 passed, 2 total
 Snapshots: 0 total
 Time: 2.095s
 Ran all test suites related to changed files.

Now that you’ve got the hang of creating tests, let’s test React components.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.227.183.153