chai-fs

Build Status Dependency Status devDependency Status NPM version

Chai 断言 插件 用于 Node.js 文件系统 API。使用 path 和同步 fs 来断言文件和目录。

所有断言都可以在 expectshouldassert 样式中使用,并支持可选的消息参数。

使用

服务器端

从 npm 安装

$ npm install chai-fs

让 chai 使用 chai-fs 模块

var chai = require('chai');
chai.use(require('chai-fs'));

浏览器端

没有文件系统。

断言

basename()

断言 path.basename(path) 的返回值

expect(path).to.have.basename(name, ?msg);
expect(path).to.not.have.basename(name, ?msg);

path.should.have.basename(name, ?msg);
path.should.not.have.basename(name, ?msg);

assert.basename(path, name, ?msg);
assert.notBasename(path, name, ?msg);

dirname()

断言 path.dirname(path) 的返回值

expect(path).to.have.dirname(name, ?msg);
expect(path).to.not.have.dirname(name, ?msg);

path.should.have.dirname(name, ?msg);
path.should.not.have.dirname(name, ?msg);

assert.dirname(path, name, ?msg);
assert.notDirname(path, name, ?msg);

extname()

断言 path.extname(path) 的返回值

expect(path).to.have.extname(name, ?msg);
expect(path).to.not.have.extname(name, ?msg);

path.should.have.extname(name, ?msg);
path.should.not.have.extname(name, ?msg);

assert.extname(path, name, ?msg);
assert.notExtname(path, name, ?msg);

path()

断言路径存在。

使用 fs.existsSync()

expect(path).to.be.a.path(?msg);
expect(path).to.not.be.a.path(?msg);

path.should.be.a.path(?msg);
path.should.not.be.a.path(?msg);

assert.pathExists(path, ?msg);
assert.notPathExists(path, ?msg);

使用 Chai 的 exist 链会很好,但但是在否定和消息参数方面存在问题。所以不要这样做。

directory()

断言路径存在并且是一个目录。

使用 fs.statSync().isDirectory()

expect(path).to.be.a.directory(?msg);
expect(path).to.not.be.a.directory(?msg);

path.should.be.a.directory(?msg);
path.should.not.be.a.directory(?msg);

assert.isDirectory(path,  ?msg);
assert.notIsDirectory(path, ?msg);

directory().and.empty

断言路径存在,是一个目录并且包含零个项目。

expect(path).to.be.a.directory(?msg).and.empty;
expect(path).to.be.a.directory(?msg).and.not.empty;

path.should.be.a.directory(?msg).and.empty;
path.should.be.a.directory(?msg).and.not.empty;

assert.isEmptyDirectory(path, ?msg);
assert.notIsEmptyDirectory(path, ?msg);
  • directory() 后链接
  • 使用 fs.readdirSync().length === 0
  • 要使用 expect/should 否定它,你需要在常规的 directory() 后链接 .not 否定。

directory().with.contents([…])

断言路径存在,是一个目录并且具有特定内容(文件、子目录、符号链接等)。

expect(path).to.be.a.directory(?msg).with.contents(array, ?msg);
expect(path).to.be.a.directory(?msg).and.not.have.contents(array, ?msg);
expect(path).to.be.a.directory(?msg).with.deep.contents(array, ?msg);
expect(path).to.be.a.directory(?msg).and.not.have.deep.contents(array, ?msg);
expect(path).to.be.a.directory(?msg).and.include.contents(array, ?msg);
expect(path).to.be.a.directory(?msg).and.not.include.contents(array, ?msg);

path.should.be.a.directory(?msg).with.contents(array, ?msg);
path.should.be.a.directory(?msg).and.not.have.contents(array, ?msg);
path.should.be.a.directory(?msg).with.deep.contents(array, ?msg);
path.should.be.a.directory(?msg).and.not.have.deep.contents(array, ?msg);
path.should.be.a.directory(?msg).and.include.contents(array, ?msg);
path.should.be.a.directory(?msg).and.not.include.contents(array, ?msg);

assert.directoryContent(path, array, ?msg);
assert.notDirectoryContent(path, array, ?msg);
assert.directoryDeepContent(path, array, ?msg);
assert.notDirectoryDeepContent(path, array, ?msg);
assert.directoryInclude(path, array, ?msg);
assert.notDirectoryInclude(path, array, ?msg);
  • 内容的路径相对于目录
  • 只有顶层内容包含在内,除非链中包含 .deep
  • 如果链中包含 .include.contain,则目录必须至少包含指定的内容,但可以包含更多内容
  • 你可以使用 .content().contents()。它们都是一样的。
  • 要使用 expect/should 否定它,你需要在常规的 directory() 后链接 .not 否定。

