如何让 Mocha 加载定义全局挂钩或实用程序的 helper.js 文件?

How can I make Mocha load a helper.js file that defines global hooks or utilities?

我有一个名为 test/helper.js 的文件,我用它来 运行 在我的 Node.js 应用程序上进行 Mocha 测试。我的测试结构如下:

test/
test/helper.js    # global before/after
test/api/sometest.spec.js
test/models/somemodel.spec.js
... more here

必须加载文件 helper.js,因为它包含我的测试套件的全局挂钩。当我 运行 Mocha 像这样执行整个测试套件时:

mocha --recursive test/

helper.js 文件在我的测试之前加载,我的 before 挂钩按预期执行。

但是,当我运行只是一个特定的测试时,helper.js在测试之前没有加载。我是这样 运行 的:

mocha test/api/sometest.spec.js

没有调用全局 before,甚至没有调用 console.log('I WAS HERE');

那么我怎样才能让 Mocha 总是 加载我的 helper.js 文件?

Mocha 没有任何名为 helper.js 的特殊文件的概念,它会在其他文件之前加载。

当您 运行 mocha --recursive 时,由于 Mocha 发生 加载文件的顺序,您尝试做的事情会起作用。因为helper.js比其他文件高一级,所以先载入。当您将单个文件指定给 Mocha 时,Mocha 只会加载 这个文件 ,而正如您所发现的,您的 helper.js 文件根本没有加载。

所以你想要做的是加载一个文件,这样它将设置顶级 ("global") 挂钩(例如 beforeafter 等)。选项:

  1. 您可以使用 Mocha programmatically 并按照您想要的顺序向其提供文件。

  2. 您可以强迫自己始终在命令行 first 上指定您的帮助程序文件,然后再列出任何其他文件。 (我不会这样做,但这是可能的。)

  3. 另一种选择是按照我在 this answer 中详述的方式组织您的套件。基本上,您有一个 "top level" 文件,可以将套件的其余部分加载到其中。使用这种方法,您将失去 运行ning Mocha 对单个文件的能力,但您可以使用 --grep 到 select 正在 运行.

不能使用-r选项。它在 运行 安装套件之前加载了一个模块,但不幸的是,加载的模块无法访问 Mocha 为您的测试提供的任何测试接口,因此它无法设置挂钩。

我所做的是创建一个 test/test_helper.js 文件,导出我创建的所有助手:

// test/test_helper.js    
module.exports = {
    MyHelper: require('./helpers/MyHelper')
}

然后我 require 我需要在任何测试中使用它的助手:

// test/spec/MySpec.js
var helper = require('../test_helper');

// Or if you need just "MyHelper"
var myHelper = require('../test_helper').MyHelper;

describe('MySpec', function () {
   // Tests here...
});

我更喜欢上面的方法,因为它易于理解且灵活。您可以在我的演示中看到它的实际效果:https://github.com/paulredmond/karma-browserify-demo/tree/master/test

首先,我肯定会使用 mocha.opts 这样您就不必每次都包含所需的选项。正如所指出的,一种选择是使用 --grep,但我个人并不十分喜欢它。它要求您以过于简单的方式命名所有内容。如果 before 挂钩不是异步的,您可以在 mocha.opts 中使用 --require。例如

#mocha.opts
--recursive
--require test/helpers.js

听起来这对您不起作用,因为您还需要全局 after 挂钩。我所做的是每次都调用完整的测试套件,但如果我在开发过程中只想测试一个套件,甚至是一个特定的测试,我会使用排他性功能,only https://mochajs.org/#exclusive-tests。您可以将其设置为 it.only('...describe.only('... 如果您这样做,它会查看所有测试并像您的完整测试工具一样进行设置,但随后只会执行您指定的测试或套件。

现在您可以毫无问题地包含那些全局挂钩。 @Louis 提到您的 helpers.js 只是巧合地以正确的顺序加载。那不是真的。如果将任何挂钩放在 describe 块之外,它会自动成为全局挂钩。这可以通过将其放在自己的文件中来完成

// helpers.js
before(function() { console.log('testing...'); });

或在测试文件中

// some.spec.js
before(function() { console.log('testing...'); });

describe('Something', function() {
  it('will be tested', function() {
  ...
  });
});

显然,我认为将它放在自己的文件中更干净。 (我称之为 hooks.js)。重点是,这不是文件加载顺序的结果。

只是一个对其他人来说可能很明显的陷阱,但我曾短暂地挣扎过 -- 未放置在 describe 块中的钩子都是全局的。它们不是特定于目录的。因此,如果您将 helpers.js 复制到测试的子目录中,beforeafter 挂钩现在将触发两次。此外,如果您在其中放置一个 beforeEach 挂钩,它将在每次测试之前触发,而不仅仅是该目录中的那些测试。

无论如何,我知道这个 post 有点旧,但希望这能帮助其他有类似问题的人。

在尝试了各种方法让我的测试连接到数据库之后,我才想到这个问题,然后 运行 在我的 models 上进行了一堆 crud 测试。

然后我发现 mocha-prepare 解决了我的问题。

在您的 helper.js 文件中,您可以只定义一个 prepare 函数。

prepare(done => {
  console.log('do something asynchronously here')
  done()
}, done => {
  console.log('asynchronously clean up after here')
  done()
})

工作愉快。

在我们的项目中,我们使用的助手有点像这样:

clientHelper = require("../../../utils/clientHelper")

您需要正确配置助手的相对路径。

然后这样调用它:

clientHelper.setCompanyId(clientId)

迟到的答案补充:-

Mocha(撰写本文时为 v7.0.0)支持指定 file 作为选项:-
根据 docs

  --file               Specify file(s) to be loaded prior to root suite
                       execution 

.mocharc.json


{
    "watch-files": [
       "test/**/*.js"
    ],
    "recursive": true,
    "file": "test/setup"
}

./test/setup.js

const request = require('supertest');
const app = require('../app'); // express app
global.request = request(app);

值得一提:

我发现上面的设置加载了所有 .js 文件,可能是因为 mocha 配置 extension 默认设置为 js。由于我有使用 .spec.js 命名所有测试文件的约定,我可以通过添加 "ignore": ["test/**/!(*.spec.js)"]

来忽略其他文件