Objects
should().objects(x, y) compares two objects deeply, field by field — with four modifiers that shape how fields are compared. The verifier takes both objects up front:
On mismatch the failure names the field and both values: Objects have different 'name': "a" & "b". — for nested fields the path is included ('address.city').
The builder rules
The modifiers — rule, map, ignoring, compareOnly — configure the comparison and must be called before equal():
equal()runs the comparison with whatever was configured before it.rule(field, checker)may be called any number of times — one custom rule per field.compareOnly(...fields)defines an exclusive whitelist — it overrides anything set byignoring().map(fieldA, fieldB)compares a field of the first object against a differently named field of the second.
Ignoring fields
For generated or irrelevant data (timestamps, ids):
Comparing only some fields
The inverse — an exclusive list; everything else is skipped (and it cancels ignoring):
Renaming fields across the two objects
When the sides name the same thing differently:
Custom rules per field
A rule receives both field values and decides equality itself — case-insensitivity, tolerance, anything:
How deep comparison works
Nested objects are compared recursively; the reported field path shows the route (
'user.address.city').Dateproperties are compared by their string representation — same instant passes, different instants fail regardless of accuracy settings (accuracy belongs to Dates).The two objects must have the same number of properties (after
maprenames andignoring/compareOnlyexclusions) — otherwise the check fails withThe objects has different number of properties.Without modifiers, plain
===applies per field — reference equality for nested objects, so deep-equal-but-distinct nested objects need aruleor a comparison of serialized values.
Negation
not inverts equal() itself; the modifiers keep their configuring role. A null/undefined object throws The entry is not defined. even under not (see Concepts).