directory().with.files([…])

断言路径存在,是一个目录并且包含特定文件。

expect(path).to.be.a.directory(?msg).with.files(array, ?msg);
expect(path).to.be.a.directory(?msg).and.not.have.files(array, ?msg);
expect(path).to.be.a.directory(?msg).with.deep.files(array, ?msg);
expect(path).to.be.a.directory(?msg).and.not.have.deep.files(array, ?msg);
expect(path).to.be.a.directory(?msg).and.include.files(array, ?msg);
expect(path).to.be.a.directory(?msg).and.not.include.files(array, ?msg);

path.should.be.a.directory(?msg).with.files(array, ?msg);
path.should.be.a.directory(?msg).and.not.have.files(array, ?msg);
path.should.be.a.directory(?msg).with.deep.files(array, ?msg);
path.should.be.a.directory(?msg).and.not.have.deep.files(array, ?msg);
path.should.be.a.directory(?msg).and.include.files(array, ?msg);
path.should.be.a.directory(?msg).and.not.include.files(array, ?msg);

assert.directoryFiles(path, array, ?msg);
assert.notDirectoryFiles(path, array, ?msg);
assert.directoryDeepFiles(path, array, ?msg);
assert.notDirectoryDeepFiles(path, array, ?msg);
assert.directoryIncludeFiles(path, array, ?msg);
assert.notDirectoryIncludeFiles(path, array, ?msg);
  • 文件路径相对于目录
  • 只有顶层文件包含在内,除非链中包含 .deep
  • 如果链中包含 .include.contain,则目录必须至少包含指定的文件,但可以包含更多文件
  • 要使用 expect/should 否定它,你需要在常规的 directory() 后链接 .not 否定。

directory().with.subDirs([…])

断言路径存在,是一个目录并且包含特定子目录。

expect(path).to.be.a.directory(?msg).with.subDirs(array, ?msg);
expect(path).to.be.a.directory(?msg).and.not.have.subDirs(array, ?msg);
expect(path).to.be.a.directory(?msg).with.deep.subDirs(array, ?msg);
expect(path).to.be.a.directory(?msg).and.not.have.deep.subDirs(array, ?msg);
expect(path).to.be.a.directory(?msg).and.include.subDirs(array, ?msg);
expect(path).to.be.a.directory(?msg).and.not.include.subDirs(array, ?msg);

path.should.be.a.directory(?msg).with.subDirs(array, ?msg);
path.should.be.a.directory(?msg).and.not.have.subDirs(array, ?msg);
path.should.be.a.directory(?msg).with.deep.subDirs(array, ?msg);
path.should.be.a.directory(?msg).and.not.have.deep.subDirs(array, ?msg);
path.should.be.a.directory(?msg).and.include.subDirs(array, ?msg);
path.should.be.a.directory(?msg).and.not.include.subDirs(array, ?msg);

assert.directorySubDirs(path, array, ?msg);
assert.notDirectorySubDirs(path, array, ?msg);
assert.directoryDeepSubDirs(path, array, ?msg);
assert.notDirectoryDeepSubDirs(path, array, ?msg);
assert.directoryIncludeSubDirs(path, array, ?msg);
assert.notDirectoryIncludeSubDirs(path, array, ?msg);
  • 内容的路径相对于起始目录
  • 只有顶层子目录包含在内,除非链中包含 .deep
  • 如果链中包含 .include.contain,则目录必须至少包含指定的子目录,但可以包含更多子目录
  • 要使用 expect/should 否定它,你需要在常规的 directory() 后链接 .not 否定。

directory().with.contents.that.satisfy(fn)

你可以将 .contents.files.subDirs 与任何可以在数组上操作的 Chai.js 断言链接起来,包括 .lengthOf().satisfy().members() 等。

expect(path).to.be.a.directory().and.content.is.an('array');

expect(path).to.be.a.directory().and.files.have.lengthOf(5);

path.should.be.a.directory().with.subDirs.that.include.members(['subDir1', 'subDir2']);

path.should.be.a.directory().with.files.that.satisfy(function(files) {
  return files.every(function(file) {
    return file.substr(-4) === '.txt';
  });
})
  • 内容的路径相对于目录
  • 只有顶层内容包含在内,除非链中包含 .deep
  • 你可以使用 .content().contents()。它们都是一样的。
  • 要使用 expect/should 否定它,你需要在常规的 directory() 后链接 .not 否定。

directory().and.equal(otherPath)

断言两者路径都存在,是目录并且包含相同的内容(文件、子目录、符号链接等)。

