Mocha: 错误:解决方法指定过多。

创建于 2016-08-02  ·  84评论  ·  资料来源: mochajs/mocha

这个:

before(done => {
    return Promise
        .all([])
        .then(() => Model.insert(...)) // Bookshelf model returning a Bluebird Promise
        .then(() => done())
        .catch(done)
})

将导致错误Error: Resolution method is overspecified. Specify a callback *or* return a Promise; not both.

文件说:

在Mocha v3.0.0和更高版本中,返回Promise并调用done()将导致异常,因为通常这是一个错误:

模型调用使用新插入的条目的Promise.<Object>进行解析,但是,如果我忽略了.then(() => done())则测试超时。

confirmed-bug

最有用的评论

具有done async函数(babel)也会中断。

所有84条评论

具有done async函数(babel)也会中断。

如错误所示,您不应该提供Arity> 0(意味着它正在接受done回调)的函数,_and_返回Promise。

解决此问题的最简单方法是忽略return ,但是由于您使用的是Promise,因此建议您改掉done回调,因为这将导致更简单的构造:

before(() => Promise.all([]).then(() => Model.insert(...)));

这是async (本质上是一个承诺)和done都中断的示例:

it('fires change event when calling blah.doSomethingThatFiresChange', async function (done) {
  const blah = await getBlah()
  blah.on('change', () => done())
  blah.doSomethingThatFiresChange()
})

@elado这是一个有趣的用例,尽管从mocha的角度来看,情况是一样的-该函数都接受done回调并返回一个promise。 我将其重写为完全基于承诺的:

it('fires change event when calling blah.doSomethingThatFiresChange', async function () {
  const blah = await getBlah()
  return new Promise(resolve => {
    blah.on('change', resolve)
    blah.doSomethingThatFiresChange()
  })
})

...但是我想您在此示例中得到的是,如果mocha等待_both_承诺得到解决和回调被调用会更好?

不幸的是,特定的组合通常是测试中的错误,这就是为什么首先添加此错误消息的原因。

...如果我省略.then(()=> done()),则测试超时。

无论如何,这似乎都是一个错误。

@ScottFreeCode嗯,是的,这似乎是因为在done回调提供的函数中发出了“ overspecified”错误: https :

...但是我们当然可以确定一旦函数返回,我们必须以该错误失败。

@ScottFreeCode这里的解决

我会猜测是“等待诺言解决或拒绝,然后以'overspecified'错误拒绝”?

如果我们要考虑在同一测试中将done加promise视为错误,那么我认为没有任何理由在使用done的测试函数返回a时不检测到该错误。承诺,如@papandreou所建议。 试图弄清楚还有哪些其他点会触发错误,对我来说没有多大意义,除非在某些情况下我们打算同时允许promise和done

@ScottFreeCode我同意。 所以就是

  1. 发现问题; 实例化Error但不要调用done()
  2. 等到承诺实现
  3. 拒绝Error

额外的问题:兑现承诺的结果怎么办?

嗯,我想我明白了-即使我们检测到错误,也需要让测试运行,以便在下一次测试期间它仍未运行其代码,并且也许还可以报告测试结果。

测试是否还可以最终调用done而不解决或拒绝承诺? 如果是这样,那是我们必须处理的另一种情况。

我的倾向,再见。 对测试结果的处理是,如果超时(没有_two_调用done或解决/拒绝了诺言),我们应该仅在诺言中报告done使用(因为对组合的困惑很可能就是为什么它从未到达任何一个并超时)的原因,但是,如果通过任何一种方法都能成功完成,那么结果大概是有效的(或者至少是某种意义上的意义),我们应该报告可能错误地使用了done并一起承诺,并且测试结果希望它至少有所帮助。

无论如何,这是目前我能提出的最好的建议,但是如果我能找到时间深入研究这个问题,我可能会有更多的见识。

好吧,我们可以分阶段进行。 首先是要确保如果返回了Promise并给出了done回调,那么Mocha将以友好的方式中断。

可以想到的是(可以使用Bluebird)是这样的:

