Jest Recap: What Runs When?
Hauke T.
Posted on July 18, 2024
TL;DR: Execution Order
- Everything on the top-level and in
describe()
blocks (wheredescribe()
blocks are basically IIFEs) -
beforeAll()
- top-level
- 1st level
describe()
- Nth level
describe()
-
beforeEach()
- top-level
- 1st level
describe()
- Nth level
describe()
test()
-
afterEach()
- Nth level
describe()
- 1st level
describe()
- top-level
- Nth level
-
afterAll()
- Nth level
describe()
- 1st level
describe()
- top-level
- Nth level
Disclaimer
I assume you have a basic understanding of jest and unit-testing. I will not explain the meaning of the hooks. This is more of cheat-sheet/reference type of post.
There are Rules
At first jest seems to do stuff magically. What gets executed when? But if you think about it for a minute it gets obvious less confusing.
Maybe these simple "rules" help:
- Each file is executed independently: nothing you do in
A.test.js
affectsB.test.js
. (unless you start to access external resources) -
describe()
callbacks are executed immediately. - hooks (
beforeAll
/afterAll
,beforeEach
/afterEach
) are executed from outer scope (top-level/module) to inner scope (describe).
Basic Example
console.log("./<start>");
beforeAll(() => {
console.log("./beforeAll");
})
beforeEach(() => {
console.log("./beforeEach");
})
afterAll(() => {
console.log("./afterAll");
})
afterEach(() => {
console.log("./afterEach");
})
describe("foo", () => {
console.log("./describe(foo)/<start>");
beforeAll(() => {
console.log("./describe(foo)/beforeAll");
})
beforeEach(() => {
console.log("./describe(foo)/beforeEach");
})
afterAll(() => {
console.log("./describe(foo)/afterAll");
})
afterEach(() => {
console.log("./describe(foo)/afterEach");
})
test("testFoo", () => {
console.log("./describe(foo)/test(testFoo)");
})
console.log("./describe(foo)/<end>");
})
describe("bar", () => {
console.log("./describe(bar)/<start>");
beforeAll(() => {
console.log("./describe(bar)/beforeAll");
})
beforeEach(() => {
console.log("./describe(bar)/beforeEach");
})
afterAll(() => {
console.log("./describe(bar)/afterAll");
})
afterEach(() => {
console.log("./describe(bar)/afterEach");
})
test("testBar", () => {
console.log("./describe(bar)/test(testBar)");
})
test("testOtherBar", () => {
console.log("./describe(bar)/test(testOtherBar)");
})
console.log("./describe(bar)/<end>");
})
console.log("./<end>");
This is the result (after I removed other output):
./<start>
./describe(foo)/<start>
./describe(foo)/<end>
./describe(bar)/<start>
./describe(bar)/<end>
./<end>
./beforeAll
./describe(foo)/beforeAll
./beforeEach
./describe(foo)/beforeEach
./describe(foo)/test(testFoo)
./describe(foo)/afterEach
./afterEach
./describe(foo)/afterAll
./describe(bar)/beforeAll
./beforeEach
./describe(bar)/beforeEach
./describe(bar)/test(testBar)
./describe(bar)/afterEach
./afterEach
./beforeEach
./describe(bar)/beforeEach
./describe(bar)/test(testOtherBar)
./describe(bar)/afterEach
./afterEach
./describe(bar)/afterAll
./afterAll
What happens?
Everything on the top-level and in describe callbacks is executed immediately:
./<start>
./describe(foo)/<start>
./describe(foo)/<end>
./describe(bar)/<start>
./describe(bar)/<end>
./<end>
[...]
beforeAll
and afterAll
on the top-level are a "brace" around all tests. Each executed only once.
[...]
./beforeAll
[...]
./afterAll
./describe(*)/beforeAll
and ./describe(*)/afterAll
are a brace around all tests in that describe
callback. Each executed only once.
[...]
./describe(foo)/beforeAll
[...]
./describe(foo)/afterAll
./describe(bar)/beforeAll
[...]
./describe(bar)/afterAll
[...]
beforeEach
and afterEach
are a braces around each test
. The top-level is the outer brace. The describe
level is the inner brace.
[...]
./beforeEach
./describe(*)/beforeEach
[...]
./describe(*)/afterEach
./afterEach
[...]
Advanced Version
This is an advanced example with a nested describe block. It produces XMLish results to emphasize the hierarchical nature of the execution steps.
console.log("<top-level>");
beforeAll(() => {
console.log("<all>");
})
beforeEach(() => {
console.log("<each>");
})
afterAll(() => {
console.log("</all>");
})
afterEach(() => {
console.log("</each>");
})
describe("foo", () => {
console.log("<describe id=\"foo\">");
beforeAll(() => {
console.log("<all in=\"foo\">");
})
beforeEach(() => {
console.log("<each in=\"foo\">");
})
afterAll(() => {
console.log("</all> <!-- in=\"foo\" -->");
})
afterEach(() => {
console.log("</each> <!-- in=\"foo\" -->");
})
test("testFoo", () => {
console.log("<test in=\"foo\" id=\"testFoo\" />");
})
console.log("</describe> <!-- id=\"foo\" -->");
})
describe("bar", () => {
describe("barinner", () => {
console.log("<describe id=\"barinner\">");
beforeAll(() => {
console.log("<all in=\"barinner\">");
})
beforeEach(() => {
console.log("<each in=\"barinner\">");
})
afterAll(() => {
console.log("</all> <!-- in=\"barinner\" -->");
})
afterEach(() => {
console.log("</each> <!-- in=\"barinner\" -->");
})
test("testBarInner", () => {
console.log("<test in=\"barinner\" id=\"testBarInner\" />");
})
console.log("</describe> <!-- id=\"barinner\" -->");
})
console.log("<describe id=\"bar\">");
beforeAll(() => {
console.log("<all in=\"bar\">");
})
beforeEach(() => {
console.log("<each in=\"bar\">");
})
afterAll(() => {
console.log("</all> <!-- in=\"bar\" -->");
})
afterEach(() => {
console.log("</each> <!-- in=\"bar\" -->");
})
test("testBar", () => {
console.log("<test in=\"bar\" id=\"testBar\" />");
})
test("testOtherBar", () => {
console.log("<test in=\"bar\" id=\"testOtherBar\" />");
})
console.log("</describe> <!-- id=\"bar\" -->");
})
console.log("</top-level>");
This is the output after some cleanup and formatting:
<top-level>
<describe id="foo">
</describe> <!-- id="foo" -->
<describe id="barinner">
</describe> <!-- id="barinner" -->
<describe id="bar">
</describe> <!-- id="bar" -->
</top-level>
<all>
<all in="foo">
<each>
<each in="foo">
<test in="foo" id="testFoo" />
</each> <!-- in="foo" -->
</each>
</all> <!-- in="foo" -->
<all in="bar">
<all in="barinner">
<each>
<each in="bar">
<each in="barinner">
<test in="barinner" id="testBarInner" />
</each> <!-- in="barinner" -->
</each> <!-- in="bar" -->
</each>
</all> <!-- in="barinner" -->
<each>
<each in="bar">
<test in="bar" id="testBar" />
</each> <!-- in="bar" -->
</each>
<each>
<each in="bar">
<test in="bar" id="otherBar" />
</each> <!-- in="bar" -->
</each>
</all> <!-- in="bar" -->
</all>
That's all there is to know about the execution order.
Posted on July 18, 2024
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.