expect(path).to.be.a.directory(?msg).and.equal(otherPath, ?msg);
expect(path).to.be.a.directory(?msg).and.not.equal(otherPath, ?msg);
expect(path).to.be.a.directory(?msg).and.deep.equal(otherPath, ?msg);
expect(path).to.be.a.directory(?msg).and.not.deep.equal(otherPath, ?msg);

path.should.be.a.directory(?msg).and.equal(otherPath, ?msg);
path.should.be.a.directory(?msg).and.not.equal(otherPath, ?msg);
path.should.be.a.directory(?msg).and.deep.equal(otherPath, ?msg);
path.should.be.a.directory(?msg).and.not.deep.equal(otherPath, ?msg);

assert.directoryEqual(path, otherPath, ?msg);
assert.notDirectoryEqual(path, otherPath, ?msg);
assert.directoryDeepEqual(path, otherPath, ?msg);
assert.notDirectoryDeepEqual(path, otherPath, ?msg);
  • 只有顶层内容进行比较,除非链中包含 .deep
  • 要使用 expect/should 否定它,你需要在常规的 directory() 后链接 .not 否定。

file()

断言路径存在并且是一个文件。

使用 fs.statSync().isFile()

expect(path).to.be.a.file(?msg);
expect(path).to.not.be.a.file(?msg);

path.should.be.a.file(?msg);
path.should.not.be.a.file(?msg);

assert.isFile(path, ?msg);
assert.notIsFile(path, ?msg);

file().and.empty

断言路径存在,是一个文件并且大小为零。

expect(path).to.be.a.file(?msg).and.empty;
expect(path).to.be.a.file(?msg).and.not.empty;

path.should.be.a.file(?msg).and.empty;
path.should.be.a.file(?msg).and.not.empty;

assert.isEmptyFile(path, ?msg);
assert.notIsEmptyFile(path, ?msg);
  • file() 后链接
  • 使用 fs.statSync().size === 0
  • 要使用 expect/should 否定它,你需要在常规的 file() 后链接 .not 否定。

file().with.content(str)

断言路径存在,是一个文件并且具有特定内容。

expect(path).to.be.a.file(?msg).with.content(data, ?msg);
expect(path).to.be.a.file(?msg).and.not.have.content(data, ?msg);

path.should.be.a.file(?msg).with.content(data, ?msg);
path.should.be.a.file(?msg).and.not.have.content(data, ?msg);

assert.fileContent(path, data, ?msg);
assert.notFileContent(path, data, ?msg);
  • 将文件读取为 utf8 文本(可以更新以支持 base64、二进制 Buffer 等)。
  • 你可以使用 .content().contents()。它们都是一样的。
  • 要使用 expect/should 否定它,你需要在常规的 file() 后链接 .not 否定。

file().with.contents.that.match(/xyz/)

断言路径存在,是一个文件并且内容与正则表达式匹配。

expect(path).to.be.a.file(?msg).with.contents.that.match(/xyz/, ?msg);
expect(path).to.be.a.file(?msg).and.not.have.contents.that.match(/xyz/, ?msg);

path.should.be.a.file(?msg).with.contents.that.match(/xyz/, ?msg);
path.should.be.a.file(?msg).and.not.have.contents.that.match(/xyz/, ?msg);

assert.fileContentMatch(path, /xyz/, ?msg);
assert.notFileContentMatch(path, /xyz/, ?msg);
  • 将文件读取为 utf8 文本(可以更新以支持 base64、二进制 Buffer 等)。
  • 你可以使用 .content.contents。它们都是一样的。
  • 要使用 expect/should 否定它,你需要在常规的 file() 后链接 .not 否定。

file().and.equal(otherPath)

断言两者路径都存在,是文件并且包含相同的内容

expect(path).to.be.a.file(?msg).and.equal(otherPath, ?msg);
expect(path).to.be.a.file(?msg).and.not.equal(otherPath, ?msg);

path.should.be.a.file(?msg).and.equal(otherPath, ?msg);
path.should.be.a.file(?msg).and.not.equal(otherPath, ?msg);

assert.fileEqual(path, otherPath, ?msg);
assert.notFileEqual(path, otherPath, ?msg);
  • 将两个文件读取为 utf8 文本(可以更新以支持 base64、二进制 Buffer 等)。
  • 要使用 expect/should 否定它,你需要在常规的 file() 后链接 .not 否定。

file().and.deep.equal(otherPath)