// to make this work, you need to omit `return`
it('should do something async for sure', function(done) {
  return somethingAsync()
    .then(makeAssertion)
    .asCallback(done);
});

但这只是您可以做的; 我还没有确定一个用例。

我觉得我很困惑。 我不确定这里是否有错误。

这更多是“ UI差”类型的问题

即使返回的诺言得到解决/拒绝,超时也要等待done调用绝对是一个错误,无论我们是否要在第一个中不使用done和诺言地点。 这应该使用promise和/或错误的结果,因为promise和done都在同一个测试中使用,但不只是超时,因为两个中的一个从未完成,而另一个则没有完成(这目前正在执行的操作):

it("should not time out", function(done) {
  return new Promise(function(resolve, reject) {
    setTimeout(resolve.bind(42), 50)
  })
})

1)不应该超时:
错误:超过2000毫秒超时。 确保此测试中正在调用done()回调。

无论如何我都会看PR ...

有兴趣的人士应观看#2413。

@briansipple

我在版本3中使用多个异步beforeEach钩子得到了相同的错误:

  beforeEach((cb) => connection.db.collection('users').remove({}, cb));
  beforeEach((cb) => connection.db.collection('accounts').remove({}, cb));
  beforeEach((cb) => connection.db.collection('accounts').insertOne(account1, cb));

这样还不能使用异步钩子吗?

我发现了我的问题:每个钩子中的方法都返回promise (我不知道那是因为在那种情况下我没有使用Promise),而且显然我也在传递cb函数。

我认为这不是一个好主意。 如果有人要求回电,我想他们已经明确了意图。 这里的错误只是一个烦人。 请删除它。

这实际上不是意图问题。 根据#1320的描述:

当同时指定了回调函数和Promise对象时
返回时,Runnable的解析条件不明确。

它不是模棱两可的,已请求回调。 big昧如何?

我同意@RobertWHurst在这里没有歧义。

除此之外,我认为这个问题可能是“基于观点的”,开发人员将有不同的观点。 我认为做一个突破性的改变并强迫人们使用这种方式是极端极端的。

我们没有强迫任何人做任何事情。 我们发布了一个专业,根据定义,它将有重大变化。 我们没有中断服务。

我不认为他意味着您破坏了semver,我认为他意味着您破坏了摩卡。 这项更改并没有使开发人员更轻松,而是在执行一种意见。

beforeEach((cb) => connection.db.collection('users').remove({}, cb));
            ^^

^^那不是模棱两可的。 很明显作者期望什么。 作者已竭尽所能请求回调。

实际上,您在此处获得例外的原因是最大程度地避免了执行意见。 Mocha对返回的诺言或回调是否具有权威性没有意见。 您不能同时使用两者,因为这会导致模棱两可的结果。 测试框架中的歧义结果应视为错误。 因此,错误消息可帮助您意识到这一点并做出选择并根据您的意见进行更改。

降低戏剧性可能会有所帮助。 “您打破了摩卡咖啡”并没有帮助任何人。 semver主要版本的增加被明确定义为可能需要您调整代码的重大更改。 您可以继续使用2.x,以便有时间进行更改以修复测试。 这是一个进化,而不是断裂

@Munter我仍然对请求回调的模棱两可感到

如果您正在感知戏剧,我的意思是没有。 “您打破了摩卡咖啡”并不意味着是双曲线的。 我只是认为这违反了模块的设计,并且破坏了原始的api合同。

如前所述,babel async / await在新的mocha @ 3上无法正常工作

it('should fill userName and password', async function (done) {
    const userNameField = global.driver.wait(until.elementLocated({css: '#username'}));
    userNameField.sendKeys('admin');

    const passNameField = global.driver.findElement({css: '#password'});
    passNameField.sendKeys('*******');

    const userNameVal = await userNameField.getAttribute('value');
    const passwordVal = await passNameField.getAttribute('value');

    try {
      assert.equal(userNameVal, 'admin');
      assert.equal(passwordVal, 'changeme');
    } catch (error) {
      done(error);
      return;
    }

    done();
  });

