npm Version License Build Status Build Status Coverage Status devDependencies Status peerDependencies Status

Chai Immutable

该插件为 Chai 提供了一组针对 Facebook 的 JavaScript 集合不变库 的断言。

断言

安装

Node.js

通过 npmyarn 安装

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-promiseddirty-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);

不变数据结构应该只包含其他不变数据结构(与 ArrayObject 不同),才能被视为不变,并能针对 .equal() 正确地工作。有关更多信息,请参见 issue #24

此外,请注意,当针对不变数据结构进行测试时,deep.equaleqlequal 的同义词,因此它们是 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

includecontain 断言可以用作基于属性的语言链,也可以用作方法来断言不变集合中包含某个值或子集。当用作语言链时,它们会为 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 还断言属性的值等于给定的 valval 可以是不可变集合。

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 类似,sizeOfsize 的别名

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);

不可变数据结构应该只包含其他不可变数据结构(与 ArrayObject 不同),才能被视为不可变数据结构,并正确地针对 .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);