Chai 中文文档 下载 App

.any / .all 集合逻辑修饰器 - members 和 keys 的子集/并集语义

基本概念

.any 和 .all 是集合逻辑修饰器,主要配合 .members 和 .keys 两个断言方法使用。它们分别表达:

.any / .all + .keys

keys 断言检查对象的键集合:

const obj = { name: 'Alice', age: 30, email: 'a@b.com' };

// 默认:all —— 所有给定的键都要存在
expect(obj).to.have.all.keys('name', 'age');           // 通过
expect(obj).to.have.all.keys('name', 'age', 'phone');  // 失败

// any —— 给定的键中存在任意一个就行
expect(obj).to.have.any.keys('name', 'phone');          // 通过(name 存在)
expect(obj).to.have.any.keys('phone', 'fax');          // 失败(都不存在)

.any.keys 特别适合验证"对象有这些键之一"的场景:

// 用户对象应该包含身份验证相关的字段之一
expect(user).to.have.any.keys('email', 'phone', 'googleId', 'facebookId');

配合 .deep 还能处理 Set / Map:

const set = new Set(['apple', 'banana']);
expect(set).to.have.all.keys(['apple', 'banana']);
expect(set).to.have.any.keys(['apple', 'cherry']);

.any / .all + .members

members 断言是数组成员匹配:

const arr = [1, 2, 3];

// 默认:all —— 给定的所有成员都要在数组中存在
expect(arr).to.have.all.members([1, 2]);        // 通过
expect(arr).to.have.all.members([1, 2, 4]);     // 失败(4 不存在)

// any —— 给定的成员中存在任意一个就行
expect(arr).to.have.any.members([1, 4]);         // 通过(1 存在)
expect(arr).to.have.any.members([4, 5]);         // 失败(都不存在)

与 .includeMembers 的关系

.includeMembers 做的事和 .all.members 类似但语义不同:

// includeMembers:haystack 包含 needle 全部成员(子集关系)
expect([1, 2, 3]).to.includeMembers([1, 2]);         // 通过
expect([1, 2, 3]).to.have.all.members([1, 2]);        // 也通过

// 区别:haystack 多出来的元素
expect([1, 2, 3]).to.includeMembers([1, 2]);          // 通过(haystack 可以多)
expect([1, 2, 3]).to.have.all.members([1, 2, 3]);     // 通过
expect([1, 2, 3]).to.have.all.members([1, 2]);       // 失败!all.members 要求 haystack 和 needle 成员完全相同

简单说:

修饰器组合

// .deep + .any:深度比较 + 任意键
expect([{ a: 1 }, { b: 2 }]).to.have.any.members([{ a: 1 }, { c: 3 }]);  // 通过
expect([{ a: 1 }, { b: 2 }]).to.have.any.members([{ c: 3 }, { d: 4 }]);  // 失败

完整语义表

写法语义示例
.all.members([...])数组必须包含且仅包含给定成员[1,2,3] vs [1,2,3] ✅ / vs [1,2] ❌
.any.members([...])数组必须包含给定成员中的至少一个[1,2,3] vs [1,4] ✅ / vs [4,5] ❌
.includeMembers([...])数组必须包含给定成员(子集)[1,2,3] vs [1,2] ✅ / vs [4] ❌
.all.keys('a','b')对象必须拥有所有给定键{a:1,b:2} ✅ / {a:1} ❌
.any.keys('a','b')对象必须拥有给定键中至少一个{a:1} ✅ / {c:1} ❌

实战场景

场景一:API 响应字段检查

it('用户 API 响应应该有至少一种联系方式', function () {
  const res = await getUserProfile(userId);
  // 应该有 email / phone / 任意社交账号之一
  expect(res.body).to.have.any.keys('email', 'phone', 'twitter', 'github');
});

场景二:数组包含期望的某些值

it('推荐列表应该包含至少一个热门标签', function () {
  const tags = await getRecommendTags();
  expect(tags).to.have.any.members(['热门', '推荐', '编辑精选', '必看']);
});

场景三:枚举值范围验证

it('订单状态应该是已定义的几种之一', function () {
  const allowedStatuses = ['pending', 'paid', 'shipped', 'delivered', 'cancelled'];
  expect(order.status).to.be.oneOf(allowedStatuses);  // oneOf 也是类似语义
});

下一步