Esse teste:
it('returns the correct value', function(done) {
var returnValue = 5;
aPromise.then(function() {
expect(returnValue).to.equal(42);
done();
});
});
Este teste falha com timeout of 2000ms exceeded
vez de erro de declaração. Acho que é porque a chamada expect()
gera um erro e o done()
nunca é executado, e estou me perguntando se há uma maneira melhor de testar esse tipo de código.
aPromise
resolve alguma vez? Do contrário, não há muita escolha a não ser lançar um tempo limite.
@NickHeiner Sim, resolve; e então expect()
descobre que returnValue
não é equal(42)
e arremessa.
@gurdiga como saber se você obtém um tempo limite e não um erro de asserção?
@hallas @NickHeiner Aqui está o que está em execução: http://jsfiddle.net/gurdiga/p9vmj/.
@gurdiga parece-me que sua promessa tem seu próprio erro de captura. Tente adicionar .catch(done)
à sua promessa e acho que funcionará conforme o esperado.
@hallas Wow: _that_ foi a resposta! :) aPromise.finally()
parece ser o ajuste perfeito para colocar done
: ele também precisa ser chamado quando a promessa for resolvida. ;)
Obrigado!
Eu me sinto estúpido.
Acho que finalmente entendi: quando algo joga em qualquer uma das funções do manipulador da promessa, seja aquela passada para .then()
, para .catch()
ou para .finally()
, o erro é manipulado pela biblioteca de promessa. Dessa forma, o executor de teste nunca vê o erro real, o done()
nunca é chamado (porque algo antes dele gerou um erro de asserção) e, portanto, o erro de tempo limite é tudo o que você obtém do executor de teste.
Para sair da promessa, eu uso setTimeout()
:
it('returns the correct value', function(done) {
var returnValue = 5;
aPromise.then(function() {
setTimeout(function() {
expect(returnValue).to.equal(42);
done();
});
});
});
Descobri que esta é a única maneira de obter mensagens de erro adequadas e testar o comportamento do executor.
Com done
passado para .catch()
ou .finally()
o teste é considerado aprovado em qualquer caso, portanto, se houver erros de asserção, você nunca os verá.
Eu encontrei um problema semelhante e finalmente percebi que você não deveria usar done ao testar funções assíncronas com promessas, em vez disso, apenas retorne a promessa. Portanto, você deve ser capaz de fazer isso sem o tempo limite, por exemplo:
it('returns the correct value', function() {
var returnValue = 5;
return aPromise.then(function() {
expect(returnValue).to.equal(42);
});
});
Acho que esse problema ainda existe. Estou recebendo um problema de tempo limite que não pode ser resolvido retornando uma promessa porque meu módulo não usa promessas.
it("works", function(done) {
new Something()
.on("eventA", function(result) {
expect(result).to.be.true;
})
.on("eventB", function(result) {
expect(result).to.be.false;
done();
});
});
Promise
parece excessivo.try
/ catch
também parece excessivo e, mais importante, resulta em Error: done() called multiple times
.Ideias:
http://staxmanade.com/2015/11/testing-asyncronous-code-with-mochajs-and-es7-async-await/
No que diz respeito às recomendações da postagem do blog, não sei sobre o tratamento de erros de função assíncrona, mas para promessas simples, a recomendação try-catch é estranha: a tentativa de promessa original sem try-catch estava quase correta, bastava usar .catch(done)
vez de usar o segundo parâmetro para then
como done
. (Concedido, como o Mocha tem suporte direto para promessas, você também pode simplesmente devolver a promessa, mas valha a pena ...) O problema no exemplo de promessa inicial não era a ausência de try-catch, era que o segundo manipulador to then
não é chamado com exceções lançadas pelo primeiro manipulador, enquanto um catch
é; Não sei qual era o motivo para as promessas serem elaboradas dessa forma, mas é assim que as promessas são. Além disso, se houvesse vários then
s por algum motivo, apenas um único .catch(done)
final seria necessário, o que é um ponto de superioridade sobre o try-catch dentro dos manipuladores (no topo do fato de que .catch(done)
é menos clichê para começar).
Quanto à sua API:
.on("error", function(error) {...})
), então eles nunca chegarão ao Mocha a menos que você os escute e tenha o ouvinte chamar done
com o erro (ou apenas usar done
com o ouvinte se o ouvinte receber o erro como seu primeiro parâmetro, por exemplo, .on("error", done)
. Presumivelmente, isso também apenas precisa ser escrito uma vez por teste, em vez de uma vez por manipulador de eventos, como .catch(done)
em uma promessa."end"
/ "drain"
para verificar se os booleanos nos outros eventos foram definidos.Ainda não sei como sua API deve relatar erros.
Sim, até agora tenho confiado nos tempos limites para _quando_ algo falha e, em seguida, cavando manualmente para descobrir _como / por quê_. Felizmente, raramente as coisas quebram, mas isso não é desculpa para a falta de um design melhor (da minha parte, principalmente).
@stevenvachon : Perdoe-me antecipadamente, mas não vejo um problema imediato com seu exemplo. As afirmações feitas em seus ouvintes de evento devem ser tratadas pelo Mocha por meio do mapeamento uncaughtException
(a menos que a implementação do emissor de evento esteja capturando erros de ouvinte e emitindo um evento error
ou algo assim, que ainda é fácil de resolver).
Agora, se sua implementação nos bastidores está usando Promises, mas emite eventos em vez de expor a Promessa, suas afirmações serão realmente "comidas". A maneira de contornar esse problema é usar unhandledRejection
.
Normalmente coloco isso em um script de configuração que é executado antes dos meus testes:
process.on('unhandledRejection', function (reason)
{
throw reason;
});
Nota: Isso pode precisar de um pouco de graxa de cotovelo extra para funcionar nos navegadores.
Espero ver o Mocha suportar isso como uncaughtException
pois este é um caso de uso comum; só porque uso Promises não significa que quero devolvê-las ao chamador!
Tendo o mesmo problema com [email protected]
it('Convert files into base64', (resolve) => {
let files = Promise.all(promises);
return files
.then(([actual, expected]) => {
assert.equal(actual, expected, 'Files not are equal');
resolve();
})
.catch(error => resolve);
});
Error: timeout of 2000ms exceeded. Ensure the done() callback is being called in this test.
O .catch
está errado. error => resolve
é equivalente a function(error) { return resolve }
, o que significa que resolve
não será chamado e o erro será ignorado. O que você quer é chamar resolve
com o erro, que seria error => resolve(error)
. Claro, passar uma função de retorno de chamada X
que simplesmente chama a função Y
com os mesmos argumentos com os quais X
é chamada é equivalente a apenas passar Y
como o callback, então mesmo .catch(error => resolve(error))
poderia ser simplificado para .catch(resolve)
. (Você só precisaria não passar resolve
diretamente se o estivesse passando para then
e, portanto, precisava evitar passar o parâmetro de resultado de then
para resolve
para evitar que seja tratado como um erro: then(()=>resolve())
vez de apenas .then(resolve)
; mas como você está usando o retorno de chamada then
para as afirmações, isso não aparece .)
(Além disso, linguisticamente, resolve
aqui provavelmente deve ser nomeado algo na linha de done
, uma vez que lida com o sucesso e o fracasso e julga que é baseado em se foi chamado com um argumento ou não. Daí o nome na mensagem de erro de Mocha. Mas isso pode ser um ponto discutível; continue a ler.)
No entanto, neste caso, você pode simplificar ainda mais apenas retornando a promessa e não usando o parâmetro de teste concluído, já que o Mocha irá esperar que a promessa seja bem-sucedida ou falhe, indicando sucesso ou falha do teste (desde que não haja nenhum parâmetro feito para a função de teste; o comportamento no caso de ambos serem usados ainda está sendo hash):
it('Convert files into base64', () => {
let files = Promise.all(promises);
return files
.then(([actual, expected]) => {
assert.equal(actual, expected, 'Files not are equal');
})
});
@lsphillips que funciona para mim. Obrigado!! Espero ver o mocha suportar isso por padrão também. Acabei de criar # 2640.
Levei um tempo para resolver isso! Com base nas respostas acima , estas são as duas opções:
npm install --save mocha expect.js q
./node_modules/mocha/bin/mocha test.spec.js
// test.spec.js
var $q = require('q');
var expect = require('expect.js');
describe('tests with done', function(){
it('returns the correct value from promise', function(done) {
var returnValue = 5;
var def = $q.defer();
def.promise.then((val) => {
expect(val).to.equal(42);
done();
}).catch(done);
def.resolve(returnValue)
});
})
describe('tests returning promises', function(){
it('returns the correct value from promise', function() {
var returnValue = 5;
var def = $q.defer();
def.resolve(returnValue)
return def.promise.then((val) => {
expect(val).to.equal(42);
});
});
})
tests with done
1) returns the correct value from promise
tests returning promises
2) returns the correct value from promise
0 passing (15ms)
2 failing
1) tests with done returns the correct value from promise:
Error: expected 5 to equal 42
at Assertion.assert (node_modules/expect.js/index.js:96:13)
at Assertion.be.Assertion.equal (node_modules/expect.js/index.js:216:10)
at def.promise.then (tests/test.spec.js:9:24)
at _fulfilled (node_modules/q/q.js:854:54)
at self.promiseDispatch.done (node_modules/q/q.js:883:30)
at Promise.promise.promiseDispatch (node_modules/q/q.js:816:13)
at node_modules/q/q.js:570:49
at runSingle (node_modules/q/q.js:137:13)
at flush (node_modules/q/q.js:125:13)
at _combinedTickCallback (internal/process/next_tick.js:67:7)
at process._tickCallback (internal/process/next_tick.js:98:9)
2) tests returning promises returns the correct value from promise:
Error: expected 5 to equal 42
at Assertion.assert (node_modules/expect.js/index.js:96:13)
at Assertion.be.Assertion.equal (node_modules/expect.js/index.js:216:10)
at def.promise.then (tests/test.spec.js:22:24)
at _fulfilled (node_modules/q/q.js:854:54)
at self.promiseDispatch.done (node_modules/q/q.js:883:30)
at Promise.promise.promiseDispatch (node_modules/q/q.js:816:13)
at node_modules/q/q.js:570:49
at runSingle (node_modules/q/q.js:137:13)
at flush (node_modules/q/q.js:125:13)
at _combinedTickCallback (internal/process/next_tick.js:67:7)
at process._tickCallback (internal/process/next_tick.js:98:9)
@gurdiga Obrigado pela ideia setTimeout ()! Tive um problema semelhante, mas agora posso obter pelo menos as mensagens de erro adequadas!
No meu cenário, usei o Nightmare para finalizar os testes. A solução para mim foi usar .catch(done)
. Você pode chamar done(error)
dentro de outro retorno de chamada catch como o exemplo abaixo.
describe('Clicking in any bad reputation tag', () => {
it('open the bad reputation modal', (done) => {
nightmare
.select('#per-page', '50')
.waitForAjax()
.click('[data-reputation="bad"]')
.evaluate(function() {
return document.querySelector('.vue-modal .ls-modal-title').innerText
})
.then(function(title) {
title.should.equal('Sua segmentação teve uma avaliação ruim!')
done()
})
.catch((error) => {
screenshot(nightmare)
done(error)
})
})
})
@itumoraes que funciona, mas você pode fazer isso:
describe('Clicking in any bad reputation tag', () => {
it('open the bad reputation modal', () => {
return nightmare
.select('#per-page', '50')
.waitForAjax()
.click('[data-reputation="bad"]')
.evaluate(function() {
return document.querySelector('.vue-modal .ls-modal-title').innerText
})
.then(function(title) {
title.should.equal('Sua segmentação teve uma avaliação ruim!')
})
})
})
Você não precisa ligar para done()
se retornar uma promessa. Veja minha postagem no blog Usando Async / Await com Mocha, Express e Mongoose
Usei o script abaixo, mas obtive o mesmo erro de ultrapassagem de tempo limite.
Myscript:
describe ("getBillingDetail", função assíncrona () {
this.timeout (55000);
it.only ("verificar nome de trabalho válido fornecido", função assíncrona (concluído) {
this.timeout (55000);
var result = await url.getBillingDetail ('12254785565647858');
console.log (resultado);
assert.equal (resultado, verdadeiro);
});
});
Erro: Tempo limite de 55.000 ms excedido. Para testes assíncronos e ganchos, certifique-se de que "done ()" seja chamado; se retornar uma promessa, certifique-se de que resolve.
Pare de soletrar a mesma coisa em vários fascículos encerrados. Não passe um retorno de chamada concluído para funções assíncronas. Leia a documentação sobre testes assíncronos
@Munter eu removi o retorno de chamada concluído, mas esses erros ocorrem novamente
Parece que sua promessa nunca foi resolvida.
Comentários muito úteis
Eu encontrei um problema semelhante e finalmente percebi que você não deveria usar done ao testar funções assíncronas com promessas, em vez disso, apenas retorne a promessa. Portanto, você deve ser capaz de fazer isso sem o tempo limite, por exemplo: