I am trying to use nockBack to automate my fixtures recording/playback with code that uses promises and chai-as-promised.
But I can't figure out how to make the async nockBack work with it.
context('sad path', () => {
it('should reject the promise', () => {
return nockBack('myfixture.json')
.then(() => assert.isRejected(myPromise.doIt(), Error));
});
});
This fails with a timeout because no callback is ever called.
I also tried with const nockBack = Promise.promisifyAll(require('nock').back), but it still times out.
Any thoughts on how to use nockBack with promises and chai-as-promised?
Related
I am trying to implement mocha testing, however it doesn't seem to work the way I expect it to. My code looks like the following:
async function getFoo() {
return new Promise(resolve => {
setTimeout(() => {
resolve('resolved')
}, 2500)
})
}
describe(`Testing stuff`, function () {
it('resolves with foo', () => {
return getFoo().then(result => {
assert.equal(result, 'foo')
})
})
})
Error message:
Error: Timeout of 2000ms exceeded. For async tests and hooks, ensure "done()" is called; if returning a Promise, ensure it resolves.
To me it seems like I have to increase the threshold of the timeout.
Is there a better way to do this? Since I don't know how long each test might take. I am testing nodejs child processes
best regards
As it is described in the error you need to use done() end of your test.
function delay(timeout = 2500) {
return new Promise(resolve => {
setTimeout(() => {
resolve('resolved')
}, timeout)
})
}
describe(`Testing stuff`, function (done) {
it('resolves with foo', (done) => {
return delay().then(result => {
assert.equal(result, 'foo')
done()
})
})
});
// better readability
describe(`Testing stuff`, function (done) {
it('resolves with foo', (done) => {
const result = await delay();
assert.equal(result, 'foo')
done();
})
});
But as you described you are testing child_processes which I don't recommend. Because to test child_process you need to promisify the child_process which doesn't make sense. Check here for more info How to promisify Node's child_process.exec and child_process.execFile functions with Bluebird?
If you really want to test child_process maybe you can mock the process with the link i gave but only for testing purposes.
I have seem many examples of how to test if a promise is rejected with a certain reason, like below:
it('should reject if no startdate is given', () => {
expect.assertions(1);
return expect(MyService.fetch()).rejects.toEqual({
error: 'Your code message',
});
});
But how do I write if I just want to test that a promise has been rejected regardless of reason.
Try to use .toBeDefined() instead of .toEqual(...)
EDIT:
You could also use .toThrow(), the method which is actually recommended by JEST
As I found later you needed to use async/await to test with this
Here is an example on how to test with them:
it('should test promise reject', async () => {
await expect(toReject(true)).rejects.toThrow()
});
Test the code here
If you expect a promise to be rejected use the .rejects.
test('should reject if no startdate is given', () => {
return expect(MyService.fetch()).rejects.toMatch('error');
});
You can combine async and await with .resolves or .rejects.
test('should reject if no startdate is given', async () => {
await expect(MyService.fetch()).rejects.toThrow('error');
});
I'm using Mocha and SuperTest to test my Express API. However my first test always seems to pass when inside the .then() of my request().
I'm passing in a String to a test that is expecting an Array. So should definitely fail the test.
It fails outside of the then() as expected, but I won't have access to the res.body there to perform my tests.
Here is my code:
const expect = require('chai').expect;
const request = require('supertest');
const router = require('../../routes/api/playlist.route');
const app = require('../../app');
describe('Playlist Route', function() {
// before((done) => {
// }
describe('Get all playlists by user', function() {
it('Should error out with "No playlists found" if there are no Playlists', function() {
request(app).get('/api/playlists/all')
.then(res => {
const { body } = res;
// Test passes if expect here
expect('sdfb').to.be.an('array');
})
.catch(err => {
console.log('err: ', err);
});
// Test fails if expect here
expect('sdfb').to.be.an('array');
})
})
});
I found this article but I'm not using a try catch block, but I thought maybe it could have something to do with the promise.
Quick reponse
it('decription', function(done) {
asyncFunc()
.then(() => {
expect(something).to.be(somethingElse)
done()
})
})
Detailed response in the comment of #jonrsharpe
Rather than using done, simply return request(app).get('/api/playlists/all') since request() returns a promise. Since you have expect('sdfb').to.be.an('array'); twice, remove the one that's not in the .then callback. When using asynchronous code, remember that synchronous code that appears to come after the async chain will execute before the promise .then handlers. This is counterintuitive.
Here's the .then approach:
it('should ...', () => {
return request(app)
.get('/api/playlists/all')
.then(res => {
const {body} = res;
// assert here
});
});
The other approach is to await the promise yourself in the test case function, then make assertions on the resolved response object. In this case, drop the then chain. This approach is generally preferred as it reduces nesting.
it('should ...', async () => {
const res = await request(app).get('/api/playlists/all');
const {body} = res;
// assert here
});
If you don't let Mocha know you're working with asynchronous code by returning a promise, awaiting the promises, or adding and calling the done parameter, the assertions occur asynchronously after the test is over and disappear into the void, creating a false positive.
Skip .catch either way. Since you've informed Mocha of the promise, if it rejects, it'll let you know.
When I try to run this, i get "UnhandledPromiseRejectionWarning". But last "catch" received control anyway with correct "err" object.
I have got two warnings:
UnhandledPromiseRejectionWarning
PromiseRejectionHandledWarning
If I comment "return delay(5000);" all works fine.
Why does Node.JS handle "promiseErr" before I do that?
const delay = (ms: number) => new Promise(res => setTimeout(res, ms));
let promiseErr = new Promise( (resolve, reject) => {
reject(new Error("__error__"));
});
let promiseOk = new Promise( (resolve, reject) => {
resolve();
});
promiseOk
.then( () => {
return delay(5000);
})
.then( () => {
return promiseErr;
})
.then( () => {
console.log("OK");
})
.catch( (err) => {
console.log(`ERR ${err}`);
});
program output
You have a rejected promise asynchronously (after 5000ms). Node.js detects unhandled promises by looking at promises that were not handled synchronously or within a microtick (inside a then).
Since Node.js cannot know "for sure" when a promise rejection is unhandled at the moment it errors on the safe side and gives you the warning. It is generally better to add catch handlers to promise errors synchronously as much as possible.
You can suppress the warning by adding a .catch(() => {}) to promiseErr when you create it which will handle the exception:
var promiseErr = ...
promiseErr.catch(() => {}); // add a catch handler without changing the original
In general - the solution is to not write code in such an error prone way. If promiseOk or delay rejects (which Node has no way of knowing) - then the exception in promiseErr itself is indeed unhandeld - so this is not really a safe way to write code.
I am working on a simple TCP client for a server and am using the latest node 7.6 because of the async/await functions. I'm new to node and asynchronous coding, so I apologize if this is stupidly easy.
I want to run a function that calls the callServer() function with specific parameters, wait until it finishes getting the data, and return the data as a variable.
Here is my code:
'use strict'
const net = require('net')
var formattedJson = funcRequestToJson("Server.GetStatus", false)
doThings()
async function doThings() {
var info = await callServer()
}
async function callServer() {
var client = new net.Socket()
client.connect(1705, '192.168.28.16', () => {
console.log('connected to server')
client.write(formattedJson)
})
client.on('data', (data) => {
client.destroy()
//return await data
console.log(data.toString())
})
client.on('close', () => {
})
}
// method and paramBool are always required
// macAddress, paramKey, paramValue are required for if paramBool is true
function funcRequestToJson(method, paramBool, macAddress, paramKey, paramValue) {
var objectRequest = {}
objectRequest[ "jsonrpc" ] = "2.0"
objectRequest[ "method" ] = method
objectRequest[ "id" ] = 0
if (paramBool == true) {
objectRequest[ "params" ] = {
"client": macAddress,
[paramKey]: paramValue
}
}
var json = (JSON.stringify(objectRequest) + '\r\n')
return json
}
So I didn't declare objectRequest() as async because it's not waiting on the server, but I think callServer() should be async, right? I know this can be done with promises, but I wanted to use async/await and this seems to be right.
Now, I want to return the data that comes from inside callServer() and client.on('data', (data) but I can't seem to figure out how to do it asynchronously. I would think there'd be a way to make an async function and call it with await like I tried (await return data) but it never works right.
I'm sorry if this is terribly convoluted, but I've been poring over async node tutorials for the past week and am still stuck.
Thanks!
Async/Await relies on code that uses promises for async operations. So you need to return a promise from any async operation in order to use it with async/await.
So, callServer() needs to return a promise that is resolved when the async operation inside it is done. In fact, you can only await an async operation in a function if that function returns a promise. await saves you from having to write .then() handlers on promises, but async/await does not magically know when async operations are done. You still have to wrap them in promises.
Here's an example of how you could make callServer() return a promise:
async function callServer(formattedJson) {
return new Promise((resolve, reject) => {
let client = new net.Socket()
client.connect(1705, '192.168.28.16', () => {
console.log('connected to server')
client.write(formattedJson)
})
client.on('data', (data) => {
resolve(data);
client.destroy()
})
client.on('close', () => {
})
client.on('error', reject);
});
}
Sample Usage:
try {
var info = await callServer(funcRequestToJson("Server.GetStatus", false));
} catch(e) {
// error here
}
Just to show you what await is doing, in ES5 (without async/await), the sample usage would be this:
callServer(funcRequestToJson("Server.GetStatus", false)).then(info => {
// info is available here
}).catch(err => {
// error here
});
So, await is just letting you avoid writing the .then() handler. Internally in the execution of the code, there's just a promise that the interpreter sets up a .then() handler for so it will know when that promise is resolved. This is syntactical sugar, not really any magic with async operations. You still have to use promises for all your async operations. You can use await instead of .then() and your code will appear more sequential even though it's really the same under the covers.
People think that await allows one to write asynchronous code as if it was synchronous, but that isn't really the case, especially if you handle errors and understand concurrency issues. It will look more synchronous, but isn't actually any more synchronous than it was with .then() in ES5.
And, watch out for error handling. In people's quest to write synchronous looking code, people seem to completely forget to handle rejected promises in their async operations (which are handled with try/catch when using await). I'm personally not yet convinced that ES6 is a step forward when it comes to error handling as the early indications are that ES6 seems to encourage people to just forget about error handling or get lazy and not do it, whereas it's easier when using .then() to just know that there should be a .catch() somewhere for it to be solid code. Maybe that's just a learning process, but it seems to be an early issue when people use await.