A comprehensive comparison library, for use in test frameworks
—
tcompare provides direct access to comparison classes for advanced usage scenarios. These classes offer performance benefits when making multiple comparisons and allow for custom comparison logic through inheritance.
Format
└── Same
├── Strict
├── Has
│ ├── HasStrict (uses Strict.prototype.test)
│ └── Match
│ └── MatchStrict (fails if a==b && a!==b)
├── MatchOnly (uses Match.prototype.test)
└── MatchOnlyStrict (uses MatchStrict.prototype.test)The foundational class for all formatting and comparison operations.
/**
* Base formatting class for converting values to strings
*/
class Format {
constructor(obj: any, options?: FormatOptions);
/** Generate formatted string representation of the object */
print(): string;
/** Check if the object is an array-like structure */
isArray(): boolean;
/** Get object keys for plain objects */
getPojoKeys(obj: any): string[];
/** Get object entries for plain objects */
getPojoEntries(obj: any): Array<[string, any]>;
}Base comparison class providing deep equivalence with loose matching.
/**
* Base class for all comparison operations - deep equivalence with loose comparison
*/
class Same extends Format {
constructor(obj: any, options: SameOptions);
/** Boolean indicating whether objects match after calling print() */
match: boolean;
/** Perform the comparison test - returns boolean or 'COMPLEX' for nested comparison */
test(): boolean | 'COMPLEX';
/** Generate diff string and set match property */
print(): string;
}
/**
* Options for all comparison operations
*/
interface SameOptions extends FormatOptions {
/** The pattern to test against */
expect: any;
/** Parent comparison object for nested comparisons */
parent?: Same;
/** Key in parent object */
key?: any;
/** Key in expected pattern */
expectKey?: any;
/** Number of lines of context to show in diffs */
diffContext?: number;
}Usage Examples:
import { Same } from "tcompare";
// Direct class usage
const comparison = new Same([1, 2, 3], {
expect: ["1", "2", "3"],
style: "js"
});
const diff = comparison.print();
console.log(comparison.match); // true
console.log(diff); // Empty string when match is trueDeep equality comparison without type coercion, extending Same.
/**
* Deep equality comparison without type coercion
*/
class Strict extends Same {
constructor(obj: any, options: SameOptions);
/** Override test method to enforce strict equality */
test(): boolean | 'COMPLEX';
}Usage Examples:
import { Strict } from "tcompare";
const comparison = new Strict([1, 2, 3], {
expect: ["1", "2", "3"]
});
console.log(comparison.print());
console.log(comparison.match); // false - no type coercionSubset matching - only tests properties present in the expected pattern.
/**
* Subset matching - all pattern fields must exist in object with loose comparison
*/
class Has extends Same {
constructor(obj: any, options: SameOptions);
/** Override to only compare fields present in expected pattern */
getPojoEntries(obj: any): Array<[string, any]>;
/** Check if structure should be treated as array */
isArray(): boolean;
}Usage Examples:
import { Has } from "tcompare";
const comparison = new Has(
{ name: "Alice", age: 25, city: "NYC" },
{ expect: { name: "Alice", age: "25" } }
);
console.log(comparison.match); // true - extra 'city' field ignoredSubset matching with strict comparison for primitives.
/**
* Subset matching with strict comparison for primitives
*/
class HasStrict extends Has {
constructor(obj: any, options: SameOptions);
/** Use strict comparison for primitives, loose for objects */
test(): boolean | 'COMPLEX';
}Most flexible matching strategy with pattern support.
/**
* Flexible pattern matching with support for regex, constructors, and string patterns
*/
class Match extends Has {
constructor(obj: any, options: SameOptions);
/** Extended test method supporting multiple pattern types */
test(): boolean | 'COMPLEX';
}Usage Examples:
import { Match } from "tcompare";
// Pattern matching with regular expressions
const regexMatch = new Match("hello@example.com", {
expect: /@example\.com$/
});
// Constructor pattern matching
const typeMatch = new Match(42, {
expect: Number
});
// String substring matching
const stringMatch = new Match("hello world", {
expect: "world"
});Pattern matching with strict object shape requirements.
/**
* Uses Match test but requires exact object shape (no extra fields)
*/
class MatchOnly extends Same {
constructor(obj: any, options: SameOptions);
/** Use Match.prototype.test for comparison logic */
test(): boolean | 'COMPLEX';
}Pattern matching without type coercion.
/**
* Like Match but fails on loose equality without strict equality
*/
class MatchStrict extends Match {
constructor(obj: any, options: SameOptions);
/** Enhanced test that rejects loose-but-not-strict equality */
test(): boolean | 'COMPLEX';
}Most restrictive matching - strict patterns with exact object shape.
/**
* Uses MatchStrict test but requires exact object shape
*/
class MatchOnlyStrict extends Same {
constructor(obj: any, options: SameOptions);
/** Use MatchStrict.prototype.test for comparison logic */
test(): boolean | 'COMPLEX';
}When making many comparisons with the same options, instantiate classes directly to avoid function call overhead:
import { Same, SameOptions } from "tcompare";
const options: SameOptions = {
expect: { name: String, age: Number },
style: "js",
diffContext: 5
};
// Reuse options object for multiple comparisons
const users = [
{ name: "Alice", age: 25 },
{ name: "Bob", age: 30 },
{ name: "Charlie", age: "invalid" } // Will fail
];
users.forEach(user => {
const comparison = new Same(user, { ...options, expect: options.expect });
const diff = comparison.print();
if (!comparison.match) {
console.log(`Invalid user: ${diff}`);
}
});Extend existing classes to implement custom comparison behavior:
import { Match } from "tcompare";
class EmailMatch extends Match {
test(): boolean | 'COMPLEX' {
const obj = this.object;
const pattern = this.expect;
// Custom email validation logic
if (typeof pattern === 'string' && pattern === 'email') {
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return typeof obj === 'string' && emailRegex.test(obj);
}
// Fall back to parent logic
return super.test();
}
}
// Usage
const emailComparison = new EmailMatch("user@example.com", {
expect: 'email'
});
console.log(emailComparison.match); // true for valid emailClasses expose internal properties for advanced inspection:
import { Same } from "tcompare";
const comparison = new Same({ a: 1, b: 2 }, {
expect: { a: 1, b: 3 }
});
// Access internal object and expected pattern
console.log('Testing:', comparison.object);
console.log('Against:', comparison.expect);
// Generate diff and check match
const diff = comparison.print();
console.log('Match:', comparison.match);
console.log('Diff:', diff);Install with Tessl CLI
npx tessl i tessl/npm-tcompare