I have an instance method on a mongoose schema, and I cannot catch errors it throws with mocha.
The method does not throw, it calls back with error as param, but mocha test doesn't catch that and I get an uncaught error.
Here's an example module, using mongoose to just do something as a method:
var mongoose = require('mongoose');
var model;
function init(callback) {
mongoose.connect('localhost/test', function() {
var schema = new mongoose.Schema({
a: String
});
schema.methods.act = function(param, cb) {
if (!param) {
console.log('Failing, no param.');
return cb(new Error('Text'));
}
this.a = param;
this.save(cb);
};
model = mongoose.model('schema', schema);
callback();
});
}
function run(cb) {
var instance = new model();
instance.save(function(err) {
if (err) {
throw err;
}
instance.act(null, function(err) {
if (err) {
console.log('An error:', err);
cb(err);
};
});
});
}
module.exports = {
init: init,
run: run
};
Here's a simplified mocha tester:
require('should');
var myModule = require('./testm');
describe('test', function() {
before(function(done) {
// prep stuff
myModule.init(done);
});
it('should catch the error', function(done) {
myModule.run(function(err) {
console.log('Error here:', err);
err.message.should.equal('Text');
done();
});
});
});
Running the test doesn't work as expected:
mocha test
test
Failing, no param.
An error: [Error: Text]
Error here: [Error: Text] Text
1) should catch the error
0 passing (30ms)
1 failing
1) test should catch the error:
Uncaught TypeError: Cannot call method 'equal' of undefined
at /home/zlatko/tmp/test.js:14:26
at /home/zlatko/tmp/testm.js:35:9
at model.schema.methods.act (/home/zlatko/tmp/testm.js:14:16)
at Promise.<anonymous> (/home/zlatko/tmp/testm.js:31:14)
at Promise.<anonymous> (/home/zlatko/tmp/node_modules/mongoose/node_modules/mpromise/lib/promise.js:177:8)
at Promise.emit (events.js:98:17)
at Promise.emit (/home/zlatko/tmp/node_modules/mongoose/node_modules/mpromise/lib/promise.js:84:38)
at Promise.fulfill (/home/zlatko/tmp/node_modules/mongoose/node_modules/mpromise/lib/promise.js:97:20)
at handleSave (/home/zlatko/tmp/node_modules/mongoose/lib/model.js:133:13)
at /home/zlatko/tmp/node_modules/mongoose/lib/utils.js:408:16
at /home/zlatko/tmp/node_modules/mongoose/node_modules/mongodb/lib/mongodb/collection/core.js:128:9
at /home/zlatko/tmp/node_modules/mongoose/node_modules/mongodb/lib/mongodb/db.js:1195:7
at /home/zlatko/tmp/node_modules/mongoose/node_modules/mongodb/lib/mongodb/db.js:1903:9
at Server.Base._callHandler (/home/zlatko/tmp/node_modules/mongoose/node_modules/mongodb/lib/mongodb/connection/base.js:453:41)
at /home/zlatko/tmp/node_modules/mongoose/node_modules/mongodb/lib/mongodb/connection/server.js:487:18
at MongoReply.parseBody (/home/zlatko/tmp/node_modules/mongoose/node_modules/mongodb/lib/mongodb/responses/mongo_reply.js:68:5)
at null.<anonymous> (/home/zlatko/tmp/node_modules/mongoose/node_modules/mongodb/lib/mongodb/connection/server.js:445:20)
at emit (events.js:95:17)
at null.<anonymous> (/home/zlatko/tmp/node_modules/mongoose/node_modules/mongodb/lib/mongodb/connection/connection_pool.js:207:13)
at emit (events.js:98:17)
at Socket.<anonymous> (/home/zlatko/tmp/node_modules/mongoose/node_modules/mongodb/lib/mongodb/connection/connection.js:440:22)
at Socket.emit (events.js:95:17)
at Socket.<anonymous> (_stream_readable.js:765:14)
at Socket.emit (events.js:92:17)
at emitReadable_ (_stream_readable.js:427:10)
at emitReadable (_stream_readable.js:423:5)
at readableAddChunk (_stream_readable.js:166:9)
at Socket.Readable.push (_stream_readable.js:128:10)
at TCP.onread (net.js:529:21)
What can I be doing wrong?
Update: changed to be more clear.
In my opinion, #Louis answer is the best way to check for an error in asynchronous scenarios: just assert if it exists, their types and so on.
But, if you really want to throw an error when you receive it in your callback, you can do it with chai-as-promised, like:
it('should catch the error', function() {
return Promise.resolve(function () {
myModule.run(function(err) {
if (err) {throw err;}
});
}).should.eventually.throw(Error);
});
In my example, I'm using should.js as the assertion library, but you can use whatever assertion library you want.
Related
I need help downloading more than one file from a remote FTP using Node js, the code is the following.
const FTPClient = require('ftp');
let ftp_client = new FTPClient();
const fs = require("fs");
let ftpConfig = {
host: "remoteHost",
port: 21,
user: 'username',
password: 'password',
}
//create a connection to ftp server
ftp_client.connect(ftpConfig);
ftp_client.on('ready', function() {
ftp_client.get('/file1.csv', function(err, stream) {
if (err) throw err;
//stream.once('close', function() { ftp_client.end(); });
stream.pipe(fs.createWriteStream('file1.csv'));
});
ftp_client.get('/dir/file2.dat', function(err, stream) {
if (err) throw err;
//stream.once('close', function() { ftp_client.end(); });
stream.pipe(fs.createWriteStream('file2.dat'));
});
ftp_client.get('/dir/file3.dat', function(err, stream) {
if (err) throw err;
stream.once('close', function() { ftp_client.end(); });
stream.pipe(fs.createWriteStream('file3.dat'));
});
});
And the error
Error: Unable to make data connection
at Socket.<anonymous> (C:\Proyectos\descargar_file\node_modules\ftp\lib\connection.js:935:10)
at Object.onceWrapper (events.js:421:28)
at Socket.emit (events.js:327:22)
at Object.cb (C:\Proyectos\descargar_file\node_modules\ftp\lib\connection.js:575:18)
at Parser.<anonymous> (C:\Proyectos\descargar_file\node_modules\ftp\lib\connection.js:117:20)
at Parser.emit (events.js:315:20)
at Parser._write (C:\Proyectos\descargar_file\node_modules\ftp\lib\parser.js:59:10)
at doWrite (_stream_writable.js:403:12)
at writeOrBuffer (_stream_writable.js:387:5)
at Parser.Writable.write (_stream_writable.js:318:11)
It is already downloading the 3 files, but also showing that error, so how can I correct this to do it in a safer way?
I also would like to add a console log while the process is downloading each file.
Thanks!
I'm trying to connect a Node.js app with a PostgreSQL server. It seems that no matter what I use, I end up with the same error:
bundle.js:16177 ERROR: TypeError: net.Stream is not a constructor
at new Connection (bundle.js:10133)
at new Client (bundle.js:9704)
at Object.create (bundle.js:11308)
at Pool._createResource (bundle.js:510)
at Pool.dispense [as _dispense] (bundle.js:498)
at Pool.acquire (bundle.js:573)
at Pool.pool.connect (bundle.js:11359)
at PG.connect (bundle.js:10876)
at bundle.js:1642
At first I was declaring a new pg.Client() like the example in the documentation here, but got the above error discovered that might be a bad idea according to this stack overflow post.
I tried using pg.connect():
var pg = require('pg'); //postgresql dependency
var connectionString = "postgres://postgres:thisissuchagoodpassword#PostgreSQL/localhost:5432/Milestone1DB"
console.log("Initiating...");
//var connectionString = "postgres://postgres:thisissuchagoodpassword#PostgreSQL9.6/localhost:5432/Milestone1DB";
//var client = new pg.Client();
//connect to the database
console.log("Attempting to connect to the database");
pg.connect(function (err, client, done)
{
if(err)
{
console.log("Error connecting to the database.");
throw err;
}
client.query("SELECT DISTINCT state FROM business ORDER BY state", function (err, result)
{
if(err)
{
console.log("Query resulted in an error.");
throw err;
}
console.log(result.rows[0]);
client.end(function (err)
{
if(err)
{
console.log("Error disconnecting from the databse.");
throw err;
}
});
});
});
Here is the pg-promise code that I tried:
var pgp = require('pg-promise');
var cn = {
host: 'localhost', // server name or IP address;
port: 5432,
database: 'Milestone1DB',
user: 'postgres',
password: 'thisissuchagoodpassword'
};
var db = pgp(cn); // database instance;
db.any("select distict state from business order by state;")
.then(data => {
console.log("DATA:", data);
})
.catch(error => {
console.log("ERROR:", error);
});
I must be missing something, but I don't know where to look. Thank you to anyone who can help me figure out what this error means.
Make sure you are not crossing a context boundary that is corrupting the net prototype chain and stripping away methods like Stream(). I ran into a similar unhandled Promise exception w Node 7.5 and pg-live-select. However it was intermittent because of the way the net reference was being passed around. I ended up using V8 inspector and putting a 'debugger' statement directly above line 13 in connection.js to catch the corruption.
node_modules/lib/connection.js:13
this.stream = config.stream || new net.Stream();
^
TypeError: net.Stream is not a constructor
at new Connection (node_modules/pg-live-select/node_modules/pg/lib/connection.js:13:34)
at new Client (node_modules/pg-live-select/node_modules/pg/lib/client.js:26:37)
at Object.create (node_modules/pg-live-select/node_modules/pg/lib/pool.js:27:24)
at Pool._createResource (node_modules/generic-pool/lib/generic-pool.js:325:17)
at Pool.dispense [as _dispense] (node_modules/generic-pool/lib/generic-pool.js:313:12)
at Pool.acquire (node_modules/generic-pool/lib/generic-pool.js:388:8)
at Pool.pool.connect (node_modules/pg-live-select/node_modules/pg/lib/pool.js:78:14)
at PG.connect (node_modules/pg-live-select/node_modules/pg/lib/index.js:49:8)
at LivePg._updateQuery (node_modules/pg-live-select/index.js:295:6)
at node_modules/pg-live-select/index.js:160:14
at Array.forEach (native)
at Timeout.performNextUpdate [as _onTimeout] (node_modules/pg-live-select/index.js:159:23)
at ontimeout (timers.js:365:14)
at tryOnTimeout (timers.js:237:5)
at Timer.listOnTimeout (timers.js:207:5)
I am attempting to test this module (receiver.js) for an error thrown:
var request = require('request')
module.exports = function(url){
request({
url: url,
method: 'POST'
}, function(error) {
if(error){
throw error
}
})
}
using this test (test.js):
var test = require('tape')
test('Receiver test', function(t){
var receiver = require('./receiver')
t.throws(function(){
receiver('http://localhost:9999') // dummy url
}, Error, 'Should throw error with invalid URL')
t.end()
})
but tape runs the assertion before the error is thrown, resulting in the following error message:
TAP version 13
# Receiver test
not ok 1 Should throw error with invalid URL
---
operator: throws
expected: |-
[Function: Error]
actual: |-
undefined
at: Test.<anonymous> (/path/to/tape-async-error-test/test.js:5:4)
...
/path/to/receiver.js:9
throw error
^
Error: connect ECONNREFUSED 127.0.0.1:9999
at Object.exports._errnoException (util.js:856:11)
at exports._exceptionWithHostPort (util.js:879:20)
at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1062:14)
Is there a way around this?
Generally, using tape, you have to ensure you call assert.end() after the async call has completed. Using promises (would require request-promise and returning the promise):
test('Receiver test', function(t){
// Tells tape to expec a single assertion
t.plan(1);
receiver('http://localhost:9999')
.then(() => {
t.fail('request should not succeed')
})
.catch(err => {
t.ok(err, 'Got expected error');
})
.finally({
t.end();
});
});
Using async/await:
test('Receiver test', async function(t) {
try {
await receiver('http://localhost:9999');
assert.fail('Should not get here');
} catch (err) {
assert.ok(err, 'Got expected error');
}
t.end();
});
The above example is mostly correct but here's a complete working example that compares async to synchronous side by side and also shows how to check for the error message in a manner similar to the tape examples given on tape's README.md.
test('ensure async function can be tested to throw', async function(t) {
// t.throw works synchronously
function normalThrower() {
throw(new Error('an artificial synchronous error'));
};
t.throws(function () { normalThrower() }, /artificial/, 'should be able to test that a normal function throws an artificial error');
// you have to do this for async functions, you can't just insert async into t.throws
async function asyncThrower() {
throw(new Error('an artificial asynchronous error'));
};
try {
await asyncThrower();
t.fail('async thrower did not throw');
} catch (e) {
t.match(e.message,/asynchronous/, 'asynchronous error was thrown');
};
});
I'm trying to use this method for non-sequential promise output.
The express .json call successfully sends a 201 alongside the user object from the API, but in the console, I get the Unhandled rejection error shown below. This seems like it should be caught by the .catch handler in the controller. I am wondering why this could be happening?
userController
module.exports.postUser = function (req, res, next) {
var user = req.body.user;
var ip = req.ip;
userService.createUser(user, ip)
.then(function (user) {
res.status(201).json({"user": user.toJSON()});
})
.catch(function (err) {
return next(err);
});
};
userService
module.exports.createUser = function (user, ip) {
var user = new Promise(function (resolve, reject) {
return resolve(User.forge(user));
});
return user.then(function validateUser(user) {
return user.validate({validatePassword: true});
})
.then(function hash() {
var password = user.value().get('password');
return hashPassword(password);
})
.then(function setPassword(hashedPass) {
user.value().set('hashedPass', hashedPass);
return user.value().save();
})
.then(function () {
return user;
});
};
output
Unhandled rejection error: null value in column "status" violates not-null constraint
at Connection.parseE (/Users/lukel99/webstorm-workspace/rocketwagon-postgres-kickstart/node_modules/pg/lib/connection.js:539:11)
at Connection.parseMessage (/Users/lukel99/webstorm-workspace/rocketwagon-postgres-kickstart/node_modules/pg/lib/connection.js:366:17)
at Socket.<anonymous> (/Users/lukel99/webstorm-workspace/rocketwagon-postgres-kickstart/node_modules/pg/lib/connection.js:105:22)
at Socket.emit (events.js:107:17)
at readableAddChunk (_stream_readable.js:163:16)
at Socket.Readable.push (_stream_readable.js:126:10)
at TCP.onread (net.js:538:20)
From previous event:
at Client._query (/Users/lukel99/webstorm-workspace/rocketwagon-postgres-kickstart/node_modules/knex/lib/dialects/postgres/index.js:122:12)
at Client.query (/Users/lukel99/webstorm-workspace/rocketwagon-postgres-kickstart/node_modules/knex/lib/client.js:127:24)
at Runner.<anonymous> (/Users/lukel99/webstorm-workspace/rocketwagon-postgres-kickstart/node_modules/knex/lib/runner.js:118:24)
From previous event:
at /Users/lukel99/webstorm-workspace/rocketwagon-postgres-kickstart/node_modules/knex/lib/runner.js:44:21
From previous event:
at Runner.run (/Users/lukel99/webstorm-workspace/rocketwagon-postgres-kickstart/node_modules/knex/lib/runner.js:30:20)
at QueryBuilder.Target.then (/Users/lukel99/webstorm-workspace/rocketwagon-postgres-kickstart/node_modules/knex/lib/interface.js:27:43)
at null.<anonymous> (/Users/lukel99/webstorm-workspace/rocketwagon-postgres-kickstart/node_modules/bookshelf/lib/model.js:208:36)
at processImmediate [as _immediateCallback] (timers.js:367:17)
The most likely cause is that return user.value().save() does not return a promise, but implements callbacks instead. If that is the case, then the error would be thrown outside of the native promise try/catch block, and would hence not be caught but your .catch().
var cradle = require('cradle');
var db = new(cradle.Connection)().database('starwars');
db.get('vader', function (err, doc) {
doc.name;
assert.equal(doc.force, 'dark');
});
db.save('skywalker', {
force: 'light',
name: 'Luke Skywalker'
}, function (err, res) {
if (err) {
// Handle error
} else {
// Handle success
}
});
installed cradle via npm
npm install cradle
The error output running node cradle.js
root#server:~# node cradle.js
/root/cradle.js:5
doc.name;
^
TypeError: Cannot read property 'name' of undefined
at Object.callback (/root/cradle.js:5:8)
at /root/node_modules/cradle/lib/cradle.js:276:26
at IncomingMessage.<anonymous> (/root/node_modules/cradle/lib/cradle.js:210:21)
at IncomingMessage.emit (events.js:81:20)
at HTTPParser.onMessageComplete (http.js:133:23)
at Socket.ondata (http.js:1213:22)
at Socket._onReadable (net.js:681:27)
at IOWatcher.onReadable [as callback] (net.js:177:10)
UPDATE: problem boils down to
db.get('vader', function (err, doc) {
doc.name;
assert.equal(doc.force, 'dark');
});
it's complaining about doc.name
Where can I view the database so I can see the new row added?
db.get('vader', function (err, doc) {
if (err) {
console.log(err);
} else {
doc.name;
assert.equal(doc.force, 'dark');
}
});
The example doesn't do error handling. I would assume the error is document vader doesn't exist or database starwars doesn't exist.
If you have couch installed and running then the database lives at http://localhost:5984/_utils/