Manage Expectations in TypeScript with @push.rocks/smartexpect
Learn how @push.rocks/smartexpect provides a fluent, type-safe assertion library for TypeScript, making tests readable, maintainable, and powerful.
A fluent, type-safe assertion library that makes your tests read like documentation.
Introduction
Writing clear and maintainable tests is just as important as writing production code. Traditional assertion libraries can sometimes be verbose or lack the expressiveness needed for complex scenarios. Enter @push.rocks/smartexpect, a TypeScript-native assertion library that combines a fluent API with precise, descriptive error messages.
What is @push.rocks/smartexpect?
@push.rocks/smartexpect
provides a rich set of built-in matchers and modifiers, allowing you to write synchronous and asynchronous assertions in a natural, chainable style. It integrates seamlessly with both Node.js and browser environments and is published on npm under the MIT license by Task Venture Capital GmbH.
Key highlights:
- Fluent API: Chainable methods mirror natural language.
- Sync & Async Support:
.resolves
and.rejects
modifiers for promises. - Deep Navigation: Drill into nested objects and arrays with
.property()
and.arrayItem()
. - Rich Matchers: Over 50 built-in matchers for primitives, objects, arrays, dates, and more.
- Custom Extensions: Define your own matchers with
expect.extend()
. - Debugging: Inspect intermediate values with
.log()
.
Installation
Install via npm or pnpm:
pnpm add @push.rocks/smartexpect --save-dev
# or using npm
npm install @push.rocks/smartexpect --save-dev
Getting Started
Import the expect
function and start writing tests:
import { expect } from '@push.rocks/smartexpect';
// Basic type assertions
expect(42).toBeTypeofNumber();
expect('hello').toBeTypeofString();
// Equality checks
expect({ a: 1 }).toEqual({ a: 1 });
expect([1, 2, 3]).toContain(2);
Asynchronous Assertions
Handle promises with ease:
async function fetchUser(id: number): Promise<{ id: number; name: string }> {
// ...fetch logic...
return { id, name: 'Alice' };
}
// In your test:
await expect(fetchUser(1)).resolves.toHaveProperty('name', 'Alice');
await expect(fetchUser(-1)).rejects.toThrow();
Navigating Complex Objects
Deeply nested data structures can be asserted without temporary variables:
const data = { users: [{ id: 1, profile: { active: true } }] };
expect(data)
.property('users')
.arrayItem(0)
.property('profile')
.property('active')
.toBeTrue();
Custom Matchers and Messages
Extend expect
with domain-specific assertions:
expect.extend({
toBeEven(received: number) {
const pass = received % 2 === 0;
return { pass, message: () => `Expected ${received} to be even` };
}
});
expect(4).toBeEven();
expect(5).not.toBeEven();
Override default failure messages for clarity:
expect(user.age)
.setFailMessage('User must be at least 18 years old')
.toBeGreaterThanOrEqual(18);
Debugging with .log()
Visualize intermediate values in assertion chains:
expect(order)
.property('items')
.log()
.arrayItem(0)
.log()
.property('quantity')
.toBeGreaterThan(0);
Getting Involved
- GitHub: https://code.foss.global/push.rocks/smartexpect
- npm: https://www.npmjs.com/package/@push.rocks/smartexpect
- Docs & Examples: Check the project README for comprehensive matcher references.
Happy testing!