Expressive, readable, framework-agnostic BDD-style assertion library for JavaScript testing.
—
Methods for testing object properties, structure, ownership, and collection characteristics.
Test that an object has a property, optionally with a specific value. Changes assertion target to the property value.
/**
* Assert that object has the specified property, optionally with a value
* Changes the assertion target to the property value for chaining
* @param name - Property name to check
* @param value - Optional expected property value
* @returns This assertion for chaining (now targeting the property value)
*/
property(name: string, value?: any): Assertion;Usage:
import should from 'should';
const user = { name: 'john', age: 30, active: true };
// Test property existence
user.should.have.property('name');
user.should.have.property('age');
// Test property with specific value
user.should.have.property('name', 'john');
user.should.have.property('age', 30);
// Chain assertions on the property value
user.should.have.property('name').which.is.a.String();
user.should.have.property('age').which.is.above(18);
// Nested objects
const config = { database: { host: 'localhost', port: 5432 } };
config.should.have.property('database').which.is.an.Object();
config.database.should.have.property('host', 'localhost');Test that an object has multiple properties.
/**
* Assert that object has all specified properties
* @param names - Property names as individual arguments or array
* @returns This assertion for chaining
*/
properties(...names: string[]): Assertion;
properties(names: string[]): Assertion;
properties(props: object): Assertion;Usage:
const user = { name: 'john', age: 30, email: 'john@test.com' };
// Multiple properties as arguments
user.should.have.properties('name', 'age', 'email');
// Properties as array
user.should.have.properties(['name', 'age']);
// Properties with values (as object)
user.should.have.properties({
name: 'john',
age: 30
});
// Partial property checking
const response = { status: 200, data: {}, headers: {} };
response.should.have.properties('status', 'data');Test that an object has its own property (not inherited).
/**
* Assert that object has the property as its own (not inherited)
* @param name - Property name to check
* @param description - Optional error message
* @returns This assertion for chaining
*/
ownProperty(name: string, description?: string): Assertion;
hasOwnProperty(name: string, description?: string): Assertion;Usage:
const obj = { name: 'test' };
obj.should.have.ownProperty('name');
obj.should.have.hasOwnProperty('name');
// Won't match inherited properties
obj.should.not.have.ownProperty('toString'); // toString is inherited
obj.should.not.have.ownProperty('constructor');
// With description
const config = { timeout: 5000 };
config.should.have.ownProperty('timeout', 'Config should have timeout setting');Test that an object has a property with specific descriptor attributes.
/**
* Assert that object has property with matching descriptor attributes
* @param name - Property name to check
* @param descriptor - Expected descriptor properties (enumerable, configurable, etc.)
* @returns This assertion for chaining
*/
propertyWithDescriptor(name: string, descriptor: object): Assertion;Usage:
const obj = {};
Object.defineProperty(obj, 'hidden', {
value: 'secret',
enumerable: false,
configurable: true
});
obj.should.have.propertyWithDescriptor('hidden', {
enumerable: false,
configurable: true
});
// Partial descriptor matching
obj.should.have.propertyWithDescriptor('hidden', {
enumerable: false
});Test the length property of arrays, strings, or array-like objects.
/**
* Assert that object has a length property with the specified value
* @param value - Expected length value
* @param description - Optional error message
* @returns This assertion for chaining
*/
length(value: number, description?: string): Assertion;
lengthOf(value: number, description?: string): Assertion;Usage:
[1, 2, 3].should.have.length(3);
'hello'.should.have.length(5);
''.should.have.length(0);
// Array-like objects
const arrayLike = { 0: 'a', 1: 'b', length: 2 };
arrayLike.should.have.length(2);
// With description
const items = ['a', 'b', 'c'];
items.should.have.lengthOf(3, 'Should have 3 items');
// Chaining with other assertions
const users = [{ name: 'john' }, { name: 'jane' }];
users.should.have.length(2).and.be.an.Array();Test that a collection or string is empty.
/**
* Assert that the value is empty (array, string, object with no own properties)
* @returns This assertion for chaining
*/
empty(): Assertion;Usage:
[].should.be.empty();
''.should.be.empty();
{}.should.be.empty();
// Maps and Sets
new Map().should.be.empty();
new Set().should.be.empty();
// Non-empty examples
[1, 2, 3].should.not.be.empty();
'hello'.should.not.be.empty();
{ name: 'john' }.should.not.be.empty();Test the size property of Maps, Sets, and other collections.
/**
* Assert that object has a size property with the specified value
* @param value - Expected size value
* @returns This assertion for chaining
*/
size(value: number): Assertion;Usage:
const map = new Map([['a', 1], ['b', 2]]);
map.should.have.size(2);
const set = new Set([1, 2, 3, 3]); // Duplicates ignored
set.should.have.size(3);
// Custom objects with size property
const collection = {
items: ['a', 'b', 'c'],
get size() { return this.items.length; }
};
collection.should.have.size(3);Test object keys.
/**
* Assert that object has the specified keys
* @param keys - Expected keys as individual arguments or array
* @returns This assertion for chaining
*/
keys(...keys: any[]): Assertion;
key(key: any): Assertion;Usage:
const obj = { name: 'john', age: 30, active: true };
// All keys (order doesn't matter)
obj.should.have.keys('name', 'age', 'active');
obj.should.have.keys(['name', 'age', 'active']);
// Single key
obj.should.have.key('name');
// Subset of keys (using .any modifier)
obj.should.have.any.keys('name', 'email'); // Has 'name', missing 'email' is ok
// Exact key matching
obj.should.have.only.keys('name', 'age', 'active');
// Array key testing
const arr = ['a', 'b', 'c'];
arr.should.have.keys('0', '1', '2', 'length');Test that an object has a key with a specific value.
/**
* Assert that object has the specified key with the given value
* @param key - Property key to check
* @param value - Expected value for the key
* @returns This assertion for chaining
*/
value(key: any, value: any): Assertion;Usage:
const obj = { name: 'john', age: 30 };
obj.should.have.value('name', 'john');
obj.should.have.value('age', 30);
// Works with arrays
const arr = ['a', 'b', 'c'];
arr.should.have.value(0, 'a');
arr.should.have.value(2, 'c');
// Maps
const map = new Map([['key1', 'value1'], ['key2', 'value2']]);
map.should.have.value('key1', 'value1');Test nested property access using a path.
/**
* Assert that object has a property accessible by the given path
* @param path - Property path as individual arguments or array
* @returns This assertion for chaining (targeting the nested value)
*/
propertyByPath(...path: string[]): Assertion;
propertyByPath(path: string[]): Assertion;Usage:
const obj = {
user: {
profile: {
name: 'john',
settings: {
theme: 'dark'
}
}
}
};
// Path as arguments
obj.should.have.propertyByPath('user', 'profile', 'name');
// Path as array
obj.should.have.propertyByPath(['user', 'profile', 'settings', 'theme']);
// Chain assertions on nested value
obj.should.have.propertyByPath('user', 'profile', 'name').which.equals('john');
// Array indices in path
const data = {
items: [
{ id: 1, name: 'first' },
{ id: 2, name: 'second' }
]
};
data.should.have.propertyByPath('items', 0, 'name').which.equals('first');Property assertions can be chained for complex object validation:
const user = {
id: 123,
profile: {
name: 'john',
email: 'john@test.com',
preferences: {
theme: 'dark',
notifications: true
}
},
roles: ['user', 'admin']
};
// Complex chaining
user.should.have.property('id').which.is.a.Number().and.be.above(0);
user.should.have.property('profile').which.is.an.Object()
.and.have.properties('name', 'email');
user.should.have.property('roles').which.is.an.Array()
.and.have.length(2)
.and.containEql('admin');
// Nested property testing
user.profile.should.have.property('preferences').which.is.an.Object();
user.profile.preferences.should.have.property('theme', 'dark');All property assertions support negation:
const obj = { name: 'john' };
obj.should.not.have.property('age');
obj.should.not.have.properties('email', 'phone');
obj.should.not.have.ownProperty('toString'); // inherited property
obj.should.not.be.empty();
obj.should.not.have.keys('age', 'email');Install with Tessl CLI
npx tessl i tessl/npm-should