Jest runs all describe blocks before running any individual test

Alistair William Taylor
3 min readJan 9, 2023

--

Photo by Tim Gouw on Unsplash

The Problem

I’m currently cleaning out the Jest test suite of our component library, which has accumulated console errors over the years. It’s got to the point where we can’t immediately tell if we’ve introduced a new warning or console error when making a change or adding a new test.

Hopefully cleaning it up will make newly introduced errors much more apparent and so improve the quality of the test suite and our codebase. I’ve been using the Jest Runner extension for VS Code to allow me to quickly and easily run individual tests to pinpoint where in the suite the console error is coming from.

Most of the errors were relatively simple to diagnose and clean up, but a few really stumped me, so I saved them to the end.

Circling back, I spent some time headscratching on a console error which was being thrown by every single individual test in a suite, when I really couldn’t see what could be causing it at all. It initially led me to wonder whether this was a murky problem somewhere deep in our production code. Increasingly, though, I came to suspect that there was some snag in the way that the tests were set up and run that I wasn’t understanding properly.

It turns out that there was a constant declaration (specialComponentSetUp in the example below) in the very last describe block in the file which mounted the Component incorrectly. The test suite was structured something like this:

describe('MyComponent', () => {
let component;

describe('when rendered with required props', () => {
beforeEach(() => {
component = mount(
<MyComponent
label="Location"
locations={testLocations}
onChange={changeSpy}
/>
);
});

it('should render a combobox with locations', () => {
// etc.
});

it('should call change handler when clicked', () => {
// etc.
});
});

// etc., etc., for 250 lines

describe('LAST SPECIFIC SPECIAL REQUIREMENT', () => {
const specialComponentSetUp = mount(
<MyComponent>
{() => 'I am causing a console error'}
</MyComponent>
);

it('should have a dropsheet', () => {
// etc.
});
it('should pass trigger to dropsheet', () => {
// etc.
});
});
});

The Learning

So why was the error in that final describe block affecting every single test in the suite? Even if I just ran the first test in the file (which was in a completely different describe block), I would still get the error.

It turns out that the Jest documentation very clearly explains why I was encountering this problem:

Jest executes all describe handlers in a test file before it executes any of the actual tests. This is another reason to do setup and teardown inside before* and after* handlers rather than inside the describe blocks.

Because specialComponentSetUp was declared at the top level of the very last describe block in the file, and wasn’t wrapped in a beforeEach() or afterEach(), it was executed before running any single test or set of tests in the file.

The Solution

Wrapping the setup of that final describe block into a beforeEach() immediately localised the console error to that set of tests, and from there it was relatively straightforward to re-write the code

It might seem harmless to just declare some variables within a describe block, when those variables are going to be shared by all the tests within that block. And it may not seem immediately necessary to wrap that setup in a beforeEach() function. But I will always make sure to be very wary of this in the future, and make good use of the safety provided by beforeEach()

Executing set up code in the top level of a describe block might well end up causing you confusion and frustration debugging later down the line if anything goes wrong, or even present an enormous headache to a junior like me who stumbles across it years later and doesn’t know the intricacies of Jest’s Order of Execution.

So be careful out there!

--

--