I get weird error whenever i'm testing my endpoint through jasmine and superset.
import app from '../index'
import supertest from 'supertest'
const request = supertest(app);
describe("suite for testing the image endpoint response", () => {
//done for supertest to tell when our endpoint is done to disconnect from server
it('Server is up', async (done)=>{
const response = await request.get('api/image');
expect(response.status).toBe(200);
done();
})
})
The Error:
suite for testing the image endpoint response Server is up
An asynchronous before/it/after function took a done callback but also returned a promise. Either remove the done callback (recommended)
or change the function to not return a promise. thrown
Unhandled promise rejection: Error: ECONNREFUSED: Connection refused
Error: Timeout - Async function did not complete within 5000ms (set by jasmine.DEFAULT_TIMEOUT_INTERVAL)
Executed 1 of 1 spec (1 FAILED) in 5 secs.
I tried to remove "done()" which is wrong to be removed since it closes the connection after the test, but still same error.
By removing done in parameters and done() in the last line, will make it work.
Related
I am using the excellent stripe documentation to build a webhook to respond to a stripe successful payment. The code works fine however as soon as I introduced async-await, I get a 500 Internal server error.
I am testing the firebase onRequest webhook function through the send test webhook on the stripe website.
My code lives here
What am I missing?
firebase function with async-await does not work:
exports.stripeEvents = functions.https.onRequest(async (request, response) =>
{
try
{
let stripesignature = request.headers['stripe-signature'] as string;
let stripeevent:Stripe.Event= stripe.webhooks.constructEvent(request.rawBody.toString('utf8'), stripesignature, config.stripewebhooksecretkey);
if(stripeevent.type === 'payment_intent.succeeded')
{
let payment_intent1 = stripeevent.data.object as Stripe.PaymentIntent;
let datafirstelement=null;
if(payment_intent1?.charges?.data && payment_intent1?.charges?.data.length>0)
{
datafirstelement=payment_intent1?.charges?.data[0];
}
let userid='someuserid';
let documentreference=config.db.collection('users').doc(userid);
await documentreference.update({payments: admin.firestore.FieldValue.arrayUnion(datafirstelement)});
response.status(200).send({'result':true});
}
}
catch(error)
{
//log error into sentry
throw error;
}
});
firebase function without async-await, works:
exports.stripeEvents = functions.https.onRequest((request, response) =>
{
try
{
let stripesignature = request.headers['stripe-signature'] as string;
let stripeevent:Stripe.Event= stripe.webhooks.constructEvent(request.rawBody.toString('utf8'), stripesignature, config.stripewebhooksecretkey);
if(stripeevent.type === 'payment_intent.succeeded')
{
let payment_intent1 = stripeevent.data.object as Stripe.PaymentIntent;
let datafirstelement=null;
if(payment_intent1?.charges?.data && payment_intent1?.charges?.data.length>0)
{
datafirstelement=payment_intent1?.charges?.data[0];
}
let userid='someuserid';
let documentreference=config.db.collection('users').doc(userid);
//await documentreference.update({payments: //admin.firestore.FieldValue.arrayUnion(datafirstelement)});
response.status(200).send({'result':true});
}
}
catch(error)
{
//log error into sentry
throw error;
}
});
update 1: I am testing the firebase onRequest webhook function through the send test webhook on the stripe website.
successful stripe payments when not using async-await, internal server error when using async-await:
webhook success logs when not using async-await(and no logs when using async-await):
update 2: firebase function log:
stripeEvents
Error: Value for argument "documentPath" is not a valid resource path. Path must be a non-empty string.
at Object.validateResourcePath (/workspace/node_modules/#google-cloud/firestore/build/src/path.js:403:15)
at CollectionReference.doc (/workspace/node_modules/#google-cloud/firestore/build/src/reference.js:1988:20)
at exports.stripeEvents.functions.https.onRequest (/workspace/lib/index.js:115:85)
at cloudFunction (/workspace/node_modules/firebase-functions/lib/providers/https.js:51:16)
at process.nextTick (/layers/google.nodejs.functions-framework/functions-framework/node_modules/#google-cloud/functions-framework/build/src/invoker.js:99:17)
at process._tickCallback (internal/process/next_tick.js:61:11)
update 3: firebase function log:
I changed line await documentreference.update({payments: //admin.firestore.FieldValue.arrayUnion(datafirstelement)}); to await documentreference.set({payments: admin.firestore.FieldValue.arrayUnion(datafirstelement)}, {merge:true}); and the application still throws the following errors. The code lives here.
12:02:30.464 AM
stripeEvents
Function execution started
12:02:54.174 AM
stripeEvents
Function execution started
12:02:54.901 AM
stripeEvents
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(). The promise rejected with the reason:
12:02:54.905 AM
stripeEvents
Function execution took 732 ms, finished with status: 'crash'
12:03:30.467 AM
stripeEvents
Function execution took 60004 ms, finished with status: 'timeout'
From the comments above and from the error you get (Error: Value for argument "documentPath" is not a valid resource path. Path must be a non-empty string.), it seems that the value you pass to the doc() method while testing your Cloud Function is an empty string.
You need to mock data in your test in order to pass a correct value to the doc() method.
Note that I’m not sure that testing it "from the web application" (as you mention in the comments above) will change something, since the stripe Webhook has nothing to do with your web application (the Stripe backend calls your backend, i.e. your Cloud Function). You may send the userId as payment metadata to Stripe and (1) add it as query string parameter to the URL called by the webhook and (2) parse and use this value in your Cloud Function.
Note also that the difference between your "async version" that does not work and you "non async version" that works is not about async/await but is just that you comment out the line that generates the error.
I'm trying to run the tests on this promises but I get this error:
"Error: Timeout of 2000ms exceeded. For async tests and hooks, ensure" done () "is called; if returning to Promise, ensure it resolves. (C:\Users\Ranieri\Documents\Projetos\Node Js\testestest\test\libs\registerUser.test.js)"
I have already increased the timeout time but it still does not solve the problem.
I searched for asynchronous test here on stackoverflow and found nothing or anyone with something similar
my test code https://github.com/ran-j/teste
Already tried :
expect(Promise.resolve( userPromesie.selectUser(rUser) ) ).to.be.null
return expect(Promise.resolve( userPromesie.selectUser(rUser) ) ).to.be.null
userPromesie.selectUser(rUser).then((result) => result.to.be.null
selectUser returns a Promise and you need to wait for this to resolve in order to be able to assert against it. This can achieved two ways:
Using then on the returning promise, calling the done() function within that block.
Using async/await, you declare your function async and you await the Promise
Below is an example of an async/await method:
it('should do something with the user', async () => {
const user = await userPromise.selectUser(rUser);
expect(user).to.be.null;
});
I'd highly recommend reading up on Promises for more information: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise
EDIT Here's an example using the done method:
it('should do something with the user', (done) => {
userPromise.selectUser(rUser).then((user) => {
expect(user).to.be.null;
done();
});
});
When using redis client (ioredis or node_redis) inside websocket's message event in a nodejs app, the callback for any command is not immediately fired. (the operation does take place on redis server though)
What is strange is that the callback for the first command will fire after i sent a second message, and the callback for the second will fire after i send a third.
wss.on('connection', (socket, request) => {
socket.on('message', (data) => {
console.log("will send test command")
this.pubClient.hset("test10", "f1","v1", (err,value) => {
//callback not firing first time
console.log("test command reply received")
})
})
}
the redis command is working as expected though in other parts of the app and even when inside the on connection directly like below.
wss.on('connection', (socket, request) => {
console.log("will send test command")
this.pubClient.hset("test10", "f1","v1", (err,value) => {
//callback fires
console.log("test command reply received")
})
socket.on('message', (data) => {})
}
UPDATE:
I had this all wrong. The reason for the weird callback behavior is the result of one my custom Redis modules not returning a reply.
And this seems to have caused all callbacks after this call to seem to have some kind of a one step delay.
I had this all wrong. The reason for the weird callback behavior is the result of one my custom Redis modules not returning a reply. And this seems to have caused all callbacks after this call to seem to have some kind of a one step delay.
I want to test the error in a request return. I'm using nock in my tests, how can I force Nock to provoke an error? I want to achieve 100% test coverage and need to test err branch for that
request('/foo', function(err, res) {
if(err) console.log('boom!');
});
Never enter in the if err branch. Even if hit err is a valid response, my Nock line in test looks like this
nock('http://localhost:3000').get('/foo').reply(400);
edit:
thanks to some comments:
I'm trying to mock an error in the request. From node manual:
https://nodejs.org/api/http.html#http_http_request_options_callback
If any error is encountered during the request (be that with DNS resolution, TCP level errors, or actual HTTP parse errors) an 'error' event is emitted on the returned request object
An error code (e.g. 4xx) doesn't define the err variable. I'm trying to mock exactly that, whatever error that defines the err variable and evaluates to true
Use replyWithError.
From the docs:
nock('http://www.google.com')
.get('/cat-poems')
.replyWithError('something awful happened');
When you initialise a http(s) request with request(url, callback), it returns an event emitter instance (along with some custom properties/methods).
As long as you can get your hands on this object (this might require some refactoring or perhaps it might not even be suitable for you) you can make this emitter to emit an error event, thus firing your callback with err being the error you emitted.
The following code snippet demonstrates this.
'use strict';
// Just importing the module
var request = require('request')
// google is now an event emitter that we can emit from!
, google = request('http://google.com', function (err, res) {
console.log(err) // Guess what this will be...?
})
// In the next tick, make the emitter emit an error event
// which will trigger the above callback with err being
// our Error object.
process.nextTick(function () {
google.emit('error', new Error('test'))
})
EDIT
The problem with this approach is that it, in most situations, requires a bit of refactoring. An alternative approach exploits the fact that Node's native modules are cached and reused across the whole application, thus we can modify the http module and Request will see our modifications. The trick is in monkey-patching the http.request() method and injecting our own bit of logic into it.
The following code snippet demonstrates this.
'use strict';
// Just importing the module
var request = require('request')
, http = require('http')
, httpRequest = http.request
// Monkey-patch the http.request method with
// our implementation
http.request = function (opts, cb) {
console.log('ping');
// Call the original implementation of http.request()
var req = httpRequest(opts, cb)
// In next tick, simulate an error in the http module
process.nextTick(function () {
req.emit('error', new Error('you shall not pass!'))
// Prevent Request from waiting for
// this request to finish
req.removeAllListeners('response')
// Properly close the current request
req.end()
})
// We must return this value to keep it
// consistent with original implementation
return req
}
request('http://google.com', function (err) {
console.log(err) // Guess what this will be...?
})
I suspect that Nock does something similar (replacing methods on the http module) so I recommend that you apply this monkey-patch after you have required (and perhaps also configured?) Nock.
Note that it will be your task to make sure you emit the error only when the correct URL is requested (inspecting the opts object) and to restore the original http.request() implementation so that future tests are not affected by your changes.
Posting an updated answer for using nock with request-promise.
Let's assume that your code calls request-promise like this:
require('request-promise')
.get({
url: 'https://google.com/'
})
.catch(res => {
console.error(res);
});
you can set up nock like this to simulate a 500 error:
nock('https://google.com')
.get('/')
.reply(500, 'FAILED!');
Your catch block would log a StatusCodeError object:
{
name: 'StatusCodeError',
statusCode: 500,
message: '500 - "FAILED!"',
error: 'FAILED!',
options: {...},
response: {
body: 'FAILED!',
...
}
}
Your test can then validate that error object.
Looks like you're looking for an exception on a nock request, this maybe can help you:
var nock = require('nock');
var google = nock('http://google.com')
.get('/')
.reply(200, 'Hello from Google!');
try{
google.done();
}
catch (e) {
console.log('boom! -> ' + e); // pass exception object to error handler
}
I've got a node.js + express web server that I'm testing with Mocha. I start the web server within the test harness, and also connect to a mongodb to look for output:
describe("Api", function() {
before(function(done) {
// start server using function exported from another js file
// connect to mongo db
});
after(function(done) {
// shut down server
// close mongo connection
});
beforeEach(function(done) {
// empty mongo collection
});
describe("Events", function() {
it("Test1", ...);
it("Test2", ...);
it("Test3", ...);
it("Test4", ...);
it("Test5", ...);
});
});
If Mocha runs more than 4 tests at a time, it times out:
4 passing (2s)
1 failing
1) Api Test5:
Error: timeout of 2000ms exceeded
at null.<anonymous> (C:\Users\<username>\AppData\Roaming\npm\node_modules\moch\lib\runnable.js:165:14)
at Timer.listOnTimeout [as ontimeout] (timers.js:110:15)
If I skip any one of the 5 tests, it passes successfully. The same problem occurs if I reorder the tests (it's always the last one that times out). Splitting the tests into groups also doesn't change things.
From poking at it, the request for the final test is being sent to the web server (using http module), but it's not being received by express. Some of the tests make one request, some more than one. It doesn't affect the outcome which ones I skip. I haven't been able to replicate this behaviour outside mocha.
What on earth is going on?
With Mocha, if you declare a first argument to your (test) functions' callback (usually called done), you must call it, otherwise Mocha will wait until it's called (and eventually time out). If you're not going to need it in a test, don't declare it:
it('test1', function(done) {
..
// 'done' declared, so call it (eventually, usually when some async action is done)
done();
});
it('test2', function() {
// not an async test, not declaring 'done', obviously no need to call it
});
And since you're using http, try increasing http.globalAgent.maxSockets (which defaults to 5):
var http = require('http');
http.globalAgent.maxSockets = 100;
(I believe 0 turns it off completely but I haven't tried).