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)
126: Testing with Vitest
Imagine you're a chef preparing a complex sauce for a high-end dinner service. You wouldn't just pour the entire pot onto a plate and serve it to a customer to see if it tastes right, right? That's a recipe for a disaster. Instead, you use a tasting spoon. You take a tiny sample, check for salt, taste for acidity, and adjust. If the spoon tastes right, you can be reasonably confident the whole pot is good.
In our world, Vitest is that tasting spoon. Instead of booting up your entire application, clicking through the UI, and hoping you didn't break the checkout flow, you write a small, isolated test to verify one specific "flavor" of your code. If the test passes, you know that specific logic is sound without having to run the whole program.
Why we're using Vitest over the alternatives
You've probably heard of Jest. For years, it was the gold standard. But if you're using Vite for your build tool—which you are—Vitest is a no-brainer. It's designed to share the same configuration as your Vite project, meaning you don't have to spend three hours fighting with Babel or TypeScript transforms just to get your tests to run. It's incredibly fast and uses a syntax that's almost identical to Jest, so the skills are transferable.
Putting assertions to work
Let's look at a real scenario. Suppose you've written a utility function that calculates the final price of an item after applying a discount and tax. This is the kind of logic where a tiny typo—like a plus sign instead of a minus—can cost a company thousands of dollars.
// priceCalculator.js
export function calculateFinalPrice(price, discount, taxRate) {
const discounted = price - (price * discount);
return discounted + (discounted * taxRate);
}
To test this, we create a file ending in .test.js. Here is how I'd set up a suite to make sure this logic is bulletproof:
import { describe, it, expect } from 'vitest';
import { calculateFinalPrice } from './priceCalculator';
describe('calculateFinalPrice()', () => {
it('should apply a 10% discount and 5% tax correctly', () => {
const result = calculateFinalPrice(100, 0.10, 0.05);
// 100 - 10 = 90. 90 + (90 * 0.05) = 94.5
expect(result).toBe(94.5);
});
it('should return the original price if discount and tax are zero', () => {
expect(calculateFinalPrice(100, 0, 0)).toBe(100);
});
it('should handle free items correctly', () => {
expect(calculateFinalPrice(0, 0.10, 0.05)).toBe(0);
});
});
Notice the pattern: describe groups our tests together, it describes the specific behavior we expect, and expect(...).toBe(...) is the actual check. If the value inside toBe doesn't match the result, Vitest will scream at you in the console, telling you exactly what it expected versus what it actually got.
Dealing with the "unpredictables"
The hardest part of testing isn't the math; it's the stuff you can't control, like API calls or the current date. I've spent way too many hours watching tests fail simply because it was a leap year or the server was down. This is where mocking comes in.
Vitest allows you to replace a real function with a "spy" or a "mock." If your function calls fetch() to get a user's profile, you don't actually want to hit the network every time you run a test. You can tell Vitest: "When this function is called, don't actually go to the internet; just pretend the server returned this specific JSON object." This keeps your tests fast, deterministic, and capable of running on a plane without Wi-Fi.
📋 Practical Task
Exercise: Validating a Password Strength Checker
You need to build and test a password validation utility. Your goal is to ensure that users aren't choosing passwords that are too simple, but also that the validator doesn't accidentally reject valid passwords.
The Requirements:
- Create a function
validatePassword(password)that returnstrueif the password is at least 8 characters long and contains at least one number, andfalseotherwise. - Write a Vitest test suite that covers the following scenarios:
- A password that is too short (e.g., "Pass1").
- A password that is long enough but has no numbers (e.g., "PasswordOnly").
- A password that meets all criteria (e.g., "SecurePass123").
- An empty string.
Success Criteria: Your test suite should run 4 tests, and all 4 must pass. Use describe and it blocks to keep your tests organized.
There are no comments for now.