I use Jest nearly every day when working, and it's a fantastic tool. It lets me ship my code with confidence, knowing that I have produced something which works as intended. More often than not, when I write tests for my code, I end up catching something I hadn't considered and go back to take that into account. It saves me from getting called in the evening to fix something in production. For me, that's a big deal. With that said, I didn't really know how jest . I used it all the time, but had no real clue what was going on under the hood. worked Recently, I bought Kent C Dodd's excellent course which has been incredible for increasing my knowledge. Testing JavaScript As part of that, he digs into how jest works under the hood, and this encouraged me to try building my own tiny version. So I want to pass on that knowledge to you! This will be a small series of posts on each part, but you can skip ahead and see the full repo . here Building our test runner Today's focus will be building the actual test runner. This simply accepts a test with a title, and a callback. We run the callback and if there are no errors, the test passes! If an error is thrown, then we deem the test to have failed. Take a look: test = (title: string, : ) => { { callback(); .log(chalk.green( )); } (error) { .error(chalk.red( )); .error(error); } const async callback Function try await console `\u2713 ` ${title} catch console `✕ ` ${title} console So as you can see, we have our test function which accepts a title which is a string, and a callback which is the function which we want to test. We then run our callback function in a try/catch block, and assuming that nothing is caught, we say the test has passed. This allows us to run something like this: test( , () => { sum = a + b result = sum( , ) expected = expect(result).toBe(expected) }) 'sum adds numbers' const ( ) => a, b const 3 7 const 10 So as you can see, we pass a title, and a function where we sum two numbers: 3 and 7. But on our final line, we see something new: and . These are our assertions and we have nothing to handle them yet. expect toBe Building our assertions Fundamentally, an assertion is a very simple concept of whether two inputs match. Does result in 10? We don't want to have to write logic like this for everything: sum(3,7) (sum( , ) !== ) { ( ) } if 3 7 10 throw new Error 'Sums do not match' Instead, we want to extract this out to a helper utility we will call expect, much like as you see in jest. expect = { { toBe(expected: | | ) { (actual !== expected) { ( ) } }, } } const ( ) => actual: Function return String Object Array if throw new Error ` is not equal to ` ${actual} ${expected} As you can see, we take in a function which is what we are running our assertion on. We then have a series of methods on a returned object allowing us to expand our test matchers later. In this case we are wanting a simple toBe test for an exact match. So we accept a variable called expected on toBe and compare that to the result of our function that we passed in earlier. Going back to our previous example where we add 3, and 7, we can do something like this: expect(sum( , )).toBe( ) 3 7 10 Pretty simple right? Although jest itself is a far more complex tool, this is more or less how it works. We can extend our matchers as well. For example, if we wanted to check for a falsy value, we could do something like this: toBeFalsy() { (actual) { ( ); } }, if throw new Error ` is not falsy.` ${actual} As you can see, our expected function can easily be extended to cater to whatever assertions you need to make. Putting it together, you can access it within our test runner and the above code will return: ✅ sum adds numbers And that's it! You've just made a very, very simple test runner with some assertions. In the next post in this series, I'll be showing you how to write your own test mocks which allow you to simulate function calls so that you don't run them in reality. It's a very useful technique. If you want to see the full code, just take a look at the ! repo