I have written logic based on test cases already defined.Basically the tc checks for one server call below is the code.How do I modify my logic to make the tc pass?
this is test case:
it('there shall be only one server call in addFavourites()', (done) => {
fetchMock.get('http://localhost:3000/movies', moviesTestData);
fetchMock.get('http://localhost:3000/favourites', favouritesTestData);
script.getMovies()
.then(() => {
return script.getFavourites();
})
.then(() => {
fetchMock.restore();
fetchMock.post('http://localhost:3000/favourites', moviesTestData[1]);
return script.addFavourite(27621);
})
.then(() => {
expect(fetchMock.done()).to.equal(true);
done();
})
.catch((err) => {
expect(err).to.equal(null, err);
done();
});
});
this is the logic written.It basically makes call to movies,tries to get it,checks if the selected favourite exists and adds if its not there
function addFavourite(event) {
const id = event;
// eslint-disable-next-line consistent-this
// const self = this;
let favmovie = {};
let favmovies={};
// let favmovie = {};
return fetch('http://localhost:3000/movies')
.then(response =>{
if(response.status === 200)
{
return Promise.resolve(response.json());
}
else
// eslint-disable-next-line no-else-return
{
return Promise.reject(new Error('Unable to fetch the data'));
}
}).then(movies=>{
console.log('moviesssss',movies);
movies.forEach(movie => {
if(movie.id === id) {
favmovie = movie;
}
return Promise.resolve(favmovie);
})
return fetch('http://localhost:3000/favourites')
.then(response =>{
if(response.status === 200)
{
return Promise.resolve(response.json());
}
else
// eslint-disable-next-line no-else-return
{
return Promise.reject(new Error('Unable to fetch the data'));
}
});
}).then(favmoves=>{
favmovies = favmoves;
}).then(()=>{
favmovies.filter(function(movie) {
if(movie.id === id) {
// eslint-disable-next-line no-alert
alert('Movie is already added to favourites');
}
});
}).then(()=>{
return fetch('http://localhost:3000/favourites', {
method: 'POST',
body: JSON.stringify( favmovie),
headers: {
'content-type': 'application/json'
}
})
.then(addedFav =>{
// console.log('addedFav',addedFav.json());
return Promise.resolve(addedFav.json());
}).then(resp=>{
const ul = document.getElementById('favouritesList');
const div = document.createElement('div');
const img = document.createElement('img');
img.setAttribute('src', resp.posterPath);
div.classList.add('moviecontent');
img.classList.add('image');
div.appendChild(document.createTextNode(resp.title));
div.appendChild(img);
div.appendChild(document.createTextNode(resp.overview));
ul.appendChild(div);
console.log('resp',resp);
});
}).catch(err =>{
return Promise.reject(new Error(null, err));
});
}
error is :
Unmatched GET to http://localhost:3000/movies
(node:59340) UnhandledPromiseRejectionWarning: AssertionError: Error: No fallback response defined for GET to http://localhost:3000/movies: expected [Error: No fallback response defined for GET to http://localhost:3000/movies] to equal null
at /Users/anushamuthyalampally/Stack Route/Assignment/javascript-movie-cruiser-assignment/test/script.spec.js:230:20
(node:59340) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 1)
(node:59340) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
1) there shall be only one server call in addFavourites()
0 passing (2s)
1 failing
1) Movie Cruiser
there shall be only one server call in addFavourites():
Error: Timeout of 2000ms exceeded. For async tests and hooks, ensure "done()" is called; if returning a Promise, ensure it resolves. (/Users/anushamuthyalampally/Stack Route/Assignment/javascript-movie-cruiser-assignment/test/script.spec.js)
at listOnTimeout (internal/timers.js:531:17)
at processTimers (internal/timers.js:475:7)
Related
Promise.all(), map() with callback function gives 404 error on .catch (err => {}) in Reactjs.
I could call the endpoint and get the response but end up by getting the below 404 error on the callback.
error request failed with status code 404 at createerror
Any suggestion how this logic should be handled.
Note: If I remove the query parameter from Axios (+ '?nbr=' + data.id) it works fine.... !!??
useEffect(() => {
const url_endpoint = `${url}/getData`
if (data != null) {
Promise.all(
data.map(async (data) =>
Axios.get(url_endpoint + '?nbr=' + data.id, {
headers: {
timestamp: 1111
}
})
.then(response => {
const { data } = response
if (response.status) {
responseCode = response.status
}
setLog({ 'status': 'success'})
callback({ error: false, data })
})
.catch(err => {
if (err.response) {
responseCode = err.response.status
}
setLog({'status': 'error'})
error({ 'responseCode': responseCode })
callback({ APIError: true })
})
)
}
}, [])
You might want to use Promise.allSettled()
The Promise.allSettled() method returns a promise that resolves after all of the given promises have either fulfilled or rejected, with an array of objects that each describes the outcome of each promise.
const promise1 = Promise.resolve(3);
const promise2 = new Promise((resolve, reject) => setTimeout(reject, 100, 'foo'));
const promises = [promise1, promise2];
Promise.allSettled(promises).
then((results) => results.forEach((result) => console.log(result.status)));
// expected output:
// "fulfilled"
// "rejected"
I have some code which calls Promise.all. It runs OK in the browser with no warnings in the console.
There are 3 functions f1, f2 & f3 all of which return a promise. The code looks like this
Promise.all([
f1(),
f2(),
f3()
]).then((values) => {
resolve({success: true})
}).catch(err => {
reject(err)
})
When I use Jest to test the file containing the above code I see this error.
(node:17177) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 18)
Is this the wrong way to code the above or is it a bug within Jest?
Here's the actual code that I'm using:
getDataFromDatabase() {
return new Promise((resolve, reject) => {
const assessmentUrl = `${this.assessmentUrl}`
http.get(assessmentUrl).then(response => {
if (response.data.record === null) {
Promise.all([
this._getPupilPlacement(),
this._getSurveyQuestions(),
this._getCompetencies()
]).then((values) => {
successState.pupilPlacement = values[0].pupilPlacement
successState.items = values[1].items
successState.formid = values[2].formid
successState.competencies = values[3].competencies
const panels = this.getPanels(values[3].competencies)
successState.panels = panels
successState.numPages = panels.length
successState.itemsAreOverridden = true
resolve(successState)
}).catch(err => {
reject(err)
})
}
else {
resolve(response.data.record)
}
})
})
}
Avoid the Promise constructor antipattern! You were forgetting to handle errors from the http.get(assessmentUrl) promise.
You should be writing
getDataFromDatabase() {
const assessmentUrl = `${this.assessmentUrl}`
return http.get(assessmentUrl).then(response => {
//^^^^^^
if (response.data.record !== null)
return response.data.record;
return Promise.all([
// ^^^^^^
this._getPupilPlacement(),
this._getSurveyQuestions(),
this._getCompetencies()
]).then(values => {
const panels = this.getPanels(values[3].competencies)
return {
// ^^^^^^
pupilPlacement: values[0].pupilPlacement,
items: values[1].items,
formid: values[2].formid,
competencies: values[3].competencies,
panels: panels,
numPages: panels.length,
itemsAreOverridden: true,
};
});
});
}
Explanation:
Calling reject will throw an error. If your top level promise doesn't catch it, then well it's an unhandled promise.
MDN Image src
Solution:
getDataFromDatabase().catch(err=>console.lor(err.message));
Example of a promise that rejects.:
function getDataFromDatabase(){
return Promise.reject(123);
}
getDataFromDatabase()
.then(data=>console.log("Success " + data))
.catch(err=>console.log("Error " + err));
Promise MDN doc
Future recommendation:
For every child promise you seem to be adding a .catch() which isn't needed. As long as somewhere higher up there is a catch, then the promise will be handled.
This question already has answers here:
Prevent "Unhandled promise rejection" error
(3 answers)
Closed 4 years ago.
Example
class Foo {
private pro = new Promise(() => {
throw new Error();
});
public usePro() {
return this.pro.then(() => {});
}
}
let foo = new Foo();
setTimeout(() => {
foo.usePro().then(() => {
console.log("end.");
}).catch(() => {
console.log("error.");
})
}, 1000);
I understand that javascript can't know at runtime that someone will catch the error later, so how am I suppose to do in such a situation ?
Console
(node:39166) UnhandledPromiseRejectionWarning: error
(node:39166) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 1)
(node:39166) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
error.
(node:39166) PromiseRejectionHandledWarning: Promise rejection was handled asynchronously (rejection id: 1)
Errors should be caught wherever the Promise is used, even if that Promise is returned (and caught) by something else later. One option would be to assign to this.proValue a resolved object or a rejected object, depending on whether the original Promise resolves or rejects. Then, when usePro is called, check this.proValue and return either Promise.resolve(resolved) or Promise.reject(rejected). Using standard Javascript so this can be shown in a runnable snippet:
class Foo {
constructor() {
this.pro = new Promise(() => {
throw new Error('Problem!');
})
.then((resolved) => {
this.proValue = { resolved };
})
.catch((rejected) => {
this.proValue = { rejected };
});
}
usePro() {
const { resolved, rejected } = this.proValue;
if (resolved) return Promise.resolve(resolved);
else if (rejected) return Promise.reject(rejected);
}
}
const foo = new Foo();
setTimeout(() => {
foo.usePro().then(() => {
console.log("end.");
}).catch((e) => {
console.log("error caught. " + e);
})
}, 1000);
If you want to be able to call usePro before Foo's internal Promise has resolved (or rejected), then when usePro is called, construct and return a Promise that resolves once this.pro's Promise resolves (or rejects). unfortunately the code required is moderately more complicated:
class Foo {
constructor() {
this.callProms = [];
setTimeout(() => {
this.pro = new Promise(() => {
throw new Error('Problem!');
})
.then((resolved) => {
this.proValue = { resolved };
})
.catch((rejected) => {
this.proValue = { rejected };
})
.finally(() => {
console.log('internal promise finishing');
this.resolveCalls();
});
}, 1000);
}
resolveCalls() {
this.callProms.forEach((resolve) => {
resolve(this.getProValue());
});
}
getProValue() {
const { proValue } = this;
if (!proValue) return;
const { resolved, rejected } = proValue;
if (resolved) return Promise.resolve(resolved);
else if (rejected) return Promise.reject(rejected);
}
usePro() {
return this.getProValue()
|| new Promise((resolve) => {
this.callProms.push(resolve);
});
}
}
console.log('Starting');
const foo = new Foo();
// Immediate call of `usePro`:
foo.usePro().then(() => {
console.log("end.");
}).catch((e) => {
console.log("immediate error caught. " + e);
})
// Delayed call:
setTimeout(() => {
foo.usePro().then(() => {
console.log("end.");
}).catch((e) => {
console.log("delayed error caught. " + e);
})
}, 2000);
Great answer by CertainPerformance.
Let me add that in Node.js, you can also add an unhandledRejection listener on process:
process.on('unhandledRejection', reason => {
console.error({Error:reason})
process.exit(1);
});
You could use Promise.all to delay the resolving:
const delay = ms => new Promise(res => setTimeout(res, ms));
Promise.all([
foo.usePro(),
delay(1000)
]).then(() => {
console.log("end.");
}).catch(() => {
console.log("error.");
});
That way the .catch is directly attached, but the then callback is executed after the delay.
this code was working properly one month ago but since last night it was crashing.
(node:3848) UnhandledPromiseRejectionWarning: Error: 400: Bad Request:
message is not modified
at buildConfig.then.then.then.then (D:\apps\bot\node_modules\telegraf\core\network\client.js:235:17)
at
at process._tickCallback (internal/process/next_tick.js:118:7) (node:3848) UnhandledPromiseRejectionWarning: Unhandled promise
rejection. This error originated either by throwing inside of an async
function without a catch block, or by rejecting a promise which was
not handled with .catch(). (rejection id: 1) (node:3848) [DEP0018]
DeprecationWarning: Unhandled promise rejections are deprecated. In
the future, promise rejections that are not handled will terminate the
Node.js process with a non-zero exit code.
code :
app.action('start', (ctx) => {
http.get('http://localhost:3000/api/questions', (res) => {
//res.setEncoding('utf8');
let rawData = '';
res.on('data', (chunk) => {
rawData += chunk;
});
res.on('end', () => {
try {
data = JSON.parse(rawData);
i = Object.keys(data).length;
ctx.editMessageText('Choose one of the options:',
Extra.HTML().markup(m => m.inlineKeyboard([
m.callbackButton(data[x].Q1, 'plus1'),
m.callbackButton(data[x].Q2, 'plus2')
], {
columns: 1
})));
} catch (e) {
console.error(e.message);
}
});
}).on('error', (e) => {
console.error(`Got error: ${e.message}`);
});
});
app.action('plus1', (ctx) => {
if (x < i) {
answer[x] = 1;
ctx.editMessageText('Choose one of the options:', Extra.HTML().markup(m => m.inlineKeyboard([
m.callbackButton(data[x].Q1, 'plus1'),
m.callbackButton(data[x].Q2, 'plus2')
], {
columns: 1
})));
x++;
} else {
ctx.editMessageText('Finished :', Extra.HTML().markup(m => m.inlineKeyboard([
m.callbackButton('Result', 'result')
])));
}
});
app.action('plus2', (ctx) => {
if (x < i) {
answer[x] = 2;
ctx.editMessageText('Choose one of the options', Extra.HTML().markup(m => m.inlineKeyboard([
m.callbackButton(data[x].Q1, 'plus1'),
m.callbackButton(data[x].Q2, 'plus2')
], {
columns: 1
})));
x++;
} else {
ctx.editMessageText('Finished :', Extra.HTML().markup(m => m.inlineKeyboard([
m.callbackButton('Result', 'result')
])));
}});
app.action('result', (ctx) => {
ctx.reply(answer);
});
app.startPolling();
Telegram has several methods for updating a message. If you call editMessageText but the text itself is not change, this is the response you get. If you only modify the markup you should use editMessageReplyMarkup. So it might make sense to review methods of the library you use and call appropriate ones. I believe your editMessageTexts are somehow called with the same text or twice.
I have constructed a function which iterates through a Generator containing both synchronous code and Promises:
module.exports = {
isPromise (value) {
return typeof value === 'object' && value !== null && 'then' in value;
},
runGen (generatorFunc, startValue) {
let that = this,
i = 0;
function *iterator(resolve, reject) {
let runGeneratorFunc = generatorFunc(startValue),
yieldedOut = {done: false},
yieldIn;
while (!yieldedOut.done) {
console.log(i++, 'Ready for next iteration');
if (that.isPromise(yieldedOut.value)) {
console.log(i++, 'Pass promise to KeepIterating');
yieldIn = yield yieldedOut.value;
console.log(i++, 'Received value from promise');
if(yieldIn instanceof Error){
console.log(i++, 'Value was instance of Error');
try {
yieldedOut = runGeneratorFunc.throw(yieldIn)
}
catch(err){
console.log(i++, 'Throw Error');
throw(yieldIn);
}
} else {
yieldedOut = runGeneratorFunc.next(yieldIn);
}
} else {
try {
yieldIn = yieldedOut.value;
yieldedOut = runGeneratorFunc.next(yieldIn);
}
catch(err) {
runGeneratorFunc.throw(err);
reject(err);
}
}
}
resolve(yieldedOut.value);
}
return new Promise(function (resolve, reject) {
var runIterator = iterator(resolve, reject);
(function keepIterating(yieldIn) {
let yieldedOutPromise = runIterator.next(yieldIn);
if (!yieldedOutPromise.done) {
yieldedOutPromise.value.then(function (fulfilledValue) {
console.log('never gets here');
keepIterating(fulfilledValue);
});
yieldedOutPromise.value.catch(function (err) {
console.log(i++, 'Rejected promise catched');
if (err instanceof Error) {
try {
console.log(i++, 'Rejected promise is instance of Error');
let yieldedOut = runIterator.next(err);
keepIterating(yieldedOut);
}
catch (err) {
console.log(i++, 'Error propagated back out');
yieldedOutPromise.value.catch(() => {})
reject(err);
}
} else {
try {
let yieldedOut = runIterator.next(new Error(err));
keepIterating(yieldedOut);
}
catch (err) {
reject(err);
}
}
})
}
})();
});
}
}
Now when I import and run it using this code:
const md = require('./module');
function* dummy () {
yield Promise.reject(new Error('error1'));
}
md.runGen(dummy)
.catch(err => {
console.log(9, 'Finished!');
})
I get this logged to the console:
0 'Ready for next iteration'
1 'Ready for next iteration'
2 'Promise yielded out'
3 'Rejected promise handled'
4 'Rejected promise instance of Error'
5 'Ready to handle promise value'
6 'Value was instance of Error'
7 'Throw Error'
8 'Error propagated back out'
9 'Finished!'
(node:9904) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 2): Error: error1
(node:9904) DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
This is all as expected except for the warning about UnhandledPromiseRejectionWarning. I am confused about why I receive this warning as the rejected Promise is handled in the code as far as I can tell.
What am I overlooking?
What am I overlooking?
Your yieldedOutPromise.value.then call is creating a new promise, and if yieldedOutPromise.value rejects then it will be rejected as well. It doesn't matter that you handle the error via .catch on yieldedOutPromise.value, there's still a rejected promise around, and it's the one that will be reported.
You are basically splitting your promise chain, which leads to each end needing an error handler. However, you shouldn't be splitting anything at all. Instead of the
promise.then(onSuccess);
promise.catch(onError);
antipattern you should use
promise.then(onSuccess, onError).…
Oh, and while you're at it, avoid the Promise constructor antipattern. Just do
module.exports = function runGen (generatorFunc, startValue) {
return Promise.resolve(startValue).then(generatorFunc).then(generator => {
return keepIterating({done: false, value: undefined});
function keepIterating({done, value}) {
if (done) return value;
return Promise.resolve(value).then(fulfilledValue =>
generator.next(fulfilledValue)
, err =>
generator.throw(err)
).then(keepIterating);
}
});
};