JavaScript
Completed
-
Section 1: Getting Started
-
Section 2: Core Syntax and Types
-
Section 3: Strings and Numbers in Depth
-
Section 4: Control Flow
-
Section 5: Functions
-
Section 6: Objects and Arrays
-
Section 7: Maps, Sets, and Symbols
-
Section 8: Asynchronous JavaScript
-
Section 9: Object-Oriented and Prototypes
-
Section 10: The DOM
-
Section 11: Browser APIs
-
Section 12: Modern JavaScript (ES2015-ES2025)
-
Section 13: Functional Programming Patterns
-
Section 14: Error Handling and Debugging
-
Section 15: Testing
-
Section 16: Accessibility for JavaScript Developers
-
Section 17: Internationalization and Localization
-
Section 18: Performance
-
Section 19: Node.js Fundamentals
-
Section 20: Regular Expressions
-
Section 21: Design Patterns in JavaScript
-
Section 22: Security Basics
-
Section 23: Data Structures and Algorithms in JavaScript
-
Section 24: Practical Projects
-
Section 25: More Advanced Async Patterns
-
Section 26: More Object and Class Practice
-
Section 27: Working with Dates and Internationalization
-
Section 28: Web Components
-
Section 29: More DOM and Browser Practice
-
Section 30: Build Tooling for Vanilla JavaScript
-
Section 31: More Practice Projects
-
Section 32: Interview and Algorithm Practice
-
Section 33: Error Objects (MDN Reference)
-
Section 34: TypedArrays and Binary Data
-
Section 35: Reflection and Metaprogramming (MDN Reference)
-
Section 36: More Global Functions (MDN Reference)
121: Unit Testing with Jest
I see this all the time with developers moving into professional environments: the belief that unit testing is essentially just a way to automate the "manual check" you already do in the browser. You write your function, you run the app, you see it works, and then you write a test to "prove" it works. This is a fundamental misunderstanding of why we use tools like Jest.
Testing isn't just a double-check for your manual testing
If you only write tests for the "happy path" that you've already manually verified, you're not actually testing; you're just documenting that the code worked once. The real power of unit testing is regression testing—ensuring that a change you make to a utility function in six months doesn't silently break an edge case you forgot existed.
Take this common scenario. Imagine you have a function that calculates a user's membership discount. It seems simple enough:
function calculateDiscount(price, code) {
if (code === 'SUMMER10') return price * 0.9;
if (code === 'WINTER20') return price * 0.8;
return price;
}
You manually test 'SUMMER10', it works. You're happy. But later, a teammate changes the logic to support case-insensitive codes. They think they've fixed it, but they've actually introduced a bug where null codes now throw an error. Without a suite of tests covering those edge cases, you won't find that bug until a customer's checkout crashes in production. I've been there, and it's a nightmare.
Defining the contract with Matchers
In Jest, we don't just "run the code." We define a contract. We use describe blocks to group related tests and test (or it) to define specific behaviors. The magic happens in the expect statement, where we use "matchers" to assert the outcome.
Instead of just checking if the discount works, we write a suite that covers the "contract" of the function:
describe('calculateDiscount', () => {
test('applies 10% discount for SUMMER10', () => {
expect(calculateDiscount(100, 'SUMMER10')).toBe(90);
});
test('applies 20% discount for WINTER20', () => {
expect(calculateDiscount(100, 'WINTER20')).toBe(80);
});
test('returns original price for invalid codes', () => {
expect(calculateDiscount(100, 'BOGUS')).toBe(100);
});
test('handles null or undefined codes gracefully', () => {
expect(calculateDiscount(100, null)).toBe(100);
expect(calculateDiscount(100, undefined)).toBe(100);
});
});
Now, if someone breaks the null handling, the test suite fails immediately. You've shifted the burden of remembering edge cases from your brain to the machine.
Isolating logic from side effects with Mocks
The biggest hurdle I see learners hit is when their function depends on something "outside"—like an API call or a database. They think, "I can't unit test this because I don't want to actually call the API every time I run my tests."
You're right, you shouldn't. That's why we use Mocks. A unit test should test the logic of your function, not the reliability of your network. If your function fetches a user and then formats their name, you don't test the network request; you mock the response and test the formatting logic.
Using jest.mock() or jest.fn(), you can replace a real module with a fake one that returns a predictable value. This keeps your tests fast and deterministic. If your tests depend on a live server, they aren't unit tests—they're integration tests, and they'll be the first things to flake out and slow down your CI/CD pipeline.
📋 Practical Task
The Global Shipping Rate Calculator Regression Suite
You are maintaining a shipping module for an e-commerce site. The core logic is handled by a function called calculateShipping, but it relies on an external module currencyConverter.js to handle exchange rates. Your goal is to ensure the shipping logic remains intact even if the currency converter is unavailable or changes.
The Code:
// shipping.js
import { getExchangeRate } from './currencyConverter';
export function calculateShipping(weight, destination) {
const baseRate = destination === 'Domestic' ? 5 : 20;
const weightSurcharge = weight * 1.5;
const total = baseRate + weightSurcharge;
// Convert the total based on the destination's currency rate
const rate = getExchangeRate(destination);
return total * rate;
}
Your Task:
- Write a Jest test file for
calculateShipping. - Use
jest.mock('./currencyConverter')to prevent real API calls. - Create a test case for a Domestic shipment (Weight: 2kg, Expected Rate: 1) to ensure the base rate and surcharge are calculated correctly.
- Create a test case for an International shipment (Weight: 2kg) where you mock
getExchangeRateto return1.2. - Create an edge case test for zero weight to ensure it doesn't crash and returns only the base rate multiplied by the exchange rate.
There are no comments for now.