Start locomotive.js 0.4.x for functional testing - functional-testing

The way to start locomotive.js 0.3.x no longer works in 0.4.x, as the signature of app.boot is different. I have:
before(function(done) {
var self = this;
var lcm = new locomotive.Locomotive();
lcm.boot('test', function() {
self.app = lcm.express;
self.app.listen(4000, done);
});
});
It throws "Error: connect ECONNREFUSED" when I tried to connect with supertest:
request(this.app)
.post('problems/' + problemId + '/solution_ratings')
.set('Content-Type', 'application/json')
.send({access_token: playerId, solution_group_id: 1, rate: 4})
.expect(200, done);
What is the proper way to start a locomotive server for functional testing?
[Update]
I have to start the server in the same process as the test in order to use sinon.js to stub/spy calls to models.

I've answered this on Locomotive's github for an issue, however I wanted to share here to get some feedback, as in better ways, cleaner, or any other input you might have.
I require multiple servers in an OAuth2 environment (auth, resource, dashboard..) of which mostly are Locomotive framework based.
I like functional tests since they best represent OAuth2 based authentication as opposed to only focusing my tests on a resource service where the authentication token might not best represent the user.
Here is the setup I've come up with for starting up the locomotive servers:
For your tests, say like in test/util.severs.js
var fork = require('child_process').fork,
async = require("async");
var authApp;
var serverStatus = [];
var start = function(done) {
authApp = fork( __dirname + '/../../authorization/server.js');
serverStatus.push(function(callback){
authApp.on('message', function(m){
//console.log('[AUTHORIZATION] SENT MESSAGE: ', m);
if (m.status == 'listening') return callback();
});
});
// add others servers if you swing that way!
async.parallel(serverStatus, function(){
done();
});
}
var stop = function(done) {
authApp.kill();
done();
}
module.exports = {
start: start,
stop: stop
};
Note that I'm using async here since I'm working with multiple servers (Environment is in OAuth2 which requires many servers to startup (IE resource, dashboard...)), ignore async if all you'll ever have is one server.
require the above file in your Mocha tests and do
servers = require('./util/servers');
...
before(servers.start);
// tests away!!!
after(servers.stop);
Then in each of my locomotive-project/server.js I do the following...
// if being started as a parent process, send() won't exist, simply define
// it as console.log or what ever other thing you do with logging stuff.
if (process.send === undefined){
process.send = function(msg){
console.log("status: ", msg.status);
};
}
process.send({status: 'starting'});
...
app.boot(function(err) {
if (err) {
process.send({status: 'error', message: err});
return process.exit(-1);
} else {
// notify any parents (fork()) that we are ready to start processing requests
process.send({status: 'listening'});
}
});
Using Locomotive 0.4.x here, could be different based on your version.
Is this the best way to go? Ideally I would like to move this over to Grunt, that is test server initialization (which is quite hefty as we build lots of data into the test DB), and then functional tests could run. So wondering if anyone has delved into grunt to do this instead of a before() task in Mocha.

Related

Using asynchronous Nightwatch After Hook with client interaction does not work

As far as I can tell, using promises or callbacks in After hook prevents Command Queue from executing when using promises / callbacks. I'm trying to figure out why, any help or suggestions are appreciated. Closest issue I could find on github is: https://github.com/nightwatchjs/nightwatch/issues/341
which states: finding that trying to make browser calls in the after hook is too late; it appears that the session is closed before after is run. (exactly my problem). But there is no solution provided. I need to run cleanup steps after my scenarios run, and those cleanup steps need to be able to interact with browser.
https://github.com/nightwatchjs/nightwatch/wiki/Understanding-the-Command-Queue
In the snippet below, bar is never outputted. Just foo.
const { After } = require('cucumber');
const { client } = require('nightwatch-cucumber');
After(() => new Promise((resolve) => {
console.log('foo')
client.perform(() => {
console.log('bar')
});
}));
I also tried using callback approach
After((browser, done) => {
console.log('foo');
client.perform(() => {
console.log('bar');
done();
});
});
But similar to 1st example, bar is never outputted, just foo
You can instead use something like:
const moreWork = async () => {
console.log('bar');
await new Promise((resolve) => {
setTimeout(resolve, 10000);
})
}
After(() => client.perform(async () => {
console.log('foo');
moreWork();
}));
But the asynchronous nature of moreWork means that the client terminates before my work is finished, so this isn't really workin for me. You can't use an await in the perform since they are in different execution contexts.
Basically the only way to get client commands to execute in after hook is my third example, but it prevents me from using async.
The 1st and 2nd examples would be great if the command queue didn't freeze and prevent execution.
edit: I'm finding more issues on github that state the browser is not available in before / after hooks: https://github.com/nightwatchjs/nightwatch/issues/575
What are you supposed to do if you want to clean up using the browser after all features have run?
Try the following
After(async () => {
await client.perform(() => {
...
});
await moreWork();
})

