What is expect()
The expect function is the cornerstone of assertion-based testing in JavaScript. When you write a test, you're essentially making a promise about your code's behavior--and expect is how you make and validate that promise. Every test assertion follows the same pattern: you provide an actual value to expect(), then chain a matcher that defines what you expect to be true about that value.
At its core, expect() takes any value--primitives, objects, functions, or promises--and returns an object with a suite of matcher methods. These matchers perform the actual comparison and throw descriptive errors when assertions fail. Our /services/web-development/ team relies on comprehensive testing to deliver reliable web applications.
Testing is not just about finding bugs--it's about documenting expected behavior and preventing regressions as your codebase evolves. Effective test suites serve as executable specifications that give developers confidence when refactoring or adding new features.
1// Basic expect usage2expect(sum(2, 2)).toBe(4);3expect(user.name).toBe('John');4expect(items.length).toBeGreaterThan(0);Core Equality Matchers
The equality matchers form the backbone of most assertions, yet many developers reach for toBe() when toEqual() would be more appropriate. Understanding the difference between reference equality and deep equality is crucial for writing accurate tests.
toBe()usesObject.is()for strict reference comparisontoEqual()performs a deep equality check, recursively comparing all propertiestoStrictEqual()is the strictest matcher, catching undefined properties and array elements
Properly testing your data structures is essential when building /services/web-development/ solutions that handle complex state and API responses.
1// Reference equality vs deep equality2const user = { name: 'Alice', age: 30 };3 4// toBe checks reference equality5// expect(user).toBe({ name: 'Alice', age: 30 }); // FAILS6 7// toEqual checks deep equality8expect(user).toEqual({ name: 'Alice', age: 30 }); // PASSES9 10// toStrictEqual is strict about undefined11expect({ a: undefined }).toStrictEqual({}); // FAILS - catches undefinedTruthiness and Nullability Matchers
JavaScript's type system includes several values that represent "emptiness" or "nothingness": null, undefined, false, 0, '', and NaN. Testing for these requires specific matchers because the simple truthiness checks you'd use in application code don't always translate to precise assertions.
Available Matchers
toBeTruthy()- Passes for any truthy valuetoBeFalsy()- Passes for any falsy valuetoBeNull()- Passes only for nulltoBeUndefined()- Passes only for undefinedtoBeNaN()- Passes only for NaNtoBeDefined()- Passes for anything except undefined
Testing for null and undefined values is especially important in /services/web-development/ projects where API responses may return varying data structures.
1// Truthiness matchers in practice2function findUser(id) {3 const users = { '1': { name: 'Alice' } };4 return users[id] || null;5}6 7expect(findUser('1')).not.toBeNull(); // User exists8expect(findUser('999')).toBeNull(); // User not found9expect(findUser('1').name).toBeTruthy(); // Name has a value10 11expect(0).toBeFalsy(); // PASSES12expect('').toBeFalsy(); // PASSES13expect(null).toBeNull(); // PASSES14expect(undefined).toBeUndefined(); // PASSESString and Numeric Matchers
String and numeric assertions are among the most common test operations. These matchers provide flexible pattern matching that goes beyond exact equality.
String Matchers
toBe()- Exact string matchtoContain()- Substring presencetoMatch()- Regex pattern matchingtoHaveLength()- Exact string length
Numeric Matchers
toBe()- Exact numeric equality (for integers)toBeCloseTo()- Approximate equality for floating-pointtoBeGreaterThan()/toBeGreaterThanOrEqual()toBeLessThan()/toBeLessThanOrEqual()
1// String matchers2expect(email).toBe('[email protected]');3expect(email).toContain('@example.com');4expect(url).toMatch(/^https:\/\//);5expect(name).toMatch(/^[A-Z]/);6 7// Numeric matchers with precision8expect(price).toBeCloseTo(19.99, 5); // Within 5 decimal places9expect(count).toBeGreaterThan(0);10expect(count).toBeGreaterThanOrEqual(1);11expect(ratio).toBeCloseTo(0.333, 2); // Close to 1/3Async Matchers: Resolves and Rejects
Modern JavaScript relies heavily on asynchronous operations. Testing these requires assertions that can wait for promises to settle and validate both successful results and error conditions.
The resolves matcher waits for the promise to fulfill and then applies the following matcher to the resolved value. The rejects matcher verifies that a promise rejects and applies matchers to the rejection reason.
When building modern /services/web-development/ applications with APIs and microservices, thorough async testing ensures your integrations work reliably under all conditions.
1// Promise resolution testing2test('fetches user data successfully', async () => {3 await expect(fetchUser('123')).resolves.toHaveProperty('id', '123');4});5 6// Testing promise rejection7test('rejects invalid input', async () => {8 await expect(validateEmail('invalid')).rejects.toThrow('Invalid email');9});10 11// Comprehensive async testing12test('API returns paginated results', async () => {13 await expect(fetchUsers({ page: 1, limit: 10 }))14 .resolves.toEqual({15 data: expect.arrayContaining([16 expect.objectContaining({ id: expect.any(String) })17 ]),18 pagination: {19 page: 1,20 total: expect.any(Number)21 }22 });23});Snapshot Testing with expect
Snapshot testing shifts the paradigm from explicitly asserting expected values to capturing and comparing output against previously recorded "snapshots." This approach is particularly powerful for catching unintended changes to user-facing output.
Property Matchers for Dynamic Values
Dynamic values like timestamps and generated IDs would cause every snapshot test to fail. Property matchers solve this by allowing you to specify that certain fields should match a pattern rather than an exact value.
expect.any(type)- matches any value of the specified typeexpect.stringMatching(regex)- matches strings matching the regex
1// Snapshot with property matchers2test('user object snapshot with property matchers', () => {3 const user = {4 id: generateId(), // Changes every run5 name: 'Alice',6 createdAt: new Date(), // Changes every run7 email: '[email protected]'8 };9 10 expect(user).toMatchSnapshot({11 id: expect.any(String),12 createdAt: expect.any(Date)13 });14});15 16// Basic snapshot17test('component renders correctly', () => {18 const tree = renderer.create(<Link page="https://example.com">Example</Link>).toJSON();19 expect(tree).toMatchSnapshot();20});Custom and Asymmetric Matchers
Sometimes the built-in matchers don't quite express what you need. The expect.extend() function lets you add custom matchers that integrate seamlessly with the expect chain. Asymmetric matchers let you express partial expectations without requiring an exact match.
Key Asymmetric Matchers
expect.any(type)- Any value of the specified typeexpect.stringContaining(str)- Strings containing the substringexpect.stringMatching(regex)- Strings matching the regexexpect.arrayContaining(arr)- Arrays containing the elementsexpect.objectContaining(obj)- Objects with the specified properties
1// Custom matcher for URL validation2expect.extend({3 toBeValidUrl(received) {4 const urlPattern = /^https:\/\/[^\s]+$/;5 const pass = urlPattern.test(received);6 7 return {8 pass,9 message: () => `expected ${received} ${pass ? 'not ' : ''}to be a valid URL`10 };11 }12});13 14// Using custom matcher15expect('https://example.com').toBeValidUrl();16 17// Asymmetric matchers in assertions18expect(response).toEqual({19 success: true,20 data: expect.objectContaining({21 userId: expect.any(String),22 name: expect.stringContaining('Alice')23 }),24 errors: expect.arrayContaining([25 expect.objectContaining({ code: 'VALIDATION_ERROR' })26 ])27});Performance Considerations
As test suites grow, execution time becomes increasingly important. While individual expect assertions are fast, the patterns you use can significantly impact suite performance.
Optimization Tips
- Prefer compound matchers - Single
toMatchObject()with multiple properties is faster than chaining multipletoBe()calls - Use
mockReset()- Clears mock call history without recreating the mock - Parallel execution - Use
test.concurrent()for independent tests - Shared setup - Use
beforeAllhooks to amortize setup costs
1// Performance-optimized test patterns2describe('User API', () => {3 const mockUserService = {4 fetchById: jest.fn(),5 update: jest.fn()6 };7 8 beforeEach(() => {9 mockUserService.fetchById.mockReset(); // Reset, don't recreate10 });11 12 // Good: Compound assertion13 test('fetches user by ID', async () => {14 mockUserService.fetchById.mockResolvedValue({ id: '123', name: 'Alice' });15 const result = await mockUserService.fetchById('123');16 17 expect(result).toMatchObject({18 id: '123',19 name: 'Alice'20 });21 });22 23 // Parallel test execution24 test.concurrent('fetches configuration', async () => {25 const config = await fetchConfig();26 expect(config).toHaveProperty('apiVersion');27 });28});Best Practices Summary
Key Takeaways
- Choose the right equality matcher - Default to
toEqual()for objects and arrays, usetoBe()for primitives - Group related assertions - Compound matchers reduce test noise and improve performance
- Use async matchers properly - Prefer
resolvesandrejectsfor promise-based code - Invest in custom matchers - For domain-specific assertions that appear frequently
- Write descriptive failure messages - Help future developers (including yourself) debug quickly
Quick Reference
| Matcher | Use Case |
|---|---|
toBe() | Primitives, reference equality |
toEqual() | Objects and arrays (deep equality) |
toStrictEqual() | Exact structure including undefined |
toMatchObject() | Partial object matching |
toContain() | Array/string contains element/substring |
toMatch() | Regex pattern matching |
resolves | Promise fulfillment |
rejects | Promise rejection |
toMatchSnapshot() | UI component/serializable output |
Key capabilities of the expect function for robust testing
Comprehensive Matchers
Equality, truthiness, string, numeric, and async matchers cover all testing scenarios.
Snapshot Testing
Capture and compare complex output automatically with toMatchSnapshot.
Custom Matchers
Extend expect with domain-specific assertions for your business logic.
Clear Error Messages
Detailed failure output helps you quickly identify and fix issues.
Frequently Asked Questions
Sources
- GitHub: JavaScript Testing Best Practices - Comprehensive guide covering Jest expect patterns and testing strategies
- Jest Documentation: Snapshot Testing - Official documentation on snapshot testing with expect matchers
- BrowserStack: JavaScript Testing Best Practices - Industry testing standards and expect usage