该代码在mocha @ 2上运行良好,但在mocha @ 3上则无效,因为在await它返回promise

我认为此PR与此处有关=> https://github.com/mochajs/mocha/pull/2413
处理此错误的极端情况会更加复杂。

@artyomtrityak这是一个不需要done的好例子。

批评者说了他们的话。 但是,Mocha的维护者不同意用于还原此更改的论点。 埃兰·哈默(Eran Hammer)说(释义):“作为一名维护者,您最难做的一件事情就是让那些希望朝着自己的方向前进的人失望。”

我欢迎采用变通方法-提供更多文档(例如,更多有关此错误的示例以及如何修复它们),更好的错误消息传递-但对戏剧,粗鲁或抱怨不感兴趣。 将这些变通办法提供给Mocha有助于将负面因素变成积极因素。

如果您不喜欢此更改,并且对它不能具有建设性,那就是OSS-您可以派生该项目并在此处还原更改。

@boneskull它将转换为返回promise的异步函数,当promise将实现时,我不需要完成我的测试用例,但需要对结果进行一些自定义检查。 正如我所说的,此代码在mocha @ 2上可以正常工作,但在mocha @ 3上却不能。 因此,由于这个原因,我的团队(〜20ppl)无法使用最新的摩卡咖啡。

当前,mocha 2.x具有很大的灵活性,此更改是否有任何技术原因?

@artyomtrityak这是一个很好的例子,说明不需要做的事情。

您能举一个例子,使用babel async/await语法,不使用return new Promise如何显示?

@artyomtrityak如何完全接受承诺? 然后,您可以将测试缩短为:

it('should fill userName and password', async function () {
    const userNameField = global.driver.wait(until.elementLocated({css: '#username'}));
    userNameField.sendKeys('admin');

    const passNameField = global.driver.findElement({css: '#password'});
    passNameField.sendKeys('*******');

    const userNameVal = await userNameField.getAttribute('value');
    const passwordVal = await passNameField.getAttribute('value');

    assert.equal(userNameVal, 'admin');
    assert.equal(passwordVal, 'changeme');
  });

如果您觉得自己受到了攻击,那么我认为您需要重新考虑自己在这次谈话中的情感投入。 没有评论是个人的。 我相信你们都很棒,尤其是考虑到您已经花了时间来帮助维护这个项目,这是非常值得赞赏和赞赏的。

你们中的大多数人(当前活跃的维护者)于2014年中左右开始在Mocha上工作。 你们已经开始建立Mocha了。 这只是我的意见,但我并不孤单,认为除非有充分理由,否则不应对已建立的库进行重大更改。 尽管我可以想象此更改的原始理由,但是当有人指出以下内容时,它并不能很好地站起来。 要求回调传达了明确的意图。 承诺不是很明确,因为不要求它们,而是将它们返回,这可能是间接和偶然发生的(例如,从第3方库返回)。 由于存在这些差异,两种产生方式并不相等,因此尝试同时使用这两种方式并不是真正的模棱两可。 回调必须写入测试参数中。 您不能凭承诺做到这一点,因此通过请求回调,您已经明确传达了您的意图。 您的社区提出了这些担忧,而你们并没有承认自己的失误,而是加倍努力。 似乎您甚至在考虑强制测试异步以确保此错误一致地发生。 参见=> https://github.com/mochajs/mocha/pull/2413。 似乎对错误消息进行了很大的更改,以防止发生不太可能的错误。

@tj离开以来,你们在维护该库方面做得非常出色,请您多考虑一下此更改。 我担心的是,这可能会损害图书馆。

完全同意@RobertWHurst。

请求done应该覆盖返回的promise行为。 不需要done的可能性不大, async函数中发出事件的场景就是一个很好的例子。

根据我上面的评论:

it('fires change event when calling blah.doSomethingThatFiresChange', async function (done) {
  const blah = await getBlah()
  blah.on('change', () => done())
  blah.doSomethingThatFiresChange()
})

随着越来越多的人转向ES6 / 7 + async / await ,使用Mocha时这将成为常见问题。

请重新考虑此更改。

