-
Section 1: Getting Started
-
Section 2: Basic Types
-
Section 3: Functions and Objects
-
Section 4: Advanced Types
-
Section 5: Object-Oriented TypeScript
-
Section 6: Working with Modules
-
Section 7: Tooling and Practice
-
Section 8: Type-Level Programming
-
Section 9: TypeScript with Backends
-
Section 10: Testing Typed Code
-
Section 11: Data Validation with Types
-
Section 12: Practical Projects
-
Section 13: Compiler Internals
-
Section 14: Configuration Deep Dive
-
Section 15: Enums, Symbols, and Special Types
-
Section 16: Working with Async Code
-
Section 17: TypeScript and the DOM
-
Section 18: Advanced Generics Practice
-
Section 19: Working with Third-Party Types
-
Section 20: Monorepo and Large-Scale Practices
-
Section 21: Common Pitfalls and Best Practices
-
Section 22: Interview Practice
-
Section 23: Handbook: Narrowing In Depth
-
Section 24: Handbook: Object Types In Depth
-
Section 25: Handbook: Classes In Depth
-
Section 26: Handbook: Modules In Depth
-
Section 27: Handbook: Declaration Files In Depth
-
Section 28: JSX and Namespaces
-
Section 29: Compiler Configuration Reference
-
Section 30: More Practice Exercises
-
Section 31: Handbook: Everyday Types Deep Dive
-
Section 32: Utility Types Full Reference
-
Section 33: Decorators Reference
-
Section 34: Mixins and Advanced OOP Patterns
-
Section 35: Iterators and Generators Typing
-
Section 36: More Type-Level Programming Practice
-
Section 37: TypeScript Ecosystem Tools
-
Section 38: TypeScript with Testing Frameworks
-
Section 39: TypeScript for Library Authors
-
Section 40: More Interview Practice
-
Section 41: Handbook: Functions In Depth
-
Section 42: Handbook: Type Manipulation Deep Dive
-
Section 43: More Real-World Patterns
-
Section 44: TypeScript Release Notes Highlights
-
Section 45: Final Practice and Review
70: Unit Testing TypeScript with Jest and ts-jest
Up until now, we've been relying on manual testing—running the code and seeing if it crashes. That works for small scripts, but in a professional codebase, it's a recipe for disaster. I want to show you how to set up a proper unit testing suite using Jest and ts-jest. Jest is the industry standard for JavaScript testing, but since we're in TypeScript land, we need ts-jest to handle the transpilation on the fly so Jest can actually understand our types.
Getting the environment ready
First, we need the tooling. I usually install these as dev dependencies because your production server doesn't need to know how to run tests. Run this in your terminal:
npm install --save-dev jest ts-jest @types/jest typescript
After that, we need a configuration file. I'm not going to make you write a JSON file by hand; just run npx ts-jest config:init. This creates a jest.config.js that tells Jest, "Hey, whenever you see a .ts file, use ts-jest to process it."
Building a ShoppingCart to test
Let's build something concrete. I'll create a simple ShoppingCart class. It's a classic example because it involves state (the items) and logic (the total calculation), which is exactly what we want to isolate in unit tests.
// shoppingCart.ts export interface Item { name: string; price: number; } export class ShoppingCart { private items: Item[] = []; addItem(item: Item) { this.items.push(item); } getTotal(discountCode?: string): number { const subtotal = this.items.reduce((sum, item) => sum + item.price, 0); if (discountCode === 'SAVE10') { return subtotal * 0.9; } return subtotal; } }Writing our first test case
Now, let's see if the
addItemandgetTotallogic actually works. I'll create a file namedshoppingCart.test.ts. I like the.test.tssuffix because it makes it incredibly easy to find tests in a large project tree.// shoppingCart.test.ts import { ShoppingCart } from './shoppingCart'; test('should calculate the total of added items', () => { const cart = new ShoppingCart(); cart.addItem({ name: 'Keyboard', price: 100 }); cart.addItem({ name: 'Mouse', price: 50 }); expect(cart.getTotal()).toBe(150); });Hitting a wall with configuration
I'll be honest: the first time I ran this, it failed. I got a confusing error:
SyntaxError: Unexpected token 'export'. I had forgotten that I'd initialized my project with"type": "module"inpackage.json, but my Jest config was expecting CommonJS.I could have spent an hour fighting with ESM modules in Jest (which is a rabbit hole you don't want to go down today). Instead, I realized the quickest fix for this small project was to ensure
ts-jestwas correctly mapped in my config and that I wasn't mixing module systems. I updated myjest.config.jsto explicitly handle the transformation of TS files, and suddenly, the "Unexpected token" disappeared and the tests passed. Always check yourpackage.jsonandjest.config.jsalignment when you see syntax errors in a test runner.Testing the discount logic and edge cases
Now that the plumbing is working, we can actually test the business logic. A good engineer doesn't just test the "happy path"; they try to break things. Let's add tests for the discount code and what happens when the cart is empty.
test('should apply 10% discount with SAVE10 code', () => { const cart = new ShoppingCart(); cart.addItem({ name: 'Monitor', price: 200 }); expect(cart.getTotal('SAVE10')).toBe(180); }); test('should return 0 for an empty cart', () => { const cart = new ShoppingCart(); expect(cart.getTotal()).toBe(0); }); test('should ignore invalid discount codes', () => { const cart = new ShoppingCart(); cart.addItem({ name: 'Cable', price: 20 }); expect(cart.getTotal('WRONGCODE')).toBe(20); });Now, when I run
npm test, I get a satisfying green checklist. If I accidentally change the discount multiplier to 0.8 in the source code, Jest will immediately tell me exactly which test failed and what the expected value was versus what it actually got.
📋 Practical Task
Exercise: Implementing and Testing a Tax Calculator
You need to extend the ShoppingCart logic to handle sales tax, but you must ensure it doesn't break the existing functionality. Follow these requirements:
- Modify the
getTotalmethod inshoppingCart.tsto accept an optionaltaxRate(a decimal, e.g., 0.07 for 7%). - The tax should be applied to the discounted price (calculate the discount first, then add the tax).
- Create a new test file
taxCalculator.test.ts. - Write three tests:
- One where a 10% tax is applied to a standard total.
- One where both the 'SAVE10' discount and a tax rate are applied simultaneously.
- One where the tax rate is 0, ensuring the total remains unchanged.
Run your tests using npm test to verify that your tax logic is mathematically sound and that your types are correctly enforced.
There are no comments for now.