I am trying to create a helper function that makes an async call which is a part of my data setup for the protactor test. is there a way i can wait for the response of the function and then proceed with the tests, here is what I am trying to do.
so basically the test should wait until the async call lo loaddata() is finished. I have read about use of promises but couldn't get to implement it sucessfully.
"use strict";
describe('sample passing test spec', function() {
describe('sample passing test suite', function() {
loaddata();
it('sample passing test', function () {
datall();
expect("1").toEqual("2");
});
});
});
loaddata() is basically making a socket connection
function loaddata(){
var net = require('net');
var client = new net.Socket();
client.connect(20000, '127.0.0.1', function() {
console.log('Connected');
client.write('Hello, server! Love, Client\n');
});
client.on('data', function(data) {
console.log('Received: ' + data);
client.destroy(); // kill client after server's response
});
client.on('close', function() {
console.log('Connection closed');
});
return "function execution over"
}
You would need to tweak loaddata to return a promise which would Protractor put on the Control Flow - a queue of pending promises to resolve:
function loaddata() {
var deferred = protractor.promise.defer();
var net = require('net');
var client = new net.Socket();
client.connect(20000, '127.0.0.1', function() {
console.log('Connected');
client.write('Hello, server! Love, Client\n');
});
client.on('data', function(data) {
console.log('Received: ' + data);
client.destroy(); // kill client after server's response
deferred.fulfill(true);
});
client.on('close', function() {
console.log('Connection closed');
});
return deferred.promise;
}
If this is something you need to do globally before your test run, put it into onPrepare() and return. If loaddata returns a promise, Protractor would first resolve it and only then run tests:
onPrepare: function () {
return loaddata();
},
Related
I have a server application (we'll call ServerApp1) which is going to be running on an Azure VM instance. I have a separate server (which we'll call ServerApp2) on a different machine which will be communicating with ServerApp1 and a separate client. The Azure VM is going to be spun up and/or down depending on need, so it's quite possible that the VM (and thus ServerApp1) aren't even alive to respond to request from ServerApp2. My client is polling ServerApp2 to ask for the status of ServerApp1, but if the VM is currently down then that request hangs for like 20 seconds before issuing an error with code ETIMEDOUT. What I'd like is for ServerApp2 to make the request to ServerApp1 to see if it's alive, but after about 1 or 2 seconds of not getting a response to then simply stop and tell the client that's it's not currently running. I thought I could get away with adding a {timeout:2000} parameter to my axios call, but this doesn't seem to change the behavior in any noticeable way.
Here's the function that gets called when the client asks ServerApp2 what the status is of ServerApp1:
router.get('/getCurrentConsoleStatus', function(req, res) {
async function getStatus() {
try {
const result = await consoleDataService.getConsoleStatus();
if (result.message === 'Begin listen for job.') {
console.log('The app is ready!');
} else {
console.log('The console app is not ready');
}
} catch (error) {
console.log(`Error communicating with console app: ${error}`);
}
}
getStatus();
});
I have a function which creates the root Axios object:
var axios = require('axios');
module.exports = axios.create({
baseURL: 'baseURL',
timeout: 1000,
headers: {
'Content-type': 'application/json'
}
});
And then the function that gets called in consoleDataService.getConsoleStatus() looks like this:
exports.getConsoleStatus = async function() {
const res = await axios({
method: 'get',
url: '/status'
});
return res.data;
};
Thanks to #JonEdwards for the suggestion to use Promise.race. I ended up solving the issue with this function which tries to take the first promise which resolves first.
exports.getConsoleStatus = () => {
var sleep = function() {
return new Promise(resolve => {
setTimeout(function() {
resolve({ status: false });
}, 2000);
});
};
var fetch = async function() {
const res = await http({
method: 'get',
url: '/status'
});
return new Promise(resolve => {
resolve(res.data);
});
};
async function getStatus() {
const asyncFunctions = [sleep(), fetch()];
const result = await Promise.race(asyncFunctions);
return result;
}
return getStatus();
};
I want to connect to a Unix Domain Socket server in a Node application. If the connection succeeds and was opened, a loop (that may take some time) shall be executed. If an error occurs during the execution of this loop, it should receive some kind of notification. If a connection to the client is not possible at all, the loop should not be executed in the first place (that seems to work with the Promise). To me this sounds like the most simple thing in the world, but I just can't get it to work... This is what I have until now:
new Promise(function(resolve, reject) {
let connection = net.createConnection('/tmp/socket.s', () => {resolve(connection);})
.on('data', function(data) {
// Do something (during loop execution)
})
.on('error', reject); // If this callback is executed, the while loop should terminate (by receiving some kind of signal within the loop)
}).then(function(connection) {
for(...) {
// Do stuff that takes some time, executes other callbacks, sends data to the socket
}
connection.end();
}, function(error) {
// Error handling
});
What am I missing?
Try to listen to the data event in the resolve section of the promise. The following code should do it:
const net = require('net');
/**
* Client
* --------------------------------------------
*/
new Promise((resolve, reject) => {
let client = net.createConnection({ path: '/tmp/socket.s'}, () => {
console.log('Client: connected ')
resolve(client);
});
// Reject on error
client.on('error', err => reject(err) );
client.on('end', () => {
console.log('Client: disconnected from server #1');
});
}).then( connection => {
connection.on('data', data => {
// Do stuff with the data
console.log(`Client: the server says: ${data.toString()}\n`);
if(data != 'Data recieved'){
// Just to ensure that the following loop runs only once
for (let i = 0; i <= 10; i++) {
setTimeout(() => {
// Send data to the server
connection.write(`Client Data ${i}`);
if (i == 10) {
// Close the connection after everything is done
connection.end();
}
}, i*2000);
}
}
});
}, error => {
console.log('Client: promise rejection error', error );
});
My test server looks like this
const net = require('net');
/**
* Server
* --------------------------------------------
*/
const server = net.createServer( connectionListener => {
console.log(`#${process.pid} Server: client connected`);
connectionListener.on('end', () => {
console.log(`#${process.pid} Server: client disconnected`);
});
connectionListener.write('Hello\r\n');
connectionListener.on('data', data => {
console.log(`#${process.pid} Server: client sends: ${data.toString()}`);
connectionListener.write('Data recieved');
});
});
server.on('error', (err) => {
console.log(err);
server.close();
});
server.listen('/tmp/socket.s', () => {
console.log(`#${process.pid} Server: server bound`);
});
process.on('exit', code => {
console.log(code);
server.close();
});
process.on('SIGTERM', () => server.close() );
process.on('SIGINT', () => server.close() );
In this example the client sends data to server and the server replies each time. The client then closes the connection after having sent data 10 times.
P.S. There is no need to use a Promise unless you do need to return a promise at some point in your code.
I can't get my head around why this is not working. I have a module which sends a HTTP POST request containing some payload using the native nodejs http module. I am stubbing the request method with sinon and pass the PassThrough stream for the request and response streams.
DummyModule.js
const http = require('http');
module.exports = {
getStuff: function(arg1, arg2, cb) {
let request = http.request({}, function(response) {
let data = '';
response.on('data', function(chunk) {
data += chunk;
});
response.on('end', function() {
// spy should be called here
cb(null, "success");
});
});
request.on('error', function(err) {
cb(err);
});
// payload
request.write(JSON.stringify({some: "data"}));
request.end();
}
};
test_get_stuff.js
const sinon = require('sinon');
const http = require('http');
const PassThrough = require('stream').PassThrough;
describe('DummyModule', function() {
let someModule,
stub;
beforeEach(function() {
someModule = require('./DummyModule');
});
describe('success', function() {
beforeEach(function() {
stub = sinon.stub(http, 'request');
});
afterEach(function() {
http.request.restore()
});
it('should return success as string', function() {
let request = new PassThrough(),
response = new PassThrough(),
callback = sinon.spy();
response.write('success');
response.end();
stub.callsArgWith(1, response).returns(request);
someModule.getStuff('arg1', 'arg2', callback);
sinon.assert.calledWith(callback, null, 'success');
});
});
});
The spy does not get called and the test fails with AssertError: expected spy to be called with arguments. So the response.on('end', ...) does not get called and therefore the test failure. Does the end event on the response stream needs to be triggered somehow?
It's working now. First, the events need to be emitted using the emit method.
Second, the events need to be emitted right after the someModule.getStuff(...) method call:
...
someModule.getStuff('arg1', 'arg2', callback);
response.emit('data', 'success');
response.emit('end');
sinon.assert.calledWith(callback, null, 'success');
...
I have an Angular service that makes a call to the server and fetch the user list. The service returns a Promise.
Problem
Promise is not being resolved until and unless I call $rootScope.$digest(); either in the service or in the test itself.
setTimeout(function () {
rootScope.$digest();
}, 5000);
Apparently, Calling $rootScope.$digest(); is a workaround and I cannot call it in the angular service so I am calling it in the unit test with an interval of 5 seconds which I think is a bad practice.
Request
Please suggest an actual solution for this.
Given below is the test that I have written.
// Before each test set our injected Users factory (_Users_) to our local Users variable
beforeEach(inject(function (_Users_, $rootScope) {
Users = _Users_;
rootScope = $rootScope;
}));
/// test getUserAsync function
describe('getting user list async', function () {
// A simple test to verify the method getUserAsync exists
it('should exist', function () {
expect(Users.getUserAsync).toBeDefined();
});
// A test to verify that calling getUserAsync() returns the array of users we hard-coded above
it('should return a list of users async', function (done) {
Users.getUserAsync().then(function (data) {
expect(data).toEqual(userList);
done();
}, function (error) {
expect(error).toEqual(null);
console.log(error.statusText);
done();
});
///WORK AROUND
setTimeout(function () {
rootScope.$digest();
}, 5000);
});
})
service
Users.getUserAsync = function () {
var defered = $q.defer();
$http({
method: 'GET',
url: baseUrl + '/users'
}).then(function (response) {
defered.resolve(response);
}, function (response) {
defered.reject(response);
});
return defered.promise;
}
You can cause the promises to flush with a call to $timeout.flush(). It makes your tests a little bit more synchronous.
Here's an example:
it('should return a list of users async', function (done) {
Users.getUserAsync().then(function (data) {
expect(data).toEqual(userList);
done();
}, function (error) {
expect(error).toEqual(null);
console.log(error.statusText);
done();
});
$timeout.flush();
});
Aside: the failback won't be handled so it adds additional complexity to the test.
Meteor.collection.insert() accepts callback as an argument. As an example, one can create a brand new Meteor project and run the following code in the browser's console.
my_collection = new Meteor.Collection("myCollection");
my_collection.insert(
{some: "object"},
function() {
console.log("finished insertion");
})
When I take this same code and put it in a Laika test, the callback argument never gets called. Here is my test code:
suite('testing Laika out', function() {
test('inserting into collection', function(done, server, client) {
client.eval(function() {
my_collection = new Meteor.Collection("myCollection");
my_collection.insert(
{some: "object"},
function() {
console.log("finished insertion");
done();
})
})
})
})
Anyone know why the callback function isn't called in this Laika test? This seems to be an issue for more than just Meteor.collection.insert().
(I'm running Ubuntu 13.04, Meteor 0.7.0.1, Laika 0.3.1, PhantomJS 1.9.2-6)
The problem is that you're trying to call done(); inside of your insert callback, when it doesn't exist in that function scope. You actually need to listen for the insertion into my_collection and emit a signal which is picked up by either the client or server (the client in your case). Also, you obviously won't be initializing your collection in your test; that should be done in your production code.
Try this instead:
var assert = require("assert");
suite('testing Laika out', function() {
test('inserting into collection', function(done, server, client) {
client.eval(function() {
addedNew = function(newItem) {
console.log("finished insertion");
emit("done", newItem)
};
my_collection = new Meteor.Collection("myCollection");
my_collection.find().observe({
added: addedNew
});
my_collection.insert(
{some: "object"}
)
}).once("done", function(item) {
assert.equal(item.some, "object");
done();
});
});
})
Check out https://github.com/arunoda/hello-laika for the basic examples for testing.
Well, Mr. jonS90, if you were to run Laika with the --verbose flag, you would notice that an exception is quietly being thrown:
[client log] Exception in delivering result of invoking '/myCollection/insert': ReferenceError: Can't find variable: done
You see, you don't have access to done() in that context. Here's how you should revise your code:
test('inserting into collection', function(done, server, client) {
client.eval(function() {
my_collection = new Meteor.Collection("myCollection");
finishedInsertion = function () {
console.log("finished insertion");
emit('done')
}
my_collection.insert(
{some: "object"},
finishedInsertion)
})
client.once('done', function() {
done();
})
})