断言两者路径都存在,是文件,包含相同的内容,并且具有相同的属性,包括

  • 所有者 (stats.uid)
  • 组 (stats.gid)
  • 创建时间 (stats.birthtime)
  • 最后修改时间 (stats.mtime)
  • 最后更改时间 (stats.ctime)

    expect(path).to.be.a.file(?msg).and.deep.equal(otherPath, ?msg); expect(path).to.be.a.file(?msg).and.not.deep.equal(otherPath, ?msg);

    path.should.be.a.file(?msg).and.deep.equal(otherPath, ?msg); path.should.be.a.file(?msg).and.not.deep.equal(otherPath, ?msg);

    assert.fileDeepEqual(path, otherPath, ?msg); assert.notFileDeepEqual(path, otherPath, ?msg);

  • 将两个文件读取为 utf8 文本(可以更新以支持 base64、二进制 Buffer 等)。
  • 要使用 expect/should 否定它,你需要在常规的 file() 后链接 .not 否定。
  • 最后访问时间 (stats.atime)包含在比较中,因为仅仅读取此值(通过 fs.stat())会导致它在某些操作系统上发生更改,这可能导致测试不稳定

file().with.json

断言路径存在,是一个文件并且包含可解析的 JSON 文本。

expect(path).to.be.a.file(?msg).with.json;
expect(path).to.be.a.file(?msg).with.not.json;

path.should.be.a.file(?msg).with.json;
path.should.be.a.file(?msg).with.not.json;

assert.jsonFile(path, ?msg);
assert.notJsonFile(path, ?msg);
  • file() 后链接
  • 要使用 expect/should 否定它,你需要在常规的 file() 后链接 .not 否定。
  • with 链只是语法糖。

file().using.json.schema(obj)

断言路径存在,是一个文件,包含符合给定 JSON-Schema 的可解析 JSON 文本。

expect(path).to.be.a.file(?msg).with.json.using.schema(obj);
expect(path).to.be.a.file(?msg).with.json.not.using.schema(obj);

path.should.be.a.file(?msg).with.json.using.schema(obj);
path.should.be.a.file(?msg).with.json.not.using.schema(obj);

assert.jsonSchemaFile(path, schema,?msg);
assert.notJsonSchemaFile(path, schema, ?msg);
  • file().with.json 后链接
  • schema 参数必须是有效的 JSON-Schema v4。
  • 依赖于 chai-json-schema 插件,需要使用 chai.use() 单独激活。
  • 要使用 expect/should 否定它,你需要在常规的 json 后链接 .not 否定。
  • withusing 链只是语法糖。

计划中的断言

这里保存了一些关于未来断言的想法 在此文档中.

历史

  • 0.1.0 - 添加了 content.match 功能(感谢 @legendary-mich)
  • 0.0.2 - 插件发布
  • 0.0.1 - Alpha 版发布

贡献

欢迎贡献。请遵循代码、测试和样式模式,并确保 JSHint 满意。请确保所有平台都能正常工作,或者至少在 Widows/Mac/Linux 上正常工作。

构建和测试

在您的 git 检出中安装开发依赖项

$ npm install

您需要全局的 grunt 命令

$ npm install grunt-cli -g

构建并运行测试

$ grunt

查看 Gruntfile 以获取其他命令。

:wrench: 测试生成器

此插件使用“断言插件测试生成器”的原型来为断言的所有方面生成测试,同时保持规格 DRY。

该模式将测试拆分为样式声明树和三种类型测试场景的变体。然后生成器将每个场景变体与样式树数据组合(“相乘”)以获得对所有情况的良好覆盖率。

样式树定义了使用断言的方式:第一级是样式:expect/should 和 assert。然后它定义了正常使用和否定,然后将它们划分为每种样式的不同调用模式。因此,您可以使用/不使用消息进行测试,或者作为链式方法或属性等等。

测试是指定断言和测试预期的方式。

  • valid - 预期通过的测试(但否定失败)。
  • invalid - 预期失败的测试(但否定通过)。
  • error - 预期始终失败的测试(即使否定时也是如此),因为数据无效(例如:数据类型错误、参数缺失等等)。

report 字段用于验证测试失败时的错误消息。它支持使用断言数据对象进行简单的模板格式。

为什么?

这看起来有点复杂和繁琐,但它确实允许快速添加大量详细的测试以进行所有断言。到目前为止,它似乎运行良好,因此我可能稍后将其提取到单独的 npm 模块中。

请注意,它将生成大量的用例变体,因此代码或测试设置中的一个小错误可能会导致测试套件爆炸,并产生许多失败的断言。仔细观察哪些测试失败,以了解导致什么。

许可证

版权所有 (c) 2013 Bart van der Schoor

根据 MIT 许可证授权。