Chai Immutable
该插件为 Chai 提供了一组针对 Facebook 的 JavaScript 集合不变库 的断言。
断言
- BDD API 参考(Expect / Should)
- TDD API 参考(Assert)
安装
Node.js
npm install --save-dev chai-immutable
yarn add --dev chai-immutable
然后你可以像使用其他 Chai 插件一样使用此插件
const chai = require('chai');
const chaiImmutable = require('chai-immutable');
chai.use(chaiImmutable);
ES6 语法(需要 Babel 编译)
import chai from 'chai';
import chaiImmutable from 'chai-immutable';
chai.use(chaiImmutable);
在浏览器中
在包含 Chai 和 Immutable 之后包含此插件。它会自动插入到 Chai 中,并准备使用
<script src="chai-immutable.js"></script>
使用 chai-immutable
与其他插件
如果您将此插件与 chai-as-promised
或 dirty-chai
一起使用,请注意 chai-immutable
必须在它们之前加载。例如
const chai = require('chai');
const chaiAsPromised = require('chai-as-promised');
const chaiImmutable = require('chai-immutable');
const dirtyChai = require('dirty-chai');
const { expect } = chai;
chai.use(chaiImmutable);
chai.use(chaiAsPromised);
chai.use(dirtyChai);
const { List } = require('immutable');
/* ... */
expect(Promise.resolve(List.of(1, 2, 3))).to.eventually.have.size(3);
expect(true).to.be.true();
BDD API 参考(Expect / Should)
.empty
断言不变集合为空。
expect(List()).to.be.empty;
expect(List.of(1, 2, 3)).to.not.be.empty;
.equal(collection)
- @param { Collection } collection
断言目标的值等价于 collection
的值。Chai 原始 equal
方法的别名也被支持。
const a = List.of(1, 2, 3);
const b = List.of(1, 2, 3);
expect(a).to.equal(b);
不变数据结构应该只包含其他不变数据结构(与 Array
和 Object
不同),才能被视为不变,并能针对 .equal()
正确地工作。有关更多信息,请参见 issue #24。
此外,请注意,当针对不变数据结构进行测试时,deep.equal
和 eql
是 equal
的同义词,因此它们是 equal
的别名。
.referenceEqual(value)
- @param {Collection} value
断言目标的引用等价于 collection
的引用。此方法保留了 Chai 的 equal
的原始行为。
有关更多详细信息,请参见 issue #210。
const a = List.of(1, 2, 3);
const b = a;
const c = List.of(1, 2, 3);
expect(a).to.referenceEqual(b);
expect(a).to.not.referenceEqual(c);
.include(value)
- @param { Mixed } val
include
和 contain
断言可以用作基于属性的语言链,也可以用作方法来断言不变集合中包含某个值或子集。当用作语言链时,它们会为 keys
断言切换 contains
标志。
请注意,在不变数据结构的上下文中,deep.include
的行为与 include
完全相同。
expect(new List([1, 2, 3])).to.include(2);
expect(new List([1, 2, 3])).to.deep.include(2);
expect(new Map({ foo: 'bar', hello: 'world' })).to.include('bar');
expect(new Map({ a: 1, b: 2, c: 3 })).to.include(new Map({ a: 1, b: 2 }));
expect(new Map({ foo: 'bar', hello: 'world' })).to.include.keys('foo');
.keys(key1[, key2[, …]])
-
@param _{ String… Array Object Collection }_ keyN
断言目标集合具有给定的键。
当目标是对象或数组时,键可以作为一个或多个字符串参数、单个数组参数、单个对象参数或不变集合提供。在最后两种情况下,只有给定对象/集合中的键很重要;值会被忽略。
expect(new Map({ foo: 1, bar: 2 })).to.have.all.keys('foo', 'bar');
expect(new Map({ foo: 1, bar: 2 })).to.have.all.keys(new List(['bar', 'foo']));
expect(new Map({ foo: 1, bar: 2 })).to.have.all.keys(new Set(['bar', 'foo']));
expect(new Map({ foo: 1, bar: 2 })).to.have.all.keys(new Stack(['bar', 'foo']));
expect(new List(['x', 'y'])).to.have.all.keys(0, 1);
expect(new Map({ foo: 1, bar: 2 })).to.have.all.keys(['foo', 'bar']);
expect(new List(['x', 'y'])).to.have.all.keys([0, 1]);
// Values in the passed object are ignored:
expect(new Map({ foo: 1, bar: 2 })).to.have.all.keys({ bar: 6, foo: 7 });
expect(new Map({ foo: 1, bar: 2 })).to.have.all.keys(
new Map({ bar: 6, foo: 7 })
);
expect(new List(['x', 'y'])).to.have.all.keys({ 0: 4, 1: 5 });
请注意,在不变数据结构的上下文中,deep.property
的行为与 property
完全相同。
默认情况下,目标必须具有所有给定的键,并且不能更多。在链中提前添加 .any
,仅要求目标至少具有一个给定的键。此外,在链中提前添加 .not
来否定 .keys
。在否定 .keys
时,通常最好添加 .any
,而在断言 .keys
时不进行否定,最好使用 .all
。
当否定 .keys
时,.any
是首选,因为 .not.any.keys
断言了对输出的预期,而 .not.all.keys
会产生不确定的预期。
// Recommended; asserts that target doesn't have any of the given keys
expect(new Map({ a: 1, b: 2 })).to.not.have.any.keys('c', 'd');
// Not recommended; asserts that target doesn't have all of the given
// keys but may or may not have some of them
expect(new Map({ a: 1, b: 2 })).to.not.have.all.keys('c', 'd');
当断言 .keys
时不进行否定,.all
是首选,因为 .all.keys
断言了对输出的预期,而 .any.keys
会产生不确定的预期。
// Recommended; asserts that target has all the given keys
expect(new Map({ a: 1, b: 2 })).to.have.all.keys('a', 'b');
// Not recommended; asserts that target has at least one of the given
// keys but may or may not have more of them
expect(new Map({ a: 1, b: 2 })).to.have.any.keys('a', 'b');
请注意,当链中既没有 .all
也没有 .any
时,默认情况下使用 .all
。但是,通常最好还是添加 .all
,因为它可以提高可读性。
// Both assertions are identical
expect(new Map({ a: 1, b: 2 })).to.have.all.keys('a', 'b'); // Recommended
expect(new Map({ a: 1, b: 2 })).to.have.keys('a', 'b'); // Not recommended
在链中提前添加 .include
,要求目标的键是预期键的超集,而不是相同的集合。
// Target object's keys are a superset of ['a', 'b'] but not identical
expect(new Map({ a: 1, b: 2, c: 3 })).to.include.all.keys('a', 'b');
expect(new Map({ a: 1, b: 2, c: 3 })).to.not.have.all.keys('a', 'b');
但是,如果 .any
和 .include
结合使用,则只生效 .any
。在这种情况下,.include
会被忽略。
// Both assertions are identical
expect(new Map({ a: 1 })).to.have.any.keys('a', 'b');
expect(new Map({ a: 1 })).to.include.any.keys('a', 'b');
别名 .key
可以与 .keys
交换使用。
expect(new Map({ foo: 1 })).to.have.key('foo');
.property(path[, val])
-
@param _{ String Array Iterable }_ path - @param { Mixed } val (可选)
断言目标具有给定 path
的属性。
expect(new Map({ a: 1 })).to.have.property('a');
当提供 val
时,.property
还断言属性的值等于给定的 val
。 val
可以是不可变集合。
expect(new Map({ a: 1 })).to.have.property('a', 1);
请注意,在不变数据结构的上下文中,deep.property
的行为与 property
完全相同。
在链中提前添加 .nested
,在引用嵌套属性时启用点和括号表示法。不可变的 List
也可以用作 nested.property
的起点。
expect(Immutable.fromJS({ a: { b: ['x', 'y'] } })).to.have.nested.property(
'a.b[1]'
);
expect(Immutable.fromJS({ a: { b: ['x', 'y'] } })).to.have.nested.property(
'a.b[1]',
'y'
);
expect(Immutable.fromJS({ a: { b: ['x', 'y'] } })).to.have.nested.property(
['a', 'b', 1],
'y'
);
expect(Immutable.fromJS({ a: { b: ['x', 'y'] } })).to.have.nested.property(
new List(['a', 'b', 1]),
'y'
);
如果 .
或 []
是实际属性名称的一部分,则可以通过在它们前面添加两个反斜杠来转义它们。
expect(Immutable.fromJS({ '.a': { '[b]': 'x' } })).to.have.nested.property(
'\\.a.\\[b\\]'
);
在链中提前添加 .not
来否定 .property
。
expect(new Map({ a: 1 })).to.not.have.property('b');
但是,在提供 val
时,否定 .property
很危险。问题在于它会产生不确定的预期,断言目标要么没有给定 path
的属性,要么它确实具有给定键 path
的属性,但其值不等于给定的 val
。通常最好确定预期的确切输出,然后编写只接受该确切输出的断言。
当目标预期在给定的 path
没有属性时,通常最好断言这一点。
expect(new Map({ b: 2 })).to.not.have.property('a'); // Recommended
expect(new Map({ b: 2 })).to.not.have.property('a', 1); // Not recommended
当目标预期在给定的键 path
具有属性时,通常最好断言该属性具有其预期值,而不是断言它没有多个意外值之一。
expect(new Map({ a: 3 })).to.have.property('a', 3); // Recommended
expect(new Map({ a: 3 })).to.not.have.property('a', 1); // Not recommended
.property
会更改链中后续任何断言的目标,使其成为原始目标对象中属性的值。
expect(new Map({ a: 1 }))
.to.have.property('a')
.that.is.a('number');
.size(value)
- @param { Number } size
断言不可变集合具有预期的规模。
expect(List.of(1, 2, 3)).to.have.size(3);
它也可以用作链的前驱,以进行 size
属性的值比较。
expect(List.of(1, 2, 3)).to.have.size.least(3);
expect(List.of(1, 2, 3)).to.have.size.most(3);
expect(List.of(1, 2, 3)).to.have.size.above(2);
expect(List.of(1, 2, 3)).to.have.size.below(4);
expect(List.of(1, 2, 3)).to.have.size.within(2, 4);
与 length
/lengthOf
类似,sizeOf
是 size
的别名
expect(List.of(1, 2, 3)).to.have.sizeOf(3);
TDD API 参考(Assert)
.equal(actual, expected)
- @param { Collection } actual
- @param { Collection } expected
断言 actual
的值等效于 expected
的值。请注意,在不可变数据结构的上下文中,.strictEqual()
和 .deepEqual()
的断言方式与 .equal()
完全相同。
const a = List.of(1, 2, 3);
const b = List.of(1, 2, 3);
assert.equal(a, b);
不可变数据结构应该只包含其他不可变数据结构(与 Array
和 Object
不同),才能被视为不可变数据结构,并正确地针对 .equal()
、.strictEqual()
或 .deepEqual()
工作。有关更多信息,请参见 issue #24。
.referenceEqual(actual, expected)
- @param {Collection} actual
- @param {Collection} expected
断言 actual
的引用等效于 expected
的引用。此方法保留了 Chai 的 equal
的原始行为。
有关更多详细信息,请参见 issue #210。
const a = List.of(1, 2, 3);
const b = a;
const c = List.of(1, 2, 3);
assert.referenceEqual(a, b);
assert.throws(() => assert.referenceEqual(a, c));
.notEqual(actual, expected)
- @param { Collection } actual
- @param { Collection } expected
断言 actual
的值不等效于 expected
的值。请注意,在不可变数据结构的上下文中,.notStrictEqual()
和 .notDeepEqual()
的断言方式与 .notEqual()
完全相同。
const a = List.of(1, 2, 3);
const b = List.of(4, 5, 6);
assert.notEqual(a, b);
.notReferenceEqual(actual, expected)
- @param {Collection} actual
- @param {Collection} expected
断言 actual
的引用不等效于 expected
的引用。此方法保留了 Chai 的 notEqual
的原始行为。
有关更多详细信息,请参见 issue #210。
const a = List.of(1, 2, 3);
const b = a;
const c = List.of(1, 2, 3);
assert.throws(() => assert.notReferenceEqual(a, b));
assert.notReferenceEqual(a, c);
.sizeOf(collection, length)
- @param { Collection } collection
- @param { Number } size
断言不可变集合具有预期的规模。
assert.sizeOf(List.of(1, 2, 3), 3);
assert.sizeOf(new List(), 0);