@RobertWHurst您认为定义done回调是明确意图。 return语句不是明确的意图吗? 两者都由您在代码中定义。 我们如何才能确定您的代码的一部分是故意的而另一部分不是故意的? 如果您想象() => foo之前的世界,那么任何return语句将始终是明确的。 现在,您全力以赴的唯一原因是因为您已经开始使用隐式return语句,而我只能认为是出于美学原因。

鉴于很多Mocha用法是由通常复制/粘贴示例的初学者使用的,这些示例很可能包含done回调,您将如何处理这个新用户显式返回诺言但超时的情况? 如果您疯狂的更改被还原,这就是结果。

当前的行为比出乎意料的超时更清楚什么地方出了问题

@Munterasync函数,我认为无论是否使用await ,返回的promise在显式性评分上都较低,因为它是自动创建和返回的:

it('should work with a async function that could have been sync', async function () {
  assert.ok(true);
});

it('should work with a legitimately async function', async function () {
  assert.equal(await getBlah(), 'blah');
});

it('should work with a fully spelled-out Promise-based test', function () {
  return getBlah().then(function (blah) {
    assert.equal(blah, 'blah');
  });
});

然后是有争议的一个:

it('should foo', async function (done) {
  assert.equal('foo', 'foo');
  done();
});

那小小的async偶然溜进去也很容易,因此@elado指出,我们应该(至少)将第一个示例视为一种新的

经过一番对话=> https://github.com/mochajs/mocha/pull/1320之后,我有了解决该问题的替代解决方案的想法。 我在这里添加了PR,以供您查看乐趣=> https://github.com/mochajs/mocha/pull/2454

:啤酒:

您认为定义完成的回调是明确意图。 退货声明不是明确的意图吗?

@Munter不要忘记coffeescript和es6箭头函数表达式返回_implicitly_,因此您可以执行类似的操作

it 'should foo', (done) -> request('/foo').end (err, res, body) -> done()

并认为你很安全。 但是,这个问题意味着您必须将这种漂亮的单线格式转换为类似

it 'should foo', (done) ->
  request('/foo').end (err, res, body) -> done()
  return

这正是mecano每个代码库的整体问题。 考虑一下:

it 'should foo', (done) ->
  obj =
    run: ->
      done()
      @
    then: -> "what the hell, i'm not a promise"
  obj.run()

这不是完全专门针对coffeescript的,但是返回隐式值会使情况更糟。 Mocha应该检测有效的Promise实例。 另外,也许有一个选项可以禁用此功能。

大家好,
使用以下代码处理此问题;

describe('Page', ->
  describe('/GET home', ->
    it('it SHOULD return the homepage', (done) ->
      chai.request(app).get('/').end((err, res) ->
        res.should.have.status(200)
        res.text.should.be.a('string')
        done()
      )
    )
  )
)

通过遵守承诺链并省略回调done()解决此问题。

describe('Page', ->
  describe('/GET home', ->
    it('it SHOULD return the homepage', ->
      chai.request(app).get('/').then((res) ->
        res.should.have.status(200)
        res.text.should.be.a('string')
      )
    )
  )
)

我希望这对其他遇到类似错误的人有所帮助:smile:

PS :心:摩卡顺子:+1:

编辑根据@Munter的评论删除catch()

@karlbateman谢谢。 不过,您不需要最后一个.catch 。 摩卡将被拒绝的承诺视为错误

@Munter我明白了,谢谢:smiley:

考虑了一下之后,我真的很喜欢等待promise和回调的行为。 实施该计划是否取得了进展?

@ light24bulbs感谢您的反馈! 不,afaik没有人开始从事这一工作,因为这只是我想到的一个想法。 我刚才正在检查是否有关于此想法的其他反馈,在任何情况下它都不起作用等。

使用babel时是否有解决方法?

使用babel时是否有解决方法?

我包装两次:

it("should work", done => {
  (async () => {
    await something;
    done();
  })();
});

@SaschaNaz谢谢,这在v3.2.0中有效:)

6个月后,这个问题仍然阻碍了所有现代js测试...
耻辱

