chai
>=4.0.0 <7.0.0postconditions4functions4last verified2026-06-24coverage score67%Postconditions: what we check
- expect · expect-assertion-failurewarningWhenassertion fails (e.g., expect(value).to.equal(expected) when value !== expected)Throws
AssertionErrorRequired handlingAssertions are EXPECTED to throw in test code, but if used outside tests (e.g., in production validation), callers MUST wrap in try-catch. Without error handling, failed assertions crash the application. Use pattern: try { expect(value).to.equal(expected); } catch (error) { /* handle */ }costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisibleSources[1] - assert · assert-assertion-failurewarningWhenassertion fails (e.g., assert.equal(actual, expected) when actual !== expected)Throws
AssertionErrorRequired handlingAssert-style assertions throw AssertionError on failure. In test code, this is expected. If used in production code, MUST wrap in try-catch to prevent crashes.costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisibleSources[2] - should · should-assertion-failurewarningWhenassertion fails (e.g., value.should.equal(expected) when value !== expected)Throws
AssertionErrorRequired handlingShould-style assertions throw AssertionError on failure. Primarily for test code. If used outside tests, MUST wrap in try-catch.costmediumin prodimmediate exceptionusers seeservice unavailablevisibilityvisibleSources[1] - assert.ifError · assert-iferror-rethrows-valuewarningWhenval is truthy (non-null, non-undefined, non-zero, non-false, non-empty-string). Common usage: assert.ifError(err) in callback-style code where err is an Error. Throws val directly — NOT wrapped in AssertionError.Throws
val (the original value passed — typically an Error, but any truthy value)Required handlingWhen assert.ifError(err) is used in production code (not test code), the caller must catch the rethrown error with the correct type. A catch block that expects AssertionError will NOT catch errors from assert.ifError — it rethrows the original value as-is. Correct pattern for production use: try { assert.ifError(err); // rethrows err if err is truthy } catch (e) { // e is err itself, not an AssertionError console.error('Callback error:', e.message); throw e; } Note: In test code, assert.ifError is typically called at the top of a callback to fail the test immediately if err is present. The rethrow causes test frameworks to mark the test as failed.costmediumin prodsilent failureusers seeservice unavailablevisibilitysilent
Sources
Every postcondition cites at least one of these. Grouped by source type; numbered to match the footnotes above.
Research notes
Curator notes from SOURCES.md captured when the profile was written so you can verify the reasoning, not just the rules.
Sources: chai
Last Updated: 2026-02-27 Package Version: >=4.0.0 <6.0.0 Research Quality: ⭐⭐⭐⭐ (comprehensive)
Official Documentation
- Chai Website: https://www.chaijs.com/
- BDD API: https://www.chaijs.com/api/bdd/ - expect() style
- Assert API: https://www.chaijs.com/api/assert/ - assert.* style
- Should API: https://www.chaijs.com/api/should/ - should style
- NPM Package: https://www.npmjs.com/package/chai
- GitHub Repository: https://github.com/chaijs/chai
Assertion Styles
Chai provides THREE assertion styles:
1. BDD Style (expect)
const { expect } = require('chai');
expect(foo).to.equal('bar');
expect(foo).to.be.a('string');
expect(foo).to.have.lengthOf(3);
Most popular style - chainable, readable
2. TDD Style (assert)
const { assert } = require('chai');
assert.equal(foo, 'bar');
assert.typeOf(foo, 'string');
assert.lengthOf(foo, 3);
Classic assert style - familiar to C/Java developers
3. Should Style
const chai = require('chai');
chai.should();
foo.should.equal('bar');
foo.should.be.a('string');
foo.should.have.lengthOf(3);
Least common - modifies Object.prototype
Error Handling
AssertionError
All failed assertions throw AssertionError:
const { expect } = require('chai');
try {
expect(1).to.equal(2);
} catch (error) {
console.log(error.name); // 'AssertionError'
console.log(error.message); // 'expected 1 to equal 2'
}
In Test Frameworks
Mocha/Jest handle AssertionError automatically:
it('test', () => {
expect(value).to.equal(expected); // No try-catch needed
});
Outside Tests (Rare)
Production validation requires try-catch:
function validateInput(data) {
try {
expect(data).to.be.an('object');
expect(data.id).to.be.a('number');
return true;
} catch (error) {
return false; // or log error
}
}
WARNING: Don't use chai for production validation - use validator libraries instead.
Common Patterns
1. Deep Equality
expect(obj1).to.deep.equal(obj2);
expect(array).to.have.deep.members([1, 2, 3]);
2. Property Assertions
expect(obj).to.have.property('name');
expect(obj).to.have.property('age', 25);
expect(obj).to.have.all.keys('name', 'age');
3. Type Assertions
expect(value).to.be.a('string');
expect(value).to.be.an('array');
expect(value).to.be.null;
expect(value).to.be.undefined;
4. Existence Assertions
expect(value).to.exist;
expect(value).to.not.exist;
expect(value).to.be.ok; // truthy
expect(value).to.be.empty; // array/string/object
5. Comparison Assertions
expect(value).to.be.above(5);
expect(value).to.be.below(10);
expect(value).to.be.within(5, 10);
6. String/Array Contains
expect('hello world').to.include('world');
expect([1, 2, 3]).to.include(2);
expect({ a: 1, b: 2 }).to.include({ a: 1 });
Common Mistakes
Mistake #1: Using Chai in Production Code
Problem: Chai is designed for testing, not production validation
Example (WRONG):
// ❌ In production API
app.post('/api/users', (req, res) => {
expect(req.body).to.have.property('email');
expect(req.body.email).to.be.a('string');
// Throws AssertionError → crashes server!
});
Fix: Use validation libraries (joi, yup, zod):
// ✅ Production validation
const schema = Joi.object({
email: Joi.string().required()
});
const { error } = schema.validate(req.body);
if (error) return res.status(400).json({ error });
Mistake #2: Forgetting .to / .be
Example (WRONG):
expect(value).equal(5); // ❌ Missing .to
expect(value).a('string'); // ❌ Missing .be
Fix:
expect(value).to.equal(5); // ✅
expect(value).to.be.a('string'); // ✅
Mistake #3: Confusing .equal vs .eql
.equal - strict equality (===):
expect(obj1).to.equal(obj2); // ❌ Different references
.eql / .deep.equal - deep equality:
expect(obj1).to.deep.equal(obj2); // ✅ Compare contents
Best Practices
1. Prefer BDD Style (expect)
Most readable and chainable:
expect(user).to.have.property('name').that.is.a('string');
2. Use Descriptive Messages
expect(value, 'User age should be positive').to.be.above(0);
3. Chain Assertions
expect(user)
.to.be.an('object')
.that.has.property('email')
.that.is.a('string');
4. Only Use in Tests
Never use chai assertions in production code - use proper validation libraries.
Integration with Test Frameworks
Mocha
const { expect } = require('chai');
describe('Math', () => {
it('should add numbers', () => {
expect(1 + 1).to.equal(2);
});
});
Jest
// Jest has built-in assertions, but chai can be used:
const { expect } = require('chai');
test('adds numbers', () => {
expect(1 + 1).to.equal(2);
});
Contract Rationale
Postconditions (assertion-failure)
All chai assertions throw AssertionError when they fail. This is expected behavior in tests but can crash applications if used outside test contexts.
Evidence:
- Chai documentation explicitly states assertions throw on failure
- AssertionError is the standard exception type for all assertion libraries
- Using chai in production is an anti-pattern
Severity: Warning (expected in tests, problematic in production)
Citations:
Important Notes
- Testing Library: Chai is for tests only, not production validation
- Security: No CVEs - development tool
- AssertionError: All assertions throw on failure
- Alternatives for Production: joi, yup, zod, ajv
Research Metadata
- Research Date: 2026-02-27
- Researcher: Claude Sonnet 4.5
- Documentation Sources: 6 URLs
- Common Mistakes Documented: 3
- Line Count: 200+ lines (target 100+ ✅)