Jest: When Failing Fast is the Smart Strategy
3 min read

Jest: When Failing Fast is the Smart Strategy

548 words

When working on large projects, it’s common to have test suites that can take several minutes to run. And when one of those tests fails early in the execution, it’s frustrating to wait for all the others to complete just to see the full results.

Jest includes a feature I’ve found very useful in development: the bail option, which allows stopping test execution after a certain number of failures. It’s one of those features that once you know and start using, you don’t understand how you lived without it.

Why use bail?

During development, especially when you’re refactoring code or implementing important changes, it’s common for several tests to fail in a chain. In these cases, it doesn’t make much sense to run the remaining 500 tests if you already know the first one is failing due to an error you introduced.

The bail option allows you to:

  • Save time during development by stopping immediately after the first failure
  • Focus on solving one problem before continuing
  • Reduce resource usage during test execution

Configuration in the config file

You can configure bail directly in your jest.config.js file:

// jest.config.js
module.exports = {
  // Stop after the first failing test
  bail: true,

  // Or specify a specific number of failures
  bail: 3,

  // Rest of your configuration...
  testEnvironment: 'node',
  collectCoverage: true
}

The behavior is quite straightforward:

  • bail: true will stop after the first failing test
  • bail: 3 will stop after the third failing test

Configuration from command line

You can also use the option directly from the CLI, which I find especially useful when I want to quickly test something:

{
  "scripts": {
    "test": "jest",
    "test:bail": "jest --bail",
    "test:bail-3": "jest --bail 3",
    "test:dev": "jest --bail --watch"
  }
}

My favorite is combining --bail with --watch during development. This way, as soon as a test fails, Jest stops immediately and waits for file changes to run again.

My workflow with bail

In my day-to-day work, I use different configurations depending on the situation:

During active development:

npm run test:dev  # --bail --watch

For quick verification before commit:

npm run test:bail  # --bail

In CI/CD:

npm test  # Without bail, to see all errors

When NOT to use bail

It’s important to understand that bail is not always the right option:

  • In CI/CD pipelines: You usually want to see all failing tests to get a complete picture
  • In code reviews: Seeing all failures gives you better context of the code state
  • Complex integration tests: Sometimes a test may fail due to timing and the next ones may execute correctly

A practical configuration

A configuration that has worked well for me is to have different config files for different scenarios:

// jest.config.dev.js
module.exports = {
  ...require('./jest.config.js'),
  bail: true,
  verbose: true,
  watchAll: false
}

And then use specific scripts:

{
  "scripts": {
    "test": "jest",
    "test:dev": "jest --config jest.config.dev.js --watch",
    "test:ci": "jest --coverage --watchAll=false"
  }
}

The bail option is one of those small workflow improvements that really make a difference in day-to-day work. Especially when working with large test suites, being able to fail fast allows you to iterate much more efficiently during development.

NOTE: Remember that in production or CI environments, you’ll usually want to run all tests to get a complete picture of the code state, regardless of how many fail.

Comments

Latest Posts

10 min

1931 words

Deno 2.4 has just been released, and I must admit it has pleasantly surprised me. Not only because of the number of new features, but because of one in particular that many of us thought would never return: deno bundle is back. And this time, it’s here to stay.

This release comes packed with improvements ranging from importing text files directly to stable observability with OpenTelemetry. Let’s explore what this release brings us.

4 min

740 words

In my experience with mobile development, I’ve seen how apps become increasingly complex and projects grow uncontrollably. I remember perfectly that feeling of having thousands of lines of code and not being sure what was really being used and what wasn’t.

That’s why I was so struck by the tool that Sentry (formerly from Emerge Tools) just released as open source: Reaper. An SDK that does something that sounds simple but is tremendously useful: find dead code in your mobile applications.

4 min

793 words

I’ve seen how certain standards and tools become indispensable when working with data. And if there’s one thing we’ve learned over these years, it’s that JSON is everywhere: APIs, logs, configurations, NoSQL databases… The question is no longer whether you’ll work with JSON, but when you’ll face that 15-level nested structure that makes you sigh.

The Problem We’ve All Lived Through

How many times have you had to write something like this?