Mastering TDD with TypeScript: A Simple Calculator Example

Mastering TDD with TypeScript: A Simple Calculator Example

Introduction

At its core, Test-Driven Development (TDD) works by continuously switching between the test file and the application code file.

You write a failing test in the test file to define the expected behaviour.

  • Then you switch to the app code file to write the minimal code required to make the test pass.
  • This cycle repeats as you build out your application, driven by tests.


It is a Two-Pronged approach between:

  1. The test code → Defines what you expect to happen.
  2. The app (production) code → Makes it happen.


It's a tight feedback loop: Test ➜ Fail ➜ Code ➜ Pass ➜ Refactor ➜ Repeat.

Setup

The folder structure for this project comprises of the following:

Article content
Project directory structure 

Using the command ‘mkdir’, create a ‘src’ folder in the root directory, along with a tests folder:

Article content
command to make the src directory
Article content
command to make the tests directory

 

In the tests folder, either by using the command ‘touch’:

touch calculator.tests.ts        

Or in vscode, using ‘right click’ and create new file, create a test file called:            

calculator.tests.ts        

And in the ‘src’ folder, again either using the ‘touch’ command (touch calculator.ts), create a file called:

            calculator.ts        
Article content
Project explorer

 

 

𝗜𝗻𝘀𝘁𝗮𝗹𝗹𝗮𝘁𝗶𝗼𝗻 𝗰𝗼𝗺𝗺𝗮𝗻𝗱𝘀:

In a nutshell, these are the ‘npm commands’ you run through to scaffold a basic typescript project:

npm init -y        
npm install --save-dev typescript        
npx tsc --init        
npm install --save-dev jest ts-jest @types/jest        
npx ts-jest config:init        

𝗪𝗵𝗮𝘁 𝗲𝗮𝗰𝗵 𝗼𝗳 𝘁𝗵𝗲𝗺 𝗱𝗼 𝗮𝗿𝗲 𝗮𝘀 𝗳𝗼𝗹𝗹𝗼𝘄𝘀:

  • npm init -y - Scaffolds (sets up) a basic Node.js project by automatically generating a package.json file with default values.
  • tsc --init - creates a tsconfig.json file in your project directory.
  • npm install --save-dev jest ts-jest @types/jest - installs Jest and TypeScript-related testing tools as development dependencies (--save-dev) in your project.
  • npx ts-jest config:init - initialises the configuration for ts-jest and generates a jest.config.js file that is pre-configured for working with TypeScript.

Specifically:

  • It creates a jest.config.js file (sometimes jest.config.ts if you tweak settings).
  • Pre-configures Jest to: Use ts-jest as its transformer, so Jest can understand TypeScript files.Look for .test.ts or .spec.ts files as your test files.

Here’s an example jest.config.js file

/** @type {import('ts-jest').JestConfigWithTsJest} */        
module.exports = {        
  preset: 'ts-jest',        
  testEnvironment: 'node',        
};        

 

Breakdown of the above:

preset: 'ts-jest'        

Tells Jest to use ts-jest so it can run TypeScript files without manual compilation

testEnvironment: 'node'        

Sets the environment for the tests (Node.js in this case). For browser-like environments, you’d use jsdom.

Why Use ts-jest?

  • TypeScript doesn’t natively run in Jest.
  • ts-jest compiles your .ts files on-the-fly for testing purposes.
  • No need to manually compile TypeScript into JavaScript before running tests.

 

❌ TDD Example: Calculator App and Test Setup (Red Phase)

1. In the /src folder, create a file called calculator.ts.

This is our empty app file, where we will define the logic later. For now, it contains a placeholder function with a temporary implementation.


2. In the /tests folder, create a file called calculator.test.ts.

This is our first failing test. It defines what we expect the add function to do. At this point, the test will fail, which is exactly what we want in the Red phase of TDD.

Article content
calculator.test.ts

 

3. Run the test in the VS Code terminal using the command: npx jest

4. You should see the test fail with the following message (or similar):

 

Article content
Failed test run

 

✅ What Just Happened?

  • The test fails because our add function doesn’t return the correct result.

Article content

  • This is the Red phase of Red-Green-Refactor.
  • Next, we will write the app code to make this test pass (Green phase).

  

✅ Next Step →  Green Phase (Make It Pass!)

Now, you update your app code to pass the test.

In /src/calculator.ts, replace the placeholder with a working function:

Note that we now have the function return a + b; instead of return 0; like before

Article content
working function

 

Next from the VS Code terminal, run the test again:

npx jest        

 

Article content
passing test run

  

🎉 You’ve successfully done the Red phase of TDD.

🎉 Your test correctly failed and told you exactly what wasn’t working.

🎉 Now you're ready to pass the test and move forward.

  

✅ Continuing the Red-Green-Refactor Cycle (Calculator Example)

After completing the add() function, you can keep following the TDD process by adding new functionality, like subtraction, multiplication, and division.

❌ Back to Red

We now need to write a failing test again. Seeing as this is a calculator, we now add the functions subtract, multiply and divide:

This is where TypeScript really proves its value. It catches errors at compile time, preventing you from running broken code. In contrast, JavaScript would allow the code to compile and run, only throwing an error at runtime.

Article content
typescript errors

So, the test cannot be run, owing to these errors, detailed above.

For the purposes of TDD, and to be able to run the test:

We need to create an empty or minimal version of the function, so TypeScript stops complaining. This lets us run the test, watch it fail (Red), and then we can start writing the code to make it pass (Green).

Below is a minimal version of the calculator.ts file, where each function is defined just enough to satisfy TypeScript and allow you to run the tests, knowing they'll fail at first (which is exactly what you want in TDD’s Red phase).


Article content
defined typescript functions

 

The errors disappear from the test:

We can now run the tests and expect them to ALL fail. Why ALL you ask?

Because in the calculator.ts each function returns a ‘0’.

It’s a function, but in TDD, during the Red phase, it acts as a stub so you can run failing tests and move forward.

Article content
typescript stub

 

✅ Red ➡️ Green Example: Moving from Stub to Real Function

➡️ Red Phase (Stub Function)

You start with a minimal implementation, a stub that doesn’t do the real work, but makes TypeScript and Jest happy enough to run.

calculator.ts (Red phase)

 

Article content
typescript stub

Now you replace the stub with the real logic that makes the test pass.

Article content
typescript function

 

✅ Key Takeaway

You start with a stub (minimal placeholder function) to get the test running. Once you see the test fail, you write the real implementation. This progresses from Red ➡️ Green, following TDD.

You write a stub function first to satisfy the compiler and make your test fail (Red), then replace it with the real function to make the test pass (Green).

✅ Green Refactor and pass

We need to update the calculator.ts functions to return values:

Next we run the tests by running the command:

npx jest         

in the vscode terminal:

 

Article content
Passing test run

All tests now pass

 

✅ Refactor Ideas for calculator.ts

1. Inline Simple Functions

If the functions are simple enough, you can make them single-line arrow functions for brevity and readability.

Article content
refactored calculator.ts

The above compares to what went before below:


Article content
original calculator.ts file


To view or add a comment, sign in

More articles by Stuart du Casse

  • Can BDD Transform Other Industries?

    I guess this came about as a means to demonstrate that BDD, otherwise known as Behaviour Driven Development is…

    1 Comment
  • Starting an Automated Software Testing Consultancy

    I'm in the process of launching my own Automated Software Testing Consultancy, but I want to get this right and would…

Insights from the community

Others also viewed

Explore topics