1409 lines
31 KiB
Markdown
1409 lines
31 KiB
Markdown
# Bupkis API Reference
|
|
|
|
Complete reference for all built-in Bupkis assertions. This document is organized by assertion category.
|
|
|
|
## Table of Contents
|
|
|
|
- [Core Concepts](#core-concepts)
|
|
- [Primitive Assertions](#primitive-assertions)
|
|
- [Numeric Assertions](#numeric-assertions)
|
|
- [String & Pattern Assertions](#string--pattern-assertions)
|
|
- [Collection Assertions](#collection-assertions)
|
|
- [Object Assertions](#object-assertions)
|
|
- [Function Assertions](#function-assertions)
|
|
- [Equality & Comparison Assertions](#equality--comparison-assertions)
|
|
- [Error Assertions](#error-assertions)
|
|
- [Date & Time Assertions](#date--time-assertions)
|
|
- [Promise Assertions](#promise-assertions)
|
|
- [Other Assertions](#other-assertions)
|
|
|
|
---
|
|
|
|
## Core Concepts
|
|
|
|
### Natural Language Assertions
|
|
|
|
Bupkis uses natural language phrases instead of method chaining:
|
|
|
|
```typescript
|
|
// Instead of:
|
|
expect(actual).toEqual(expected);
|
|
|
|
// Write:
|
|
expect(actual, 'to equal', expected);
|
|
expect(actual, 'is', expected);
|
|
expect(actual, 'to be', expected);
|
|
```
|
|
|
|
### Anatomy of an Assertion
|
|
|
|
```typescript
|
|
expect(subject, 'phrase', [parameter?, phrase?, parameter?, ...]);
|
|
```
|
|
|
|
- **Subject**: The value being tested (first parameter)
|
|
- **Phrase**: String describing the assertion (e.g., 'to be', 'to equal')
|
|
- **Parameter**: Optional values for comparison or validation
|
|
|
|
### Negation
|
|
|
|
ANY assertion can be negated by prepending `not` to the first phrase:
|
|
|
|
```typescript
|
|
expect(42, 'to be', 42); // passes
|
|
expect(42, 'not to be', '42'); // passes
|
|
expect('hello', 'not to be a number'); // passes
|
|
```
|
|
|
|
### Concatenation with 'and'
|
|
|
|
Chain multiple assertions on the same subject:
|
|
|
|
```typescript
|
|
expect(
|
|
user,
|
|
'to be an object',
|
|
'and',
|
|
'to have property',
|
|
'name',
|
|
'and',
|
|
'to satisfy',
|
|
{ age: expect.it('to be greater than', 18) },
|
|
);
|
|
```
|
|
|
|
### Embeddable Assertions with expect.it()
|
|
|
|
Use `expect.it()` to embed assertions within "to satisfy" patterns:
|
|
|
|
```typescript
|
|
expect(user, 'to satisfy', {
|
|
name: expect.it('to be a string'),
|
|
email: /^[^\s@]+@[^\s@]+\.[^\s@]+$/, // RegExp works too
|
|
age: expect.it('to be greater than', 18),
|
|
roles: [expect.it('to be a string')], // Each element must be a string
|
|
});
|
|
```
|
|
|
|
---
|
|
|
|
## Primitive Assertions
|
|
|
|
### `{unknown} to be a string`
|
|
|
|
**Aliases:** None
|
|
|
|
**Checks:** Value is a string primitive or String object
|
|
|
|
```typescript
|
|
expect('hello', 'to be a string'); // ✓
|
|
expect(42, 'to be a string'); // ✗
|
|
expect(42, 'not to be a string'); // ✓
|
|
```
|
|
|
|
### `{unknown} to be a boolean`
|
|
|
|
**Aliases:** `to be a bool`, `to be boolean`
|
|
|
|
**Checks:** Value is a boolean primitive or Boolean object
|
|
|
|
```typescript
|
|
expect(true, 'to be a boolean'); // ✓
|
|
expect(0, 'to be a boolean'); // ✗
|
|
expect(0, 'not to be a boolean'); // ✓
|
|
```
|
|
|
|
### `{unknown} to be a number`
|
|
|
|
**Aliases:** `to be finite`
|
|
|
|
**Checks:** Value is a finite number (NaN and Infinity excluded)
|
|
|
|
```typescript
|
|
expect(42, 'to be a number'); // ✓
|
|
expect(NaN, 'to be a number'); // ✗ (NaN not considered a number)
|
|
expect(Infinity, 'to be a number'); // ✗ (Infinity not considered a number)
|
|
```
|
|
|
|
### `{unknown} to be a bigint`
|
|
|
|
**Aliases:** None
|
|
|
|
**Checks:** Value is a BigInt
|
|
|
|
```typescript
|
|
expect(9007199254741991n, 'to be a bigint'); // ✓
|
|
expect(42, 'to be a bigint'); // ✗
|
|
```
|
|
|
|
### `{unknown} to be a symbol`
|
|
|
|
**Aliases:** None
|
|
|
|
**Checks:** Value is a Symbol
|
|
|
|
```typescript
|
|
expect(Symbol('foo'), 'to be a symbol'); // ✓
|
|
expect('foo', 'to be a symbol'); // ✗
|
|
```
|
|
|
|
### `{unknown} to be null`
|
|
|
|
**Aliases:** None
|
|
|
|
**Checks:** Value is exactly null
|
|
|
|
```typescript
|
|
expect(null, 'to be null'); // ✓
|
|
expect(undefined, 'to be null'); // ✗
|
|
```
|
|
|
|
### `{unknown} to be undefined`
|
|
|
|
**Aliases:** None
|
|
|
|
**Checks:** Value is exactly undefined
|
|
|
|
```typescript
|
|
expect(undefined, 'to be undefined'); // ✓
|
|
expect(null, 'to be undefined'); // ✗
|
|
```
|
|
|
|
### `{unknown} to be a primitive`
|
|
|
|
**Aliases:** None
|
|
|
|
**Checks:** Value is a primitive (string, number, boolean, null, undefined, symbol, bigint)
|
|
|
|
```typescript
|
|
expect('hello', 'to be a primitive'); // ✓
|
|
expect(42, 'to be a primitive'); // ✓
|
|
expect({}, 'to be a primitive'); // ✗
|
|
```
|
|
|
|
---
|
|
|
|
## Numeric Assertions
|
|
|
|
### `{unknown} to be infinite`
|
|
|
|
**Aliases:** None
|
|
|
|
**Checks:** Value is Infinity or -Infinity
|
|
|
|
```typescript
|
|
expect(Infinity, 'to be infinite'); // ✓
|
|
expect(-Infinity, 'to be infinite'); // ✓
|
|
expect(42, 'to be infinite'); // ✗
|
|
```
|
|
|
|
### `{unknown} to be Infinity`
|
|
|
|
**Aliases:** None
|
|
|
|
**Checks:** Value is exactly positive Infinity
|
|
|
|
```typescript
|
|
expect(Infinity, 'to be Infinity'); // ✓
|
|
expect(-Infinity, 'to be Infinity'); // ✗
|
|
```
|
|
|
|
### `{unknown} to be -Infinity`
|
|
|
|
**Aliases:** None
|
|
|
|
**Checks:** Value is exactly negative Infinity
|
|
|
|
```typescript
|
|
expect(-Infinity, 'to be -Infinity'); // ✓
|
|
expect(Infinity, 'to be -Infinity'); // ✗
|
|
```
|
|
|
|
### `{unknown} to be positive`
|
|
|
|
**Aliases:** `to be a positive number`
|
|
|
|
**Checks:** Value is a positive finite number (excludes 0)
|
|
|
|
```typescript
|
|
expect(42, 'to be positive'); // ✓
|
|
expect(0, 'to be positive'); // ✗ (zero is not positive)
|
|
expect(-5, 'to be positive'); // ✗
|
|
```
|
|
|
|
### `{unknown} to be a positive integer`
|
|
|
|
**Aliases:** `to be a positive int`
|
|
|
|
**Checks:** Value is a positive integer (excludes 0)
|
|
|
|
```typescript
|
|
expect(42, 'to be a positive integer'); // ✓
|
|
expect(3.14, 'to be a positive integer'); // ✗ (not an integer)
|
|
expect(0, 'to be a positive integer'); // ✗ (zero excluded)
|
|
```
|
|
|
|
### `{unknown} to be negative`
|
|
|
|
**Aliases:** `to be a negative number`
|
|
|
|
**Checks:** Value is a negative finite number (excludes 0)
|
|
|
|
```typescript
|
|
expect(-42, 'to be negative'); // ✓
|
|
expect(0, 'to be negative'); // ✗
|
|
expect(5, 'to be negative'); // ✗
|
|
```
|
|
|
|
### `{unknown} to be a negative integer`
|
|
|
|
**Aliases:** `to be a negative int`
|
|
|
|
**Checks:** Value is a negative integer (excludes 0)
|
|
|
|
```typescript
|
|
expect(-42, 'to be a negative integer'); // ✓
|
|
expect(-3.14, 'to be a negative integer'); // ✗ (not an integer)
|
|
```
|
|
|
|
### `{unknown} to be NaN`
|
|
|
|
**Aliases:** None
|
|
|
|
**Checks:** Value is NaN
|
|
|
|
```typescript
|
|
expect(NaN, 'to be NaN'); // ✓
|
|
expect(42, 'to be NaN'); // ✗
|
|
```
|
|
|
|
### `{unknown} to be an integer`
|
|
|
|
**Aliases:** `to be a safe integer`, `to be an int`, `to be a safe int`
|
|
|
|
**Checks:** Value is a safe integer
|
|
|
|
```typescript
|
|
expect(42, 'to be an integer'); // ✓
|
|
expect(3.14, 'to be an integer'); // ✗
|
|
```
|
|
|
|
### `{unknown} to be greater than {number}`
|
|
|
|
**Aliases:** None
|
|
|
|
**Checks:** Value is strictly greater than the parameter
|
|
|
|
```typescript
|
|
expect(10, 'to be greater than', 5); // ✓
|
|
expect(5, 'to be greater than', 10); // ✗
|
|
```
|
|
|
|
### `{unknown} to be less than {number}`
|
|
|
|
**Aliases:** `to be lt`
|
|
|
|
**Checks:** Value is strictly less than the parameter
|
|
|
|
```typescript
|
|
expect(5, 'to be less than', 10); // ✓
|
|
expect(10, 'to be less than', 5); // ✗
|
|
```
|
|
|
|
### `{unknown} to be greater than or equal to {number}`
|
|
|
|
**Aliases:** `to be at least`, `to be gte`
|
|
|
|
**Checks:** Value is greater than or equal to the parameter
|
|
|
|
```typescript
|
|
expect(10, 'to be at least', 10); // ✓
|
|
expect(15, 'to be at least', 10); // ✓
|
|
expect(5, 'to be at least', 10); // ✗
|
|
```
|
|
|
|
### `{unknown} to be less than or equal to {number}`
|
|
|
|
**Aliases:** `to be at most`, `to be lte`
|
|
|
|
**Checks:** Value is less than or equal to the parameter
|
|
|
|
```typescript
|
|
expect(10, 'to be at most', 10); // ✓
|
|
expect(5, 'to be at most', 10); // ✓
|
|
expect(15, 'to be at most', 10); // ✗
|
|
```
|
|
|
|
### `{number} to be between {number} and {number}`
|
|
|
|
**Aliases:** `to be within`
|
|
|
|
**Checks:** Value is between two numbers (inclusive)
|
|
|
|
```typescript
|
|
expect(5, 'to be between', 1, 10); // ✓
|
|
expect(15, 'to be between', 1, 10); // ✗
|
|
```
|
|
|
|
### `{number} to be close to {number} within {number}`
|
|
|
|
**Aliases:** None
|
|
|
|
**Checks:** Value is within tolerance of target
|
|
|
|
**Parameters:** (subject, target, tolerance)
|
|
|
|
```typescript
|
|
expect(1.0, 'to be close to', 1.1, 0.2); // ✓ (diff = 0.1)
|
|
expect(3.14159, 'to be close to', 3.14, 0.01); // ✓
|
|
expect(1.0, 'to be close to', 2.0, 0.5); // ✗ (diff = 1.0)
|
|
```
|
|
|
|
---
|
|
|
|
## String & Pattern Assertions
|
|
|
|
### `{string} to begin with {string}`
|
|
|
|
**Aliases:** `to start with`
|
|
|
|
**Checks:** String starts with the specified prefix
|
|
|
|
```typescript
|
|
expect('hello world', 'to begin with', 'hello'); // ✓
|
|
expect('hello world', 'to start with', 'world'); // ✗
|
|
```
|
|
|
|
### `{string} to end with {string}`
|
|
|
|
**Aliases:** None
|
|
|
|
**Checks:** String ends with the specified suffix
|
|
|
|
```typescript
|
|
expect('hello world', 'to end with', 'world'); // ✓
|
|
expect('hello world', 'to end with', 'hello'); // ✗
|
|
```
|
|
|
|
### `{string} to match {RegExp}`
|
|
|
|
**Aliases:** None
|
|
|
|
**Checks:** String matches the regular expression
|
|
|
|
```typescript
|
|
expect('hello123', 'to match', /\d+/); // ✓
|
|
expect('JavaScript', 'to match', /^Java/); // ✓
|
|
expect('hello', 'to match', /\d+/); // ✗
|
|
```
|
|
|
|
### `{string} to be empty`
|
|
|
|
**Aliases:** None
|
|
|
|
**Checks:** String has zero length
|
|
|
|
```typescript
|
|
expect('', 'to be empty'); // ✓
|
|
expect('hello', 'to be empty'); // ✗
|
|
```
|
|
|
|
### `{string} to be non-empty`
|
|
|
|
**Aliases:** None
|
|
|
|
**Checks:** String has at least one character
|
|
|
|
```typescript
|
|
expect('hello', 'to be non-empty'); // ✓
|
|
expect(' ', 'to be non-empty'); // ✓ (whitespace counts)
|
|
expect('', 'to be non-empty'); // ✗
|
|
```
|
|
|
|
### `{string} includes {string}`
|
|
|
|
**Aliases:** `contains`
|
|
|
|
**Checks:** String contains the substring
|
|
|
|
```typescript
|
|
expect('hello world', 'includes', 'world'); // ✓
|
|
expect('hello', 'includes', 'world'); // ✗
|
|
```
|
|
|
|
### `{unknown} to be a RegExp`
|
|
|
|
**Aliases:** `to be a regex`, `to be a regexp`
|
|
|
|
**Checks:** Value is a RegExp object
|
|
|
|
```typescript
|
|
expect(/hello/, 'to be a RegExp'); // ✓
|
|
expect(new RegExp('world'), 'to be a regex'); // ✓
|
|
expect('hello', 'to be a RegExp'); // ✗
|
|
```
|
|
|
|
---
|
|
|
|
## Collection Assertions
|
|
|
|
### `{unknown} to be an array`
|
|
|
|
**Aliases:** `to be array`
|
|
|
|
**Checks:** Value is an Array
|
|
|
|
```typescript
|
|
expect([], 'to be an array'); // ✓
|
|
expect([1, 2, 3], 'to be an array'); // ✓
|
|
expect('hello', 'to be an array'); // ✗
|
|
```
|
|
|
|
### `{arraylike} to be empty`
|
|
|
|
**Aliases:** None
|
|
|
|
**Checks:** Array/string/collection has zero length
|
|
|
|
```typescript
|
|
expect([], 'to be empty'); // ✓
|
|
expect([1, 2, 3], 'to be empty'); // ✗
|
|
```
|
|
|
|
### `{array} to have length {nonnegative-integer}`
|
|
|
|
**Aliases:** `to have size`
|
|
|
|
**Checks:** Array/string has exact length
|
|
|
|
```typescript
|
|
expect([1, 2, 3], 'to have length', 3); // ✓
|
|
expect('hello', 'to have length', 5); // ✓
|
|
expect([1, 2], 'to have length', 3); // ✗
|
|
```
|
|
|
|
### `{arraylike} to be non-empty`
|
|
|
|
**Aliases:** None
|
|
|
|
**Checks:** Array/string has at least one element
|
|
|
|
```typescript
|
|
expect([1, 2, 3], 'to be non-empty'); // ✓
|
|
expect([], 'to be non-empty'); // ✗
|
|
```
|
|
|
|
### `{array} to contain {any}`
|
|
|
|
**Aliases:** `to include`
|
|
|
|
**Checks:** Array contains the value
|
|
|
|
```typescript
|
|
expect([1, 2, 3], 'to contain', 2); // ✓
|
|
expect(['a', 'b'], 'to include', 'c'); // ✗
|
|
```
|
|
|
|
### `{Map} to contain {any}`
|
|
|
|
**Aliases:** `to include`
|
|
|
|
**Checks:** Map contains the key
|
|
|
|
```typescript
|
|
const map = new Map([['key1', 'value1']]);
|
|
expect(map, 'to contain', 'key1'); // ✓
|
|
expect(map, 'to contain', 'key2'); // ✗
|
|
```
|
|
|
|
### `{Map} to have size {nonnegative-integer}`
|
|
|
|
**Aliases:** None
|
|
|
|
**Checks:** Map has exact size
|
|
|
|
```typescript
|
|
const map = new Map([
|
|
['a', 1],
|
|
['b', 2],
|
|
]);
|
|
expect(map, 'to have size', 2); // ✓
|
|
expect(map, 'to have size', 3); // ✗
|
|
```
|
|
|
|
### `{Map} to be empty`
|
|
|
|
**Aliases:** None
|
|
|
|
**Checks:** Map has no entries
|
|
|
|
```typescript
|
|
expect(new Map(), 'to be empty'); // ✓
|
|
expect(new Map([['a', 1]]), 'to be empty'); // ✗
|
|
```
|
|
|
|
### `{Set} to contain {any}`
|
|
|
|
**Aliases:** `to include`
|
|
|
|
**Checks:** Set contains the value
|
|
|
|
```typescript
|
|
const set = new Set([1, 2, 3]);
|
|
expect(set, 'to contain', 2); // ✓
|
|
expect(set, 'to contain', 5); // ✗
|
|
```
|
|
|
|
### `{Set} to have size {nonnegative-integer}`
|
|
|
|
**Aliases:** None
|
|
|
|
**Checks:** Set has exact size
|
|
|
|
```typescript
|
|
const set = new Set([1, 2, 3]);
|
|
expect(set, 'to have size', 3); // ✓
|
|
expect(set, 'to have size', 5); // ✗
|
|
```
|
|
|
|
### `{Set} to be empty`
|
|
|
|
**Aliases:** None
|
|
|
|
**Checks:** Set has no elements
|
|
|
|
```typescript
|
|
expect(new Set(), 'to be empty'); // ✓
|
|
expect(new Set([1]), 'to be empty'); // ✗
|
|
```
|
|
|
|
### `{unknown} to be a Set`
|
|
|
|
**Aliases:** None
|
|
|
|
**Checks:** Value is a Set
|
|
|
|
```typescript
|
|
expect(new Set(), 'to be a Set'); // ✓
|
|
expect([1, 2, 3], 'to be a Set'); // ✗
|
|
```
|
|
|
|
### `{WeakMap} to contain {object | symbol}`
|
|
|
|
**Aliases:** `to include`
|
|
|
|
**Checks:** WeakMap contains the key
|
|
|
|
```typescript
|
|
const obj = {};
|
|
const wm = new WeakMap([[obj, 'value']]);
|
|
expect(wm, 'to contain', obj); // ✓
|
|
```
|
|
|
|
### `{unknown} to be a WeakMap`
|
|
|
|
**Aliases:** None
|
|
|
|
**Checks:** Value is a WeakMap
|
|
|
|
```typescript
|
|
expect(new WeakMap(), 'to be a WeakMap'); // ✓
|
|
expect(new Map(), 'to be a WeakMap'); // ✗
|
|
```
|
|
|
|
### `{WeakSet} to contain {object | symbol}`
|
|
|
|
**Aliases:** `to include`
|
|
|
|
**Checks:** WeakSet contains the value
|
|
|
|
```typescript
|
|
const obj = {};
|
|
const ws = new WeakSet([obj]);
|
|
expect(ws, 'to contain', obj); // ✓
|
|
```
|
|
|
|
### `{unknown} to be a WeakSet`
|
|
|
|
**Aliases:** None
|
|
|
|
**Checks:** Value is a WeakSet
|
|
|
|
```typescript
|
|
expect(new WeakSet(), 'to be a WeakSet'); // ✓
|
|
expect(new Set(), 'to be a WeakSet'); // ✗
|
|
```
|
|
|
|
---
|
|
|
|
## Object Assertions
|
|
|
|
### `{unknown} to be an object`
|
|
|
|
**Aliases:** None
|
|
|
|
**Checks:** Value is an object (includes arrays, excludes null)
|
|
|
|
```typescript
|
|
expect({}, 'to be an object'); // ✓
|
|
expect([], 'to be an object'); // ✓ (arrays are objects)
|
|
expect(new Date(), 'to be an object'); // ✓
|
|
expect(null, 'to be an object'); // ✗
|
|
expect('hello', 'to be an object'); // ✗
|
|
```
|
|
|
|
**Note:** `to be an object` already implies non-null. No need for redundant null checks.
|
|
|
|
### `{unknown} to be a record`
|
|
|
|
**Aliases:** `to be a plain object`
|
|
|
|
**Checks:** Value is a plain object (excludes arrays, dates, etc.)
|
|
|
|
```typescript
|
|
expect({}, 'to be a record'); // ✓
|
|
expect({ a: 1 }, 'to be a plain object'); // ✓
|
|
expect([], 'to be a record'); // ✗
|
|
expect(new Date(), 'to be a record'); // ✗
|
|
```
|
|
|
|
### `{object} to be empty`
|
|
|
|
**Aliases:** None
|
|
|
|
**Checks:** Object has no own enumerable properties
|
|
|
|
```typescript
|
|
expect({}, 'to be empty'); // ✓
|
|
expect({ a: 1 }, 'to be empty'); // ✗
|
|
```
|
|
|
|
### `{object} to have keys {array}`
|
|
|
|
**Aliases:** `to have properties`, `to have props`, `to include keys`, `to include properties`, `to include props`, `to contain keys`, `to contain properties`, `to contain props`
|
|
|
|
**Checks:** Object has all specified keys
|
|
|
|
```typescript
|
|
expect({ a: 1, b: 2 }, 'to have keys', ['a', 'b']); // ✓
|
|
expect({ a: 1 }, 'to have keys', ['a', 'b']); // ✗ (missing 'b')
|
|
```
|
|
|
|
### `{object} to have key {keypath}`
|
|
|
|
**Aliases:** `to have property`, `to have prop`, `to include key`, `to include property`, `to include prop`, `to contain key`, `to contain property`, `to contain prop`
|
|
|
|
**Checks:** Object has property at keypath (supports dot/bracket notation)
|
|
|
|
**Keypath formats:**
|
|
|
|
- Dot notation: `'prop.nested'`
|
|
- Bracket notation: `'arr[0]'`, `'obj["key"]'`
|
|
- Mixed: `'data.items[1].name'`
|
|
|
|
```typescript
|
|
const obj = {
|
|
foo: { bar: [{ baz: 'value' }] },
|
|
items: [{ id: 1 }, { id: 2 }],
|
|
};
|
|
|
|
expect(obj, 'to have property', 'foo.bar'); // ✓
|
|
expect(obj, 'to have key', 'foo.bar[0].baz'); // ✓
|
|
expect(obj, 'to have property', 'items[1].id'); // ✓
|
|
expect(obj, 'to have key', 'nonexistent.path'); // ✗
|
|
```
|
|
|
|
### `{object} to have exact key {string | number | symbol}`
|
|
|
|
**Aliases:** `to have exact property`, `to have exact prop`
|
|
|
|
**Checks:** Object has direct property (no keypath traversal)
|
|
|
|
```typescript
|
|
const sym = Symbol('test');
|
|
const obj = {
|
|
'key.with.dots': 'value', // literal key, not nested
|
|
'key[with]brackets': 'value', // literal key, not array
|
|
[sym]: 'symbol value',
|
|
};
|
|
|
|
expect(obj, 'to have exact key', 'key.with.dots'); // ✓ (literal key)
|
|
expect(obj, 'to have exact property', 'key[with]brackets'); // ✓
|
|
expect(obj, 'to have exact key', sym); // ✓
|
|
```
|
|
|
|
### `{object} to satisfy {any}`
|
|
|
|
**Aliases:** `to be like`
|
|
|
|
**Checks:** Object contains at least the specified properties (partial match)
|
|
|
|
**Special features:**
|
|
|
|
- RegExp values test corresponding property as string
|
|
- `expect.it()` embeds assertions
|
|
- Ignores extra properties
|
|
|
|
```typescript
|
|
expect({ a: 1, b: 2, c: 3 }, 'to satisfy', { a: 1, b: 2 }); // ✓
|
|
|
|
// Using RegExp
|
|
expect({ email: 'user@example.com', phone: '+1-555-0123' }, 'to satisfy', {
|
|
email: /^user@/,
|
|
phone: /^\+1-555/,
|
|
}); // ✓
|
|
|
|
// Using expect.it()
|
|
expect({ name: 'John', age: 30 }, 'to satisfy', {
|
|
name: expect.it('to be a string'),
|
|
age: expect.it('to be greater than', 18),
|
|
}); // ✓
|
|
```
|
|
|
|
### `{object} to have a null prototype`
|
|
|
|
**Aliases:** `to be a dictionary`
|
|
|
|
**Checks:** Object was created with Object.create(null)
|
|
|
|
```typescript
|
|
const obj = Object.create(null);
|
|
expect(obj, 'to have a null prototype'); // ✓
|
|
expect({}, 'to have a null prototype'); // ✗
|
|
```
|
|
|
|
### `{string | number | symbol} to be an enumerable property of {non-null}`
|
|
|
|
**Aliases:** `{non-null} to have enumerable property {string | number | symbol}`
|
|
|
|
**Checks:** Property exists and is enumerable
|
|
|
|
```typescript
|
|
const obj = { a: 1, b: 2 };
|
|
expect('a', 'to be an enumerable property of', obj); // ✓
|
|
|
|
Object.defineProperty(obj, 'c', { value: 3, enumerable: false });
|
|
expect('c', 'to be an enumerable property of', obj); // ✗
|
|
```
|
|
|
|
### `{unknown} to be sealed`
|
|
|
|
**Aliases:** None
|
|
|
|
**Checks:** Object is sealed (Object.seal())
|
|
|
|
```typescript
|
|
const obj = { a: 1 };
|
|
Object.seal(obj);
|
|
expect(obj, 'to be sealed'); // ✓
|
|
expect({}, 'to be sealed'); // ✗
|
|
```
|
|
|
|
### `{unknown} to be frozen`
|
|
|
|
**Aliases:** None
|
|
|
|
**Checks:** Object is frozen (Object.freeze())
|
|
|
|
```typescript
|
|
const obj = { a: 1 };
|
|
Object.freeze(obj);
|
|
expect(obj, 'to be frozen'); // ✓
|
|
expect({}, 'to be frozen'); // ✗
|
|
```
|
|
|
|
### `{unknown} to be extensible`
|
|
|
|
**Aliases:** None
|
|
|
|
**Checks:** New properties can be added to object
|
|
|
|
```typescript
|
|
expect({}, 'to be extensible'); // ✓
|
|
|
|
const obj = {};
|
|
Object.preventExtensions(obj);
|
|
expect(obj, 'to be extensible'); // ✗
|
|
```
|
|
|
|
---
|
|
|
|
## Function Assertions
|
|
|
|
### `{unknown} to be a function`
|
|
|
|
**Aliases:** None
|
|
|
|
**Checks:** Value is a function
|
|
|
|
```typescript
|
|
expect(() => {}, 'to be a function'); // ✓
|
|
expect(Math.max, 'to be a function'); // ✓
|
|
expect('hello', 'to be a function'); // ✗
|
|
```
|
|
|
|
### `{unknown} to be an async function`
|
|
|
|
**Aliases:** None
|
|
|
|
**Checks:** Value is an async function
|
|
|
|
```typescript
|
|
expect(async () => {}, 'to be an async function'); // ✓
|
|
expect(() => {}, 'to be an async function'); // ✗
|
|
```
|
|
|
|
### `{unknown} to be a constructor`
|
|
|
|
**Aliases:** `to be constructible`, `to be a class`
|
|
|
|
**Checks:** Function can be called with 'new'
|
|
|
|
**Warning:** Cannot reliably distinguish classes from regular functions
|
|
|
|
```typescript
|
|
class MyClass {}
|
|
expect(MyClass, 'to be a class'); // ✓
|
|
expect(Date, 'to be a constructor'); // ✓
|
|
```
|
|
|
|
### `{function} to have arity {nonnegative-integer}`
|
|
|
|
**Aliases:** None
|
|
|
|
**Checks:** Function has exact number of parameters
|
|
|
|
```typescript
|
|
function add(a, b) {
|
|
return a + b;
|
|
}
|
|
expect(add, 'to have arity', 2); // ✓
|
|
expect(add, 'to have arity', 3); // ✗
|
|
```
|
|
|
|
### `{function} to throw [{any}]`
|
|
|
|
**Aliases:** `to throw an error satisfying`
|
|
|
|
**Checks:** Function throws when called
|
|
|
|
**Optional parameter:** Uses "to satisfy" semantics (string/RegExp/object matching)
|
|
|
|
```typescript
|
|
expect(() => {
|
|
throw new Error('oops');
|
|
}, 'to throw'); // ✓
|
|
|
|
// String matching
|
|
expect(
|
|
() => {
|
|
throw new Error('Specific error');
|
|
},
|
|
'to throw',
|
|
'Specific error',
|
|
); // ✓
|
|
|
|
// RegExp matching
|
|
expect(
|
|
() => {
|
|
throw new Error('Error: failed');
|
|
},
|
|
'to throw',
|
|
/failed/,
|
|
); // ✓
|
|
|
|
// Object matching
|
|
expect(
|
|
() => {
|
|
throw new Error('Custom error');
|
|
},
|
|
'to throw',
|
|
{ message: 'Custom error' },
|
|
); // ✓
|
|
```
|
|
|
|
### `{function} to throw a {constructor}`
|
|
|
|
**Aliases:** `to throw an`
|
|
|
|
**Checks:** Function throws specific error type
|
|
|
|
```typescript
|
|
expect(
|
|
() => {
|
|
throw new TypeError('type error');
|
|
},
|
|
'to throw a',
|
|
TypeError,
|
|
); // ✓
|
|
|
|
expect(
|
|
() => {
|
|
throw new TypeError('type error');
|
|
},
|
|
'to throw a',
|
|
RangeError,
|
|
); // ✗
|
|
```
|
|
|
|
### `{function} to throw a {constructor} satisfying {any}`
|
|
|
|
**Aliases:** `to throw an {constructor} satisfying`
|
|
|
|
**Checks:** Function throws specific error type matching pattern
|
|
|
|
```typescript
|
|
expect(
|
|
() => {
|
|
const err = new Error('Custom error');
|
|
err.code = 'CUSTOM_CODE';
|
|
throw err;
|
|
},
|
|
'to throw a',
|
|
Error,
|
|
'satisfying',
|
|
{ code: 'CUSTOM_CODE' },
|
|
); // ✓
|
|
```
|
|
|
|
---
|
|
|
|
## Equality & Comparison Assertions
|
|
|
|
### `{unknown} to equal {any}`
|
|
|
|
**Aliases:** `to be`, `equals`, `is`, `is equal to`, `to strictly equal`, `is strictly equal to`
|
|
|
|
**Checks:** Values are strictly equal (===)
|
|
|
|
```typescript
|
|
expect(42, 'to be', 42); // ✓
|
|
expect('hello', 'to equal', 'hello'); // ✓
|
|
expect(42, 'is', '42'); // ✗ (different types)
|
|
expect({}, 'to equal', {}); // ✗ (different references)
|
|
```
|
|
|
|
### `{unknown} to deep equal {any}`
|
|
|
|
**Aliases:** `to deeply equal`
|
|
|
|
**Checks:** Values are deeply equal (recursive comparison)
|
|
|
|
```typescript
|
|
expect({ a: 1, b: 2 }, 'to deep equal', { a: 1, b: 2 }); // ✓
|
|
expect([1, 2, 3], 'to deeply equal', [1, 2, 3]); // ✓
|
|
expect({ a: 1 }, 'to deep equal', { a: 1, b: 2 }); // ✗
|
|
```
|
|
|
|
### `{unknown} to be one of {array}`
|
|
|
|
**Aliases:** None
|
|
|
|
**Checks:** Value is in the array
|
|
|
|
```typescript
|
|
expect(2, 'to be one of', [1, 2, 3]); // ✓
|
|
expect('blue', 'to be one of', ['red', 'green', 'blue']); // ✓
|
|
expect(5, 'to be one of', [1, 2, 3]); // ✗
|
|
```
|
|
|
|
### `{unknown} to be an instance of {constructor}`
|
|
|
|
**Aliases:** `to be a`, `to be an`
|
|
|
|
**Checks:** Value is instance of constructor
|
|
|
|
```typescript
|
|
expect(new Date(), 'to be an instance of', Date); // ✓
|
|
expect([], 'to be a', Array); // ✓
|
|
expect('hello', 'to be an instance of', Number); // ✗
|
|
```
|
|
|
|
### `{unknown} to be a {intrinsic-type}`
|
|
|
|
**Aliases:** `to be an`, `to have type`
|
|
|
|
**Checks:** Value is of intrinsic type (case-insensitive)
|
|
|
|
**Intrinsic types:** string, number, boolean, bigint, symbol, undefined, object, function, null, Map, Set, WeakMap, WeakSet, WeakRef, Date, Error, Array, RegExp, Promise
|
|
|
|
```typescript
|
|
expect(new Date(), 'to be a', 'Date'); // ✓
|
|
expect([], 'to be an', 'Array'); // ✓
|
|
expect(1, 'to be a', 'number'); // ✓
|
|
```
|
|
|
|
---
|
|
|
|
## Error Assertions
|
|
|
|
### `{unknown} to be an Error`
|
|
|
|
**Aliases:** `to be a Error`
|
|
|
|
**Checks:** Value is an Error instance
|
|
|
|
```typescript
|
|
expect(new Error(), 'to be an Error'); // ✓
|
|
expect(new TypeError(), 'to be an Error'); // ✓
|
|
expect('error message', 'to be an Error'); // ✗
|
|
```
|
|
|
|
### `{Error} to have message {string}`
|
|
|
|
**Aliases:** None
|
|
|
|
**Checks:** Error has exact message
|
|
|
|
```typescript
|
|
const error = new Error('Something went wrong');
|
|
expect(error, 'to have message', 'Something went wrong'); // ✓
|
|
expect(error, 'to have message', 'Different message'); // ✗
|
|
```
|
|
|
|
### `{Error} to have message matching {RegExp}`
|
|
|
|
**Aliases:** None
|
|
|
|
**Checks:** Error message matches pattern
|
|
|
|
```typescript
|
|
const error = new Error('File not found: /path/to/file.txt');
|
|
expect(error, 'to have message matching', /File not found/); // ✓
|
|
expect(error, 'to have message matching', /\.txt$/); // ✓
|
|
```
|
|
|
|
---
|
|
|
|
## Date & Time Assertions
|
|
|
|
### `{unknown} to be a Date`
|
|
|
|
**Aliases:** `to be a date`
|
|
|
|
**Checks:** Value is a Date object
|
|
|
|
```typescript
|
|
expect(new Date(), 'to be a Date'); // ✓
|
|
expect('2024-01-01', 'to be a Date'); // ✗
|
|
expect(1704067200000, 'to be a Date'); // ✗ (timestamp)
|
|
```
|
|
|
|
### `{unknown} to be a valid date`
|
|
|
|
**Aliases:** `to be date-like`
|
|
|
|
**Checks:** Value can be converted to a valid date
|
|
|
|
```typescript
|
|
expect(new Date(), 'to be a valid date'); // ✓
|
|
expect('2024-01-01', 'to be date-like'); // ✓
|
|
expect(1704067200000, 'to be a valid date'); // ✓ (timestamp)
|
|
expect('invalid-date', 'to be a valid date'); // ✗
|
|
```
|
|
|
|
### `{date-like} to be before {date-like}`
|
|
|
|
**Aliases:** None
|
|
|
|
**Checks:** Date is before another date
|
|
|
|
```typescript
|
|
expect(new Date('2022-01-01'), 'to be before', new Date('2023-01-01')); // ✓
|
|
expect('2022-01-01', 'to be before', '2023-01-01'); // ✓
|
|
```
|
|
|
|
### `{date-like} to be after {date-like}`
|
|
|
|
**Aliases:** None
|
|
|
|
**Checks:** Date is after another date
|
|
|
|
```typescript
|
|
expect(new Date('2023-01-01'), 'to be after', new Date('2022-01-01')); // ✓
|
|
expect(Date.now(), 'to be after', new Date('2020-01-01')); // ✓
|
|
```
|
|
|
|
### `{date-like} to be between {date-like} and {date-like}`
|
|
|
|
**Aliases:** None
|
|
|
|
**Checks:** Date is between two dates (inclusive)
|
|
|
|
```typescript
|
|
expect(
|
|
new Date('2022-06-01'),
|
|
'to be between',
|
|
new Date('2022-01-01'),
|
|
new Date('2022-12-31'),
|
|
); // ✓
|
|
```
|
|
|
|
### `{date-like} to be the same date as {date-like}`
|
|
|
|
**Aliases:** None
|
|
|
|
**Checks:** Dates represent the same calendar day (ignores time)
|
|
|
|
```typescript
|
|
expect(
|
|
new Date('2023-01-01T10:00:00'),
|
|
'to be the same date as',
|
|
new Date('2023-01-01T15:30:00'),
|
|
); // ✓ (same date, different times)
|
|
```
|
|
|
|
### `{date-like} to equal {date-like} within {duration}`
|
|
|
|
**Aliases:** None
|
|
|
|
**Checks:** Dates are within specified duration
|
|
|
|
**Duration formats:** "100 milliseconds", "30 seconds", "5 minutes", "2 hours", "7 days"
|
|
|
|
```typescript
|
|
const date1 = new Date('2023-01-01T10:00:00.000Z');
|
|
const date2 = new Date('2023-01-01T10:00:00.500Z');
|
|
expect(date1, 'to equal', date2, 'within', '1 second'); // ✓ (500ms diff)
|
|
```
|
|
|
|
### `{unknown} to be a weekend`
|
|
|
|
**Aliases:** None
|
|
|
|
**Checks:** Date is Saturday or Sunday (in UTC)
|
|
|
|
```typescript
|
|
expect(new Date('2023-01-07'), 'to be a weekend'); // ✓ (Saturday)
|
|
expect(new Date('2023-01-09'), 'to be a weekend'); // ✗ (Monday)
|
|
```
|
|
|
|
### `{unknown} to be a weekday`
|
|
|
|
**Aliases:** None
|
|
|
|
**Checks:** Date is Monday-Friday (in UTC)
|
|
|
|
```typescript
|
|
expect(new Date('2023-01-09'), 'to be a weekday'); // ✓ (Monday)
|
|
expect(new Date('2023-01-07'), 'to be a weekday'); // ✗ (Saturday)
|
|
```
|
|
|
|
---
|
|
|
|
## Promise Assertions
|
|
|
|
**Note:** All promise assertions require `expectAsync()` instead of `expect()`
|
|
|
|
### `{Promise} to resolve`
|
|
|
|
**Aliases:** `to fulfill`
|
|
|
|
**Checks:** Promise resolves successfully
|
|
|
|
```typescript
|
|
await expectAsync(Promise.resolve(42), 'to resolve'); // ✓
|
|
await expectAsync(async () => 'result', 'to resolve'); // ✓
|
|
await expectAsync(Promise.reject('error'), 'to resolve'); // ✗
|
|
```
|
|
|
|
### `{Promise} to reject`
|
|
|
|
**Aliases:** None
|
|
|
|
**Checks:** Promise rejects
|
|
|
|
```typescript
|
|
await expectAsync(Promise.reject('error'), 'to reject'); // ✓
|
|
await expectAsync(async () => {
|
|
throw new Error('failed');
|
|
}, 'to reject'); // ✓
|
|
await expectAsync(Promise.resolve(42), 'to reject'); // ✗
|
|
```
|
|
|
|
### `{Promise} to reject with a {constructor}`
|
|
|
|
**Aliases:** `to reject with an`
|
|
|
|
**Checks:** Promise rejects with specific error type
|
|
|
|
```typescript
|
|
await expectAsync(
|
|
Promise.reject(new TypeError('Type error')),
|
|
'to reject with a',
|
|
TypeError,
|
|
); // ✓
|
|
```
|
|
|
|
### `{Promise} to reject with error satisfying {any}`
|
|
|
|
**Aliases:** None
|
|
|
|
**Checks:** Promise rejection matches pattern (string/RegExp/object)
|
|
|
|
```typescript
|
|
// String matching
|
|
await expectAsync(
|
|
Promise.reject(new Error('Specific error')),
|
|
'to reject with',
|
|
'Specific error',
|
|
); // ✓
|
|
|
|
// RegExp matching
|
|
await expectAsync(
|
|
Promise.reject(new Error('Error: Something failed')),
|
|
'to reject with',
|
|
/Something failed/,
|
|
); // ✓
|
|
|
|
// Object matching
|
|
await expectAsync(
|
|
Promise.reject({ message: 'Custom error', code: 500 }),
|
|
'to reject with',
|
|
{ message: 'Custom error' },
|
|
); // ✓
|
|
```
|
|
|
|
### `{Promise} to resolve with value satisfying {any}`
|
|
|
|
**Aliases:** `to fulfill with value satisfying`
|
|
|
|
**Checks:** Promise resolves to value matching pattern
|
|
|
|
```typescript
|
|
// String matching
|
|
await expectAsync(
|
|
Promise.resolve('Hello World'),
|
|
'to fulfill with value satisfying',
|
|
'Hello World',
|
|
); // ✓
|
|
|
|
// RegExp matching
|
|
await expectAsync(
|
|
Promise.resolve('Success: Operation completed'),
|
|
'to resolve to value satisfying',
|
|
/Success/,
|
|
); // ✓
|
|
|
|
// Object matching
|
|
await expectAsync(
|
|
Promise.resolve({ status: 'ok', data: [1, 2, 3] }),
|
|
'to fulfill with value satisfying',
|
|
{ status: 'ok' },
|
|
); // ✓
|
|
```
|
|
|
|
---
|
|
|
|
## Other Assertions
|
|
|
|
### `{unknown} to be truthy`
|
|
|
|
**Aliases:** `to exist`, `to be ok`
|
|
|
|
**Checks:** Value is truthy
|
|
|
|
```typescript
|
|
expect(1, 'to be truthy'); // ✓
|
|
expect('hello', 'to be truthy'); // ✓
|
|
expect(true, 'to exist'); // ✓
|
|
expect(0, 'to be truthy'); // ✗
|
|
expect('', 'to exist'); // ✗
|
|
expect(null, 'to be ok'); // ✗
|
|
```
|
|
|
|
### `{unknown} to be falsy`
|
|
|
|
**Aliases:** None
|
|
|
|
**Checks:** Value is falsy
|
|
|
|
```typescript
|
|
expect(0, 'to be falsy'); // ✓
|
|
expect('', 'to be falsy'); // ✓
|
|
expect(false, 'to be falsy'); // ✓
|
|
expect(null, 'to be falsy'); // ✓
|
|
expect(undefined, 'to be falsy'); // ✓
|
|
expect(1, 'to be falsy'); // ✗
|
|
```
|
|
|
|
### `{unknown} to be defined`
|
|
|
|
**Aliases:** None
|
|
|
|
**Checks:** Value is not undefined
|
|
|
|
```typescript
|
|
expect(0, 'to be defined'); // ✓
|
|
expect('', 'to be defined'); // ✓
|
|
expect(null, 'to be defined'); // ✓
|
|
expect(undefined, 'to be defined'); // ✗
|
|
```
|
|
|
|
---
|
|
|
|
## Quick Reference Tables
|
|
|
|
### Type Checking
|
|
|
|
| Phrase | Checks |
|
|
| ------------------ | ----------------------- |
|
|
| `to be a string` | Is a string |
|
|
| `to be a number` | Is a finite number |
|
|
| `to be a boolean` | Is a boolean |
|
|
| `to be a bigint` | Is a BigInt |
|
|
| `to be a symbol` | Is a Symbol |
|
|
| `to be an object` | Is an object (non-null) |
|
|
| `to be a function` | Is a function |
|
|
| `to be an array` | Is an Array |
|
|
| `to be a Date` | Is a Date object |
|
|
| `to be an Error` | Is an Error |
|
|
| `to be null` | Is null |
|
|
| `to be undefined` | Is undefined |
|
|
| `to be defined` | Is not undefined |
|
|
|
|
### Comparisons
|
|
|
|
| Phrase | Checks |
|
|
| ------------------------- | ------------------------ |
|
|
| `to equal`, `to be`, `is` | Strict equality (===) |
|
|
| `to deep equal` | Deep structural equality |
|
|
| `to be greater than` | Numeric > comparison |
|
|
| `to be less than` | Numeric < comparison |
|
|
| `to be between` | Within range (inclusive) |
|
|
| `to be one of` | Value in array |
|
|
|
|
### Collections
|
|
|
|
| Phrase | Checks |
|
|
| ------------------------------------ | ------------------------------ |
|
|
| `to be empty` | Length/size is 0 |
|
|
| `to have length` | Exact length/size |
|
|
| `to contain`, `to include` | Contains value |
|
|
| `to have property`, `to have key` | Has property (keypath support) |
|
|
| `to have properties`, `to have keys` | Has all specified keys |
|
|
|
|
### Object Patterns
|
|
|
|
| Phrase | Checks |
|
|
| ------------ | ---------------------------------------------------- |
|
|
| `to satisfy` | Partial object match with RegExp/expect.it() support |
|
|
| `to be like` | Alias for `to satisfy` |
|
|
|
|
### Promises
|
|
|
|
| Phrase | Requires | Checks |
|
|
| ---------------------------------- | --------------- | -------------------------- |
|
|
| `to resolve` | `expectAsync()` | Promise resolves |
|
|
| `to reject` | `expectAsync()` | Promise rejects |
|
|
| `to reject with` | `expectAsync()` | Rejection matches pattern |
|
|
| `to resolve with value satisfying` | `expectAsync()` | Resolution matches pattern |
|
|
|
|
### Functions
|
|
|
|
| Phrase | Checks |
|
|
| ------------------- | ----------------------------------- |
|
|
| `to throw` | Function throws |
|
|
| `to throw a {Type}` | Function throws specific error type |
|
|
| `to have arity` | Function parameter count |
|