Jasmine/Protractor: stop test on failure in beforeEach

I am currently writing tests protractor and I was wondering if there is some possibility to cancel test execution as soon as something in the beforeEach fails (and return some useful message like "precondition failed: could not login user").
I.e. I have some helper methods in the beforeEach that login the user and then do some setup.
beforeEach:
1) login user
2) set some user properties
Obviously it does not make any sense to execute the 2nd step if the first one fails (actually its quite harmful as the user gets locked which is not nice). I tried to add an "expect" as part of the 1st step, but the 2nd step was still executed -> fresh out of ideas.
Strictly answering your question and without external dependencies:
beforeEach(function() {
// 1) login user
expect(1).toBe(1);
// This works on Jasmine 1.3.1
if (this.results_.failedCount > 0) {
// Hack: Quit by filtering upcoming tests
this.env.specFilter = function(spec) {
return false;
};
} else {
// 2) set some user properties
expect(2).toBe(2);
}
});
it('does your thing (always runs, even on prior failure)', function() {
// Below conditional only necessary in this first it() block
if (this.results_.failedCount === 0) {
expect(3).toBe(3);
}
});
it('does more things (does not run on prior failure)', function() {
expect(4).toBe(4);
});
So if 1 fails, 2,3,4,N won't run as you expect.
There is also jasmine-bail-fast but I'm not sure how it will behave in your before each scenario.
jasmine.Env.prototype.bailFast = function() {
var env = this;
env.afterEach(function() {
if (!this.results().passed()) {
env.specFilter = function(spec) {
return false;
};
}
});
};
then just call:
jasmine.getEnv().bailFast();
(credit goes to hurrymaplelad who wrote an npm that does just that, however you don't need to use it)
jasmine-bail-fast does exactly what you did overriding the specFilter function, but does it on afterEach. So it will only fail after the first "it" is run. It won't help solving this specific case.
with jasmine2 we can set throwOnExpectationFailure to true.
For example in protractor config:
//protractor.conf.js
exports.config = {
//...
onPrepare: () => {
jasmine.getEnv().throwOnExpectationFailure(true);
}
};

a file upload progress bar with node (socket.io and formidable) and ajax

I was in the middle of teaching myself some Ajax, and this lesson required building a simple file upload form locally. I'm running XAMPP on windows 7, with a virtual host set up for http://test. The solution in the book was to use node and an almost unknown package called "multipart" which was supposed to parse the form data but was crapping out on me.
I looked for the best package for the job, and that seems to be formidable. It does the trick and my file will upload locally and I get all the details back through Ajax. BUT, it won't play nice with the simple JS code from the book which was to display the upload progress in a progress element. SO, I looked around and people suggested using socket.io to emit the progress info back to the client page.
I've managed to get formidable working locally, and I've managed to get socket.io working with some basic tutorials. Now, I can't for the life of me get them to work together. I can't even get a simple console log message to be sent back to my page from socket.io while formidable does its thing.
First, here is the file upload form by itself. The script inside the upload.html page:
document.getElementById("submit").onclick = handleButtonPress;
var httpRequest;
function handleResponse() {
if (httpRequest.readyState == 4 && httpRequest.status == 200) {
document.getElementById("results").innerHTML = httpRequest.responseText;
}
}
function handleButtonPress(e) {
e.preventDefault();
var form = document.getElementById("myform");
var formData = new FormData(form);
httpRequest = new XMLHttpRequest();
httpRequest.onreadystatechange = handleResponse;
httpRequest.open("POST", form.action);
httpRequest.send(formData);
}
And here's the corresponding node script (the important part being form.on('progress')
var http = require('http'),
util = require('util'),
formidable = require('formidable');
http.createServer(function(req, res) {
if (req.url == '/upload' && req.method.toLowerCase() == 'post') {
var form = new formidable.IncomingForm(),
files = [],
fields = [];
form.uploadDir = './files/';
form.keepExtensions = true;
form
.on('progress', function(bytesReceived, bytesExpected) {
console.log('Progress so far: '+(bytesReceived / bytesExpected * 100).toFixed(0)+"%");
})
.on('file', function(name, file) {
files.push([name, file]);
})
.on('error', function(err) {
console.log('ERROR!');
res.end();
})
.on('end', function() {
console.log('-> upload done');
res.writeHead(200, "OK", {
"Content-Type": "text/html", "Access-Control-Allow-Origin": "http://test"
});
res.end('received files: '+util.inspect(files));
});
form.parse(req);
} else {
res.writeHead(404, {'content-type': 'text/plain'});
res.end('404');
}
return;
}).listen(8080);
console.log('listening');
Ok, so that all works as expected. Now here's the simplest socket.io script which I'm hoping to infuse into the previous two to emit the progress info back to my page. Here's the client-side code:
var socket = io.connect('http://test:8080');
socket.on('news', function(data){
console.log('server sent news:', data);
});
And here's the server-side node script:
var http = require('http'),
fs = require('fs');
var server = http.createServer(function(req, res) {
fs.createReadStream('./socket.html').pipe(res);
});
var io = require('socket.io').listen(server);
io.sockets.on('connection', function(socket) {
socket.emit('news', {hello: "world"});
});
server.listen(8080);
So this works fine by itself, but my problem comes when I try to place the socket.io code inside my form.... I've tried placing it anywhere it might remotely make sense, i've tried the asynchronous mode of fs.readFile too, but it just wont send anything back to the client - meanwhile the file upload portion still works fine. Do I need to establish some sort of handshake between the two packages? Help me out here. I'm a front-end guy so I'm not too familiar with this back-end stuff. I'll put this aside for now and move onto other lessons.
Maybe you can create a room for one single client and then broadcast the percentage to this room.
I explained it here: How to connect formidable file upload to socket.io in Node.js

Proper separation of concerns natively in node.js?

I am a total node.js noobie and trying to figure out the best way to structure my application with proper separation of concerns.
I am using mongodb via mongoose and have successfully gotten my controllers separated out using node.js modules and am trying to then separate out my models. What I've gone appears to work, but when I check the database nothing has been saved. Also, I tried a console.log() in the save function and nothing gets logged.
from my server.js I have:
app.post(api.urlslug + '/messages', messagesapi.insert);
I then have a /controllers/api/messages.js:
var m = require('../../models/message');
exports.index = function(req, res, next){
res.send('all the messages...');
}
exports.insert = function(req, res, next){
var message;
message = new m.Message({
messagebody: req.body.messagebody
});
message.save(function(err) {
console.log('here we are in the save');
if(!err) {
return console.log('message created');
} else {
return console.log(err);
}
});
return res.send(message);
}
and my /models/message.js looks like this:
// required modules
var mongoose = require('mongoose')
, db = require('../models/db');
// setup database connection
mongoose.connect(db.connectionstring());
var Message = exports.Message = mongoose.model('Message', new mongoose.Schema({
messagebody: String
}));
When I post to the API I get a the proper JSON back and it even has the _id field with what appears to me as a mongodb provided unique id. With that, I am having trouble understanding why it is not actually going into mongodb if it appears to be creating the object and communicating with mongodb correctly.
sounds like a connection is not being made. try listening to the open/error events of the default mongoose connection to find out why.
function log (msg) { console.log('connection: ', msg) }
mongoose.connection.on('open', log);
mongoose.connection.on('error', log);

Node.js Express mongoose query find

I have a little problem with Express and mongoose using Node.js . I pasted the code in pastebin, for a better visibility.
Here is the app.js: http://pastebin.com/FRAFzvjR
Here is the routes/index.js: http://pastebin.com/gDgBXSy6
Since the db.js isn't big, I post it here:
var mongoose = require('mongoose'),
Schema = mongoose.Schema;
module.exports = function () {
mongoose.connect('mongodb://localhost/test',
function(err) {
if (err) { throw err; }
}
);
};
var User = new Schema({
username: {type: String, index: { unique: true }},
mdp: String
});
module.exports = mongoose.model('User', User);
As you can see, I used the console.log to debug my app, and I found that, in routes/index.js, only the a appeared. That's weird, it's as if the script stopped (or continue without any response) when
userModel.findOne({username: req.body.username}, function(err, data)
is tried.
Any idea?
You never connect to your database. Your connect method is within the db.export, but that is never called as a function from your app.
Also, you are overwriting your module.exports - if you want multiple functions/classes to be exported, you must add them as different properties of the module.export object. ie.:
module.export.truthy = function() { return true; }
module.export.falsy = function() { return false; }
When you then require that module, you must call the function (trueFalse.truthy();) in order to get the value. Since you never execute the function to connect to your database, you are not recieveing any data.
A couple of things real quick.
Make sure you're on the latest mongoose (2.5.3). Update your package.json and run npm update.
Try doing a console.log(augments) before your if (err). It's possible that an error is happening.
Are you sure you're really connecting to the database? Try explicitly connecting at the top of your file (just for testing) mongoose.connect('mongodb://localhost/my_database');
I'll update if I get any other ideas.

Resources