Talking About TestingATT</>
Unit Testing with Jest

Score 100% on the quiz to continue

Lesson
Free Preview

Your first unit test

Write a test with describe, test, and expect, run it, and learn to read a failure.

A unit test checks one small piece of code, a unit, on its own: usually a function, called with some input, with its result compared against what a rule says it should be. No browser, no server, no database. That is why unit tests run in milliseconds, and why a failing one points straight at what broke.

In this lesson, you write your first unit test, for lateFee(), and learn the three things every Jest test is made of: a group, a test, and an expectation.

Commands overview 📖

require() the code under test

A test file is plain JavaScript. It starts by requiring the function it tests.

Syntax:

const { functionName } = require('./module-file')

Example:

const { lateFee } = require('./fees')
👨‍🏫 You never require Jest itself. When Jest runs a test file, it makes describe, test, expect, and the rest available as globals.

describe()

Groups related tests under a name. Groups can be nested, and the names add up in the output.

Syntax:

describe('<what is being tested>', () => {
  // tests go here
})

Example:

describe('lateFee', () => {
  // tests for lateFee() go here
})

test() (or it())

Defines one test: a name and a function that runs it. it is an alias for test, so it('charges...') and test('charges...') are the same thing. This course uses test.

Syntax:

test('<the behavior, as a sentence>', () => {
  // call the code and check the result
})

Example:

test('charges 25 cents for each day late', () => {
  expect(lateFee(10)).toBe(250)
})
👨‍🏫 Name a test after the behavior it checks, not after the function. "charges 25 cents for each day late" tells you what broke when it fails. "lateFee works" tells you nothing.

expect() and toBe()

expect(value) wraps the value you got, and a matcher compares it with the value you expected. toBe() is the simplest matcher: it passes when both are the same value (it uses Object.is, which is strict equality, ===, for numbers and strings).

Syntax:

expect(<received>).toBe(<expected>)

Example:

expect(lateFee(0)).toBe(0)

Running one file, or everything

Syntax:

npm test
npx jest <path-to-test-file>

Example:

npx jest src/fees.test.js

Watch mode

--watch keeps Jest running and reruns the tests related to the files you change, every time you save. While it runs, press a to run all tests, f to run only the failed ones, p to filter by file name, t to filter by test name, and q to quit.

Syntax:

npx jest --watch

Example:

npm test -- --watch
👨‍🏫 --watch relies on git to know which files changed, which is why it works in your clone out of the box. The -- in npm test -- --watch tells npm to pass the flag through to Jest instead of keeping it for itself.

Reading a failure

A test you have never seen fail might not be checking anything. So the first thing to learn is how a failure reads. Suppose a test expects 200 where the rule says 250:

 FAIL  src/fees.test.js
  lateFee
    ✕ charges 25 cents for each day late (3 ms)

  ● lateFee › charges 25 cents for each day late

    expect(received).toBe(expected) // Object.is equality

    Expected: 200
    Received: 250

      5 |
      6 |   test('charges 25 cents for each day late', () => {
    > 7 |     expect(lateFee(10)).toBe(200)
        |                         ^
      8 |   })

Read it from the top:

  • FAIL and the file name: which file has a failing test.
  • lateFee › charges 25 cents for each day late: the describe name and the test name, joined. Good names make this line a sentence.
  • Expected and Received: what the test wanted, and what the code returned.
  • The code frame: the exact line of the failing assertion, with a caret under the matcher.

And then decide who is wrong. Here, the README says 25 cents a day, so 10 days is 250, and the test is wrong. Later in the course, it will be the other way around.

Suggested content 📚 and documentation links 🔗

Exercise 🎯

Create the file src/fees.test.js. Inside a describe('lateFee') block, write tests for these README rules, using values well inside each range:

  • A book returned on time (0 days late) has no fee.
  • A book 10 days late costs 250 cents (25 cents for every day late).
  • A book 20 days late costs 500 cents.

Run npm test and watch all three pass. Then break one on purpose: change the expected value of the 10-day test to 200, run it again, and read the failure from top to bottom as described above. Put it back to 250.

Finally, start watch mode with npm test -- --watch, change and save the test file a couple of times, and watch the tests rerun on their own. Press q to quit.

👨‍🏫 Commit the new test file and push it.

Show the world what you learned 🌎

To show your professional network what you learned in this lesson, post the following on LinkedIn.

I am taking the "Unit Testing with Jest" course by @Walmyr Lima e Silva Filho at the @Talking About Testing School, and I just wrote my first unit tests with Jest, watched one fail on purpose, and learned to read the expected and received values and the code frame of a failure. #TalkingAboutTesting #TATSchool #UnitTestingWithJest #Jest #UnitTesting

👨‍🏫 Remember to tag me in your post. Here is my LinkedIn profile.

Quiz

Question 1 of 2
Score: 0

A test fails with Expected: 200 and Received: 250 for lateFee(10). What should you do before changing anything?

Score 100% on the quiz to continue