@benfavre感谢您的鼓励性话语,这些话语肯定会激励志愿者承担实施闲暇时间未指定的任何解决方案的责任,而不是与孩子一起玩

@Munter不用担心,我可以帮助确定作为mochajs的新用户时遇到的特定问题。
@SaschaNaz建议将包装两次的解决方案无济于事。

=>完全使用promises可以正常工作。

下次,我想我应该像傻瓜一样“ +1”,这样我就不会受到免费侮辱。
我的信息没有侮辱任何内容,此外,我的说法仍然正确。

大多数人只会选择另一个框架...到现在为止,它已经被async / await打破了,在主站点的任何地方都没有明确的指示,并且cli中没有明确的错误消息。

新年快乐,玩得开心与孩子们一起玩。

寒意...

讨论演变成对done回调和返回的Promise “关注”: https :

闭幕。 参见#2509

万一有些身体还在挣扎...

使用babel时是否有解决方法?

现在,如#2509中所述,有了内置的promise处理程序,我们不必像这样使用wrapping twice hack

it("should work", done => {
  (async () => {
    await something;
    done();
  })();
});

取而代之的是,我们可以简单地这样做:

it("should work", async () => {
  await something;
});

查看此帖子以获取更多详细信息

@ lo-tp
1.)使用babel编译时,此代码有效吗?

it("should work", async () => {
  await something;
});

@SerkanSipahi

  • 是的,为了现在使用async/await语法,我们需要babel的帮助。

不知道我是否遗漏了什么...但是我通过不对Promises使用任何return语句并仅依靠done()解决了这个问题。

这是为我工作的一个例子

  describe('STRIPE CHARGES: Get Charges', () => {
    it('should list customer charges', async () => {
      const charges = await Stripe.getChargesList(customerObj);
      charges.data[0].should.have.property('id');
      charges.data[0].amount.should.have.property('id');
    });
  });

我一直在使用chai.assert的摩卡咖啡4。

起初,我尝试像这样使用done()回调。

it('should throw an error', async function(done) {
  try {
    result = await something('value that causes something() to throw an Error');
    done('failed');
  } catch (e) {
    done();
  }
});

它失败了

Error: Resolution method is overspecified. Specify a callback *or* return a Promise; not both."

该错误导致我在此处进入此页面。 经过漫长的漫长跋涉(我承认我并没有完全理解所有争议),我是否明白我根本不应该对异步调用使用done(),因为它们基于Promised?

如果是这样,当等待await()的调用引发错误并且我期望发生这种情况时,如何使以下测试通过?

it('should throw an error', async function() {
  try {
    result = await something('value that causes something() to throw an Error');
  } catch (e) {
    // how to indicate that this should happen, if I can't call done() to tell mocha?
  }
});

有人可以帮我理解这个特殊情况吗? 我应该使用断言库还是在上面的代码中添加其他内容?

非常感谢。

低级别且容易出错的解决方案:

it('should throw an error', async function() {
  try {
    result = await something('value that causes something() to throw an Error');
    throw new Error('Promise unexpectedly fulfilled');
  } catch (e) {
    // Optionally assert something about e...
  }
});

我会在一周的任何一天使用一个断言库:

const expect = require('unexpected');
it('should throw an error', async function () {
    await expect(something(), 'to be rejected with', 'the error message');
});

或猜猜猜猜猜猜猜猜猜猜猜猜猜猜猜猜

const chai = require('chai');
chai.use(require('chai-as-promised'));
const expect = chai.expect;

it('should throw an error', async function () {
    await expect(something()).to.be.rejectedWith('argh');
});

嗨,大家好,这个与asyncawait搭配使用很好(只是省略了'done()')

describe('New order from landing', function() {
    describe('check new client function', function () {
        it("must check db and return that random client is new", async function () {
            var result = await handler.checkClient(reqNewClient.body)
                expect(result).to.have.property('newclient').equal(true)
            })
    })
})

结果:

降落的新订单
检查新的客户端功能
√必须检查db并返回随机客户端是新客户端
1通过(9毫秒)

@kolykhalov谢谢对我

就我而言,我将异步块包装在try / catch中

