Więc testuję komponent, który opiera się na emiterze zdarzeń. Aby to zrobić, wymyśliłem rozwiązanie wykorzystujące Promises z Mocha + Chai:
it('should transition with the correct event', (done) => {
const cFSM = new CharacterFSM({}, emitter, transitions);
let timeout = null;
let resolved = false;
new Promise((resolve, reject) => {
emitter.once('action', resolve);
emitter.emit('done', {});
timeout = setTimeout(() => {
if (!resolved) {
reject('Timedout!');
}
clearTimeout(timeout);
}, 100);
}).then((state) => {
resolved = true;
assert(state.action === 'DONE', 'should change state');
done();
}).catch((error) => {
assert.isNotOk(error,'Promise error');
done();
});
});
Na konsoli otrzymuję komunikat „UnhandledPromiseRejectionWarning”, mimo że wywoływana jest funkcja odrzucania, ponieważ natychmiast wyświetla komunikat „AssertionError: Promise error”
(node: 25754) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 2): AssertionError: Promise error: oczekiwano, że {Object (message, showDiff, ...)} będzie fałszywy 1) powinien przejść z poprawnym zdarzeniem
A potem po 2 sekundach otrzymuję
Błąd: przekroczono limit czasu 2000 ms. Upewnij się, że wywołanie zwrotne done () jest wywoływane w tym teście.
Co jest jeszcze dziwniejsze, odkąd wykonano wywołanie zwrotne catch (myślę, że z jakiegoś powodu niepowodzenie potwierdzenia uniemożliwiło resztę wykonania)
Zabawne jest to, że jeśli skomentuję, assert.isNotOk(error...)
test przebiega dobrze bez żadnego ostrzeżenia w konsoli. Wciąż „zawodzi” w tym sensie, że wykonuje złapanie.
Ale nadal nie mogę z obietnicą zrozumieć tych błędów. Czy ktoś może mnie oświecić?
Odpowiedzi:
Problem jest spowodowany tym:
.catch((error) => { assert.isNotOk(error,'Promise error'); done(); });
Jeśli asercja się nie powiedzie, zgłosi błąd. Ten błąd spowoduje, że nikt
done()
nie zostanie wywołany, ponieważ wcześniej kod był błędny. To właśnie powoduje upływ czasu.„Unhandled odrzucenie obietnica” jest również spowodowane nieudanym twierdzenie, ponieważ jeśli zostanie zgłoszony błąd w
catch()
procedurze obsługi, a nie jest kolejnymcatch()
obsługi , błąd będzie się połknięciu (jak wyjaśniono w tym artykule ).UnhandledPromiseRejectionWarning
Ostrzegawczy informujący o tym fakcie.Ogólnie rzecz biorąc, jeśli chcesz przetestować kod oparty na obietnicy w Mocha, powinieneś polegać na tym, że sama Mocha może już obsługiwać obietnice. Nie powinieneś używać
done()
, ale zamiast tego zwróć obietnicę z testu. Mocha sama wyłapie wszelkie błędy.Lubię to:
it('should transition with the correct event', () => { ... return new Promise((resolve, reject) => { ... }).then((state) => { assert(state.action === 'DONE', 'should change state'); }) .catch((error) => { assert.isNotOk(error,'Promise error'); }); });
źródło
catch
obsługi powinien prawdopodobnie zostać przekazany jako drugi argument dothen
. Jednak nie jestem do końca pewien, jaki był zamiar PO, więc zostawiłem go tak, jak jest.done.fail('msg')
w tym przypadku.Otrzymałem ten błąd przy kiciu z sinonem.
Rozwiązaniem jest użycie pakietu npm sinon-zgodnie z obietnicą podczas rozwiązywania lub odrzucania obietnic z kodami pośredniczącymi.
Zamiast ...
sinon.stub(Database, 'connect').returns(Promise.reject( Error('oops') ))
Posługiwać się ...
require('sinon-as-promised'); sinon.stub(Database, 'connect').rejects(Error('oops'));
Istnieje również metoda rozstrzygania (zwróć uwagę na s na końcu).
Zobacz http://clarkdave.net/2016/09/node-v6-6-and-asynchronously-handled-promise-rejections
źródło
Biblioteki asercji w Mocha działają, generując błąd, jeśli asercja nie jest poprawna. Zgłoszenie błędu powoduje odrzucenie obietnicy, nawet jeśli zostanie zgłoszona w funkcji wykonawczej dostarczonej do
catch
metody..catch((error) => { assert.isNotOk(error,'Promise error'); done(); });
W powyższym kodzie obiekt, którego
error
obiekcje są szacowane,true
więc biblioteka potwierdzeń zgłasza błąd ... który nigdy nie jest przechwytywany. W wyniku błędudone
metoda nigdy nie jest wywoływana.done
Callback Mocha akceptuje te błędy, więc możesz po prostu zakończyć wszystkie łańcuchy obietnic w Mocha za pomocą.then(done,done)
. Gwarantuje to, że gotowa metoda jest zawsze wywoływana, a błąd byłby zgłaszany w taki sam sposób, jak wtedy, gdy Mocha przechwytuje błąd asercji w kodzie synchronicznym.it('should transition with the correct event', (done) => { const cFSM = new CharacterFSM({}, emitter, transitions); let timeout = null; let resolved = false; new Promise((resolve, reject) => { emitter.once('action', resolve); emitter.emit('done', {}); timeout = setTimeout(() => { if (!resolved) { reject('Timedout!'); } clearTimeout(timeout); }, 100); }).then(((state) => { resolved = true; assert(state.action === 'DONE', 'should change state'); })).then(done,done); });
I dać kredyt do tego artykułu na pomysł wykorzystania .Następnie (zrobione, zrobione) podczas testowania obietnic w Mocha.
źródło
Dla tych, którzy szukają błędu / ostrzeżenia
UnhandledPromiseRejectionWarning
poza środowiskiem testowym, może to być prawdopodobnie spowodowane tym, że nikt w kodzie nie zajmuje się ostatecznym błędem w obietnicy:Na przykład ten kod pokaże ostrzeżenie zgłoszone w tym pytaniu:
new Promise((resolve, reject) => { return reject('Error reason!'); });
(node:XXXX) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): Error: Error reason!
a dodanie
.catch()
lub obsługa błędu powinno rozwiązać ostrzeżenie / błądnew Promise((resolve, reject) => { return reject('Error reason!'); }).catch(() => { /* do whatever you want here */ });
Lub używając drugiego parametru w
then
funkcjinew Promise((resolve, reject) => { return reject('Error reason!'); }).then(null, () => { /* do whatever you want here */ });
źródło
new Promise((resolve, reject) => { return reject('Error reason!'); })
ale w funkcji,function test() { return new Promise((resolve, reject) => { return reject('Error reason!'); });}
więc wewnątrz funkcji nie musimy używać,.catch()
ale aby skutecznie obsługiwać błędy, wystarczy użyć podczas wywoływania tej funkcjitest().catch(e => console.log(e))
lub wersji async /try { await test() } catch (e) { console.log(e) }
Zmierzyłem się z tym problemem:
To był mój błąd, wymieniłem
res
obiekt wthen(function(res)
, więc zmienionyres
na wynik i teraz działa.Źle
module.exports.update = function(req, res){ return Services.User.update(req.body) .then(function(res){//issue was here, res overwrite return res.json(res); }, function(error){ return res.json({error:error.message}); }).catch(function () { console.log("Promise Rejected"); });
Korekta
module.exports.update = function(req, res){ return Services.User.update(req.body) .then(function(result){//res replaced with result return res.json(result); }, function(error){ return res.json({error:error.message}); }).catch(function () { console.log("Promise Rejected"); });
Kod serwisowy:
function update(data){ var id = new require('mongodb').ObjectID(data._id); userData = { name:data.name, email:data.email, phone: data.phone }; return collection.findAndModify( {_id:id}, // query [['_id','asc']], // sort order {$set: userData}, // replacement { "new": true } ).then(function(doc) { if(!doc) throw new Error('Record not updated.'); return doc.value; }); } module.exports = { update:update }
źródło
Oto moje doświadczenie z E7 async / await :
W przypadku, gdy masz połączenie
async helperFunction()
z testu ... (async
mam na myśli jedno ze słowem kluczowym ES7 )→ upewnij się, że tak
await helperFunction(whateverParams)
też nazywasz (cóż, tak, oczywiście, kiedy już wiesz ...)Aby to zadziałało (aby uniknąć „await jest słowem zastrzeżonym”), funkcja testowa musi mieć zewnętrzny znacznik asynchroniczny:
it('my test', async () => { ...
źródło
await helperFunction(...)
.async
Zwraca obietnicę. Możesz po prostu obsłużyć zwróconą obietnicę, tak jak zrobiłbyś to na funkcji nieoznaczonej,async
która tak się składa, że zwraca obietnicę. Chodzi o to, aby dotrzymać obietnicy, kropka.async
Nie ma znaczenia, czy funkcja jest, czy nie.await
jest tylko jednym z wielu sposobów dotrzymania obietnicy.UnhandledPromiseRejectionWarning
dla mnie… stąd ta odpowiedź.Miałem podobne doświadczenia z Chai-Webdriver for Selenium. Dodałem
await
do asercji i rozwiązałem problem:Przykład przy użyciu Cucumberjs:
Then(/I see heading with the text of Tasks/, async function() { await chai.expect('h1').dom.to.contain.text('Tasks'); });
źródło
Rozwiązałem ten problem po odinstalowaniu webpacka (reaguj na problem z js).
źródło