Table of Contents#
- What is Chai BDD and
expect? - Setup: Installing Chai
- Core Assertion:
to.be.oneOf - Handling Case Sensitivity
- Edge Cases to Consider
oneOfvs.include: When to Use Which?- Real-World Example: Testing API Responses
- Conclusion
- References
What is Chai BDD and expect?#
Chai is a BDD/TDD assertion library for Node.js and the browser, designed to work with testing frameworks like Mocha, Jest, or Jasmine. It offers three assertion styles: should, expect, and assert.
The expect interface is particularly popular for BDD because it uses a chainable, natural-language syntax (e.g., expect(value).to.equal(42)), making tests read like plain English. This style avoids extending native JavaScript objects (unlike should), which can cause issues in some environments.
Setup: Installing Chai#
Before using Chai, ensure you have a testing framework (e.g., Mocha) installed. If not, set up a basic project:
-
Initialize a Node.js project (if needed):
npm init -y -
Install Chai and Mocha as dev dependencies:
npm install chai mocha --save-dev -
In your test file (e.g.,
string-in-array.test.js), importexpectfrom Chai:const { expect } = require('chai');
Now you’re ready to write assertions!
Core Assertion: to.be.oneOf#
To check if a string (or any value) is an element of an array, Chai provides the to.be.oneOf assertion. This method verifies that the target value is strictly equal (===) to at least one element in the provided array.
Basic Example#
Let’s start with a simple test: Assert that the string "apple" is one of the elements in ["banana", "apple", "orange"].
Test Code:
describe('String in Array Check', () => {
it('should pass if the string is in the array', () => {
const fruit = 'apple';
const fruits = ['banana', 'apple', 'orange'];
// Assert: "apple" is one of the elements in fruits
expect(fruit).to.be.oneOf(fruits);
});
it('should fail if the string is NOT in the array', () => {
const fruit = 'grape';
const fruits = ['banana', 'apple', 'orange'];
// This will fail (grape is not in fruits)
expect(fruit).to.be.oneOf(fruits);
});
}); Output (when run with Mocha):
- The first test passes:
✓ should pass if the string is in the array. - The second test fails with an error:
AssertionError: expected 'grape' to be one of [ 'banana', 'apple', 'orange' ]
How It Works#
expect(value).to.be.oneOf(array) works by iterating over array and checking if value is strictly equal (===) to any element. For strings, this means the check is case-sensitive and type-sensitive (e.g., "123" ≠ 123).
Handling Case Sensitivity#
Since to.be.oneOf uses strict equality (===), case differences will cause the assertion to fail. For example, "Apple" (capital "A") will not match "apple" (lowercase "a"):
Example:
it('fails for case differences', () => {
const fruit = 'Apple'; // Capital "A"
const fruits = ['apple', 'banana', 'orange']; // Lowercase "a"
expect(fruit).to.be.oneOf(fruits); // Fails!
}); Fix for Case-Insensitive Checks:
To ignore case, normalize both the target string and array elements (e.g., convert to lowercase):
it('passes with case-insensitive check', () => {
const fruit = 'Apple';
const fruits = ['apple', 'banana', 'orange'];
// Normalize to lowercase
const normalizedFruit = fruit.toLowerCase();
const normalizedFruits = fruits.map(f => f.toLowerCase());
expect(normalizedFruit).to.be.oneOf(normalizedFruits); // Passes!
}); Edge Cases to Consider#
Empty Arrays#
If the array is empty, to.be.oneOf will always fail (since there are no elements to match):
it('fails when array is empty', () => {
const fruit = 'apple';
const emptyArray = [];
expect(fruit).to.be.oneOf(emptyArray); // Fails: "expected 'apple' to be one of []"
}); Non-String Elements in the Array#
If the array contains non-string elements (e.g., numbers, objects), to.be.oneOf will only pass if the target string strictly matches a string element. Non-string elements will not match:
it('ignores non-string elements', () => {
const value = '42'; // String
const mixedArray = [42, 'banana', { key: 'value' }]; // Number, string, object
expect(value).to.be.oneOf(mixedArray); // Fails: "42" (string) ≠ 42 (number)
}); Null/Undefined Strings#
If the target string is null or undefined, to.be.oneOf will check if null/undefined exists in the array:
it('handles null/undefined', () => {
expect(null).to.be.oneOf([null, 'apple']); // Passes
expect(undefined).to.be.oneOf(['banana', undefined]); // Passes
expect(null).to.be.oneOf(['apple', 'banana']); // Fails
}); oneOf vs. include: When to Use Which?#
Chai also has an include assertion for arrays, which checks if the array contains a value. How does this differ from oneOf?
expect(value).to.be.oneOf(array): The subject is the value; asserts the value is an element of the array.expect(array).to.include(value): The subject is the array; asserts the array includes the value.
Both use strict equality (===), but the syntax depends on what you’re testing. Use oneOf when the value is the focus (e.g., "this string should be one of these options"), and include when the array is the focus (e.g., "this array should include the string").
Real-World Example: Testing API Responses#
Let’s apply this to a common scenario: testing that an API returns a valid status for a user. Suppose an endpoint /api/users/1 returns a JSON object with a status field, which must be "active", "inactive", or "pending".
Test Code:
const { expect } = require('chai');
const request = require('supertest'); // For API testing
const app = require('../app'); // Your Express app
describe('GET /api/users/1', () => {
it('responds with a valid status', async () => {
const response = await request(app).get('/api/users/1');
// Assert status is 200 OK
expect(response.status).to.equal(200);
// Assert user status is one of allowed values
const allowedStatuses = ['active', 'inactive', 'pending'];
expect(response.body.status).to.be.oneOf(allowedStatuses);
});
}); This test ensures the API behaves as expected, catching invalid statuses (e.g., "banned") early.
Conclusion#
Chai’s to.be.oneOf assertion is a powerful tool for checking if a string (or any value) is an element of an array. Its strict equality check ensures precision, and with minor adjustments (like normalization for case insensitivity), it handles most real-world scenarios.
Key takeaways:
- Use
expect(string).to.be.oneOf(array)to assert a string is in an array. - Remember strict equality (
===) for case and type sensitivity. - Normalize strings/arrays for case-insensitive checks.
- Handle edge cases like empty arrays or non-string elements explicitly.
By mastering this assertion, you’ll write more robust, readable tests for validating allowed values in your applications.