it('It should activate a user.', async() => {
        return new Promise((resolve, reject) => {
            try {
                // Get the last activation token from the DB
                let sql = 'select * from activation_tokens order by created_at desc limit 1';
                let res = await DB.query(sql);
                let {token} = res[0];

                server
                    .post('/auth/activate')
                    .send({token})
                    .set('Content-Type', 'application/x-www-form-urlencoded')
                    .expect('Content-Type', /json/)
                    .expect(200)
                    .end((err, res) => {
                        res.body.data.should.contain.keys('message');
                        res.body.data.message.should.equal("Activated");
                        resolve();
                    });
            } catch (e) {
                console.error(e);
            }
        });
    });

升级以避免漏洞。 现在,我必须重写99个测试。 FML

因此,只是要弄清楚问题出在哪里,正如有些人说的那样,您不需要使用doneasync ,这是一个您想同时使用两者的示例。

it('should error on fn', async function(done) {
  try {
    await fn();
  } catch (e) {
    // assert some things here
    done()
  }
});

如果未引发任何错误,则不使用done将使测试通过。 有些人建议使用expect(await fn).to.throw('blah') ,但有时您需要检查的属性多于单层。

我收到此错误,但不小心返回了诺言(超级测试)

it('Should do something', (done) => {
       return supertest(server)
           .get(`/api/endpoint`)
           .set('somekey', 'somevalue')
           .expect(200)
           .then(() => { done(); })
           .catch(done);
});

删除“ return”子句可以解决问题

对于任何为此感到疯狂的人...

这有效:

it("should work", async () => {
  await something;
});

这不是:

it("should work", async (done) => {
  await something;
});

您必须删除done作为参数。

@tamoyal ,是的-正如Elado在2016年8月3日发布的那样。

使用async / await返回一个隐式Promisedone回调用于
CPS为基础的异步,如图所示这里。 Mocha支持这两种功能……但不能同时支持。
自Mocha-3.0版本以来,这已被记录并成为标准行为。

我收到此错误,但不小心返回了诺言(超级测试)

it('should do something', (done) => {
       return supertest(server)
           .get(`/api/endpoint`)
           .set('somekey', 'somevalue')
           .expect(200)
           .then(() => { done(); })
           .catch(done);
});

删除“ return”子句可以解决问题

@victorsferreira ,看来这应该是解决方案...

it('should do something', () => {
  return supertest(server)
    .get(`/api/endpoint`)
    .set('somekey', 'somevalue')
    .expect(200);
});

@tamoyal是的,这让我

@mienaikoe ,这个确切的场景已明确记录在案,您知道...

@plroebuck两件事:

1)记录某些内容与成为npm内省函数功能参数的少数几个库之一有区别。 我可以证明我第一次见到所有朋友时都会进行背景调查,但这仍然很奇怪,除非我有理由并明确告诉他们原因,否则人们仍然会抱怨。

2)文档中有一个缺陷:

在Mocha v3.0.0及更高版本中,返回Promise并调用done()...

这与调用完成无关,而是与指定done作为参数_是否使用它有关。

@mienaikoe

  1. Mocha检查it的第二个参数以查看函数是否存在,并检查其是否确定用户是否添加了回调。 这几乎不能算是自省,通常在JavaScript中使用。
  2. 如果您认为过于模糊,请发送PR来更正文档。

删除完成作为参数对我有用!

之前:

image

之后(工作!)

image

@QauseenMZ ,您的“之前”和“之后”代码之间没有区别。

您也没有兑现诺言。 它不应该像下面这样吗?

  it('should receive successful RPC response', async () => {
    return await getResponse(unitData)
      .then((res) => {
        expect(res).to.have.status(200);
      });
  });

PS。 您的Node回调参数排序很糟糕…… error _always_首先。

@plroebuck感谢您的提及! 我刚刚编辑了。

我没有处理诺言,因为getResponse函数正在返回回调。 这是我获得工作的唯一途径。 getResponse函数如下:

image

这里的错误是第二个参数,仅仅是因为回调getResponse函数正在返回。 请让我知道您对此的想法。 谢谢!

有些部分似乎有点不合逻辑。 为了清楚起见,您使用的是哪个request软件包?
为什么需要返回options对象(您命名为unitData )?

  • obj来自哪里?
  • 为什么会有res.body.errorres.statusCode === 200

PS。 请仅粘贴代码本身而不是代码的图像...

对于任何为此感到疯狂的人...

这有效:

it("should work", async () => {
  await something;
});

这不是:

it("should work", async (done) => {
  await something;
});

您必须删除done作为参数。

@tamoyal您救了我的命<3

这会中断并导致相同的错误:

it('Location Querying Works', async () => {
    await WeatherComponent.pullLocationData();
    Vue.nextTick(()=>{
      expect(WeatherComponent.$el.textContent).contain("Spain")
    })
  })

为了给您快速解决此问题的方法,请将整个测试包装在promise中,并像使用resolve一样使用done

转这个:

it.only("Works with the database", async (done) => {
    let browser = await puppeteer.launch();
    let query = db.collection('lists').where('ownerId', '==', 'UJIXXwynaCj8oeuWfYa8');
    let ct = 0;
    query.onSnapshot(async querySnapshot => {
        if (ct === 0) {
            await addAPurpose(browser, session, sessionSig); // A function with a bunch of Puppeteer code.
            ct++
        } else {
            expect(querySnapshot.size).to.equal(1);
            expect(querySnapshot.docs[0].get().title).to.equal("Understand Mocha");
            done();
        }
        console.log(`Received query snapshot of size ${querySnapshot.size}`);
    }, err => {
        console.log(`Encountered error: ${err}`);
    });
});

到这个:

it.only("Works with the database", async () => {
    const onSnap = new Promise(async (res, rej) => {
        let browser = await puppeteer.launch();
        let query = db.collection('lists').where('ownerId', '==', 'UJIo1gGMueoubgfWfYa8');
        let ct = 0;
        let unsubscribe = query.onSnapshot(async querySnapshot => {
            if (ct === 0) {
                await addAPurpose(browser, session, sessionSig);
                ct++
            } else {
                expect(querySnapshot.size).to.equal(1);
                expect(querySnapshot.docs[0].data().title).to.equal("Evolution");
                // done(); 
                unsubscribe();
                res();
            }
            console.log(`Received query snapshot of size ${querySnapshot.size}`);
        }, err => {
            console.log(`Encountered error: ${err}`);
            rej()
        });
    });
    return onSnap;
});

它像您想要的那样工作。

删除done使我感到惊讶,因为测试一直进行到调用完成为止。 为了更明显地表明done不应与async一起使用,如果传递了done,则异步函数应_immediately_失败。 摩卡咖啡应通过以下方式开始测试:

  1. 查看函数是否异步,以及
  2. 检测done参数。

如果它们都存在,则应该抛出该异常,而不是让我的测试运行直到调用done ,然后对我进行全面评估。 然后错误将建议您将代码包装在另一个Promise中,并像done那样使用resolve。

我知道您可以使用function.prototype.name === "AsyncFunction" 。 那是

if (function.prototype.name === "AsyncFunction && arg1.name === "done") {
  throw new Error("Can't use done with an async function")
}

实现这一点。

在这方面,我几乎是SOL 。 我需要执行异步代码,并且它期望代码永远不会完成执行,所以我不得不使用done。 恼人的一轮回合是将我的异步测试代码包装在一个自我调用的异步函数中,但是将it func保留为同步函数。

解:

it("It shouldn't be like this", function (done) {
    ( async function(){
        var life = require('InfiniteLife');
        var asyncRes = await life.someCoolstuff();
        assert(asyncRes);
        setTimeout( function(){
            done();
        },letsCallItQuitsNow);
    })();
});

具有完成中断功能的异步函数示例。

it('If the credentials exists in the system it should return the token generated against it.', async (done) => {
        let aObj = await admin.createAdmin();
        chai.request(server)
        .post("/authenticate")
        .set("Content-Type", "application/x-www-form-urlencoded")
        .send({username: aObj.login,password:aObj.password})
        .end((err, res) => {
            res.should.have.status(200);
            res.body.should.be.a("string");
            done();
        });
    });

成功案例

it('If the credentials exists in the system it should return the token generated against it.', async () => {
        let adminObj = await admin.createAdmin();
        chai.request(server)
        .post("/auth/login")
        .set("Content-Type", "application/x-www-form-urlencoded")
        .send({username: adminObj.login,password:adminObj.password})
        .end((err, res) => {
            res.should.have.status(200);
            res.body.should.be.a("string");
            // done();
        });
    });

Ha

您不需要在测试中使用doneasync 。 柴http返回了一个承诺。 如果您返回承诺,则Mocha的测试将使用异步代码。

it('If the credentials exists in the system it should return the token generated against it.', () => {
  let adminObj = await admin.createAdmin();
  return chai.request(server)
    .post("/auth/login")
    .set("Content-Type", "application/x-www-form-urlencoded")
    .send({username: adminObj.login,password:adminObj.password})
    .end((err, res) => {
      res.should.have.status(200);
      res.body.should.be.a("string");
    });
});

@NateZimmer

您发布的解决方案用于在测试花费太长时间的情况下使测试超时。 Mocha已经内置了

it("It should be liek this", async function () {
  this.timeout(letsCallItQuitsNow);

  var life = require('InfiniteLife');
  var asyncRes = await life.someCoolstuff();
  assert(asyncRes);
});

如果超过了超时,您的示例似乎也不会通过测试,因此请谨慎考虑它的正确性

`使用express / js和firebase云功能,检查api错误响应,然后获取令牌并重试。 确保如果使用express,则返回.json而不是.send,还可以与Mocha一起使用记录器错误,因此请使用普通console.log。
确保您使用异步并完全完成发出

  process.env.NODE_ENV='TESTING';
  const { FIREBASE_UID } = require('dotenv').config()?.parsed;
  const { red, green, white } = require('chalk');
  const chai = require('chai');
  const chaiHttp = require('chai-http');
  const server = require('../lib/api').API;
  const should = chai.should();
  const expect = chai.expect;
  chai.use(chaiHttp);
  const test = chai.request(server).keepOpen();

  const shouldPrint = (details, status) => {
      return white(`details: ${details}, status: ${status}`);
  };

describe('Authorization Middleware Error Check for bad token', () => {

    it(shouldPrint('Bad Request', red(400)), async () => {
        try {
            const res = await test.get('/').send()
            res.should.have.status(400);
            res.should.have.json
            const { details, status } = JSON.parse(res.text)
            expect(details).to.equal('Bad request')
            expect(status).to.equal(400)
        } catch (error) { 
            throw error 
        }
    })


    it(shouldPrint('Unauthorized', red(401)), async () => {
        try {
            const res = await test.get('/').set('Authorization', 'Bearer bad123token').send()
            res.should.exist
            res.should.have.status(401);
            res.should.have.json
            const { details, status } = JSON.parse(res.text)
            expect(details).to.equal('Unauthorized')
            expect(status).to.equal(401) 
        } catch (error) {
            throw error
        }
    })

})

 describe('Get token and ping', () => {
    let adminToken

    it(shouldPrint( 'Create custom jwt for testing', green(200)), async () => {
        try {
            const res = await test.get(`/createToken/${FIREBASE_UID}`).send()
            res.should.exist
            res.should.have.status(200);
            res.should.have.json
            adminToken = (JSON.parse(res.text)).token
        } catch (error) {
            throw error
        }
    })

    it(shouldPrint('PING', green(200)), async () => {
        try {
            const res = await test.get('/')
                .set('x-tenorders-testing', 'true')
                .set('Authorization', `Bearer ${adminToken}`).send()

            res.should.exist
            res.should.have.status(200);
            res.should.have.json
            const { details, status } = JSON.parse(res.text)
            expect(details).to.equal('PING')
            expect(status).to.equal(200)
        } catch (error) {
            throw error
        }   
    })

})
`

此页面是否有帮助?
0 / 5 - 0 等级