Automate UI testing with Javascript, node - starting & stopping a web server - javascript

I'm currently investiagating automated UI testing using JavaScript on windows with node.js and phantom.js and unsurprisingly I've found many frameworks that can help in this regard (casper.js, Buster.js, etc).
The one thing that seems to be missing from the frameworks I have looked at so far is stopping and starting a web server to server the web pages so that testing framework can perform its testing. One exception is WebDriver.js which uses the Selenium standalone server but this relies on a server written Java and at the moment I'd prefer to find a node based solution if at all possible.
From the node perscpective I've looked at Connect.js and also Http-Server (which I particularly like) but the issue is starting and stopping these from a JavaScript test.
I've attempted to create a casper.js test that would interact with a server, run the test and then stop the server but I can't get it to work, here's an example script
var childProcess = require('child_process').spawn('http-server', '/TestSite');
casper.test.begin("Load-page", 1, function suite(test){
casper.start('http://localhost:8080/',function(){
test.assertTitle("test page");
});
casper.run(function(){
test.done();
childProcess.kill();
});
});
I call this from the command line using the following command (casper is in my Path variable):
casperjs Load-page testFile.js
What I was hoping would happen is the http-server would start, casper would start the test and then after the test was run the http-server would be killed.
I've also tried similar with Connect:
var server= connect.createServer(connect.static('/TestSite')).listen(8080)
casper.test.begin("Load-page", 1, function suite(test){
casper.start('http://localhost:8080/',function(){
test.assertTitle("test page");
});
casper.run(function(){
test.done();
server.stop();
});
});
But again with no luck.
I can run the Casper sample tests which work and I've also got Node in my Path as well and can call the REPL from the command prompt.
The directory structure is:
Code
/TestSite
/node_modules
and I run the tests from the Code folder.
Am I simply unable to do this or am I just not getting how it should work?

When you say "no luck" what do you mean?
The connect example looks mostly OK, and I'd prefer it over spawning a subprocess. Bear in mind that listen is potentially async so the server might not be available immediately though. The second param to listen is a callback that will be run once the server is listening - maybe try running the tests in that callback instead?
Pro Tip: Don't rely on port 8080 always being free on whatever machine you're running on - passing in 0 for the port will cause the server to start on a random port, you can then do server.address().port in the listen callback to get the port that was chosen

I managed to get it working using a combination of differebt scripts and using child_process spawn.
I created a script called startServer.js that would start the server using Connect:
var connect = require('connect');
var server= connect.createServer(connect.static('TestSite'));
server.listen(8081);
I created another script runTests.js that would call the server script via spawn and then call Casper, again via spawn, and run all the capser tests that are in a folder called tests relative to where the script is run from.
var child_process = require('child_process');
var stillRunning = true;
var server = child_process.spawn('node', ['createServer.js']);
var casper = child_process.spawn('casperjs', ['test tests']);
casper.stdout.on('data', function(data){
console.log(data.toString());
});
casper.stderr.on('data', function(data){
console.log('Error: ' + data);
});
casper.on('exit', function(code){
server.kill();
process.exit(0);
});
To use this at the command prompt navigate to the folder where the script is and then run node runTests.js and the server will be started and the tests run against the site

Related

How to run child_process.exec correctly on an ajax request?

There is a server, that I have an access to, but do not have ownership on. It serves a node js / express application on a default port 3000. There are several scripts, that are usually run either manually from the terminal or by cron job. What I want to do is to have a button on the client-side and make an ajax request to a certain route and execute a node js command with inline arguments. For example:
node script.js 123
All routes are set and working. I have a CliController file that handles requests and has to run the command above. Currently I am using the following code:
cp.exec(`node script.js ${ip}`, function (err, stdout, stderr) {
if (err) {
console.log(err);
}
console.log(stdout);
console.log(stderr);
});
The script.js file is in root folder of the project, but the project itself was built by using express-generator and is being served using node bin/www command. There is a service/process on the server that runs nodemon to restart this project if it fails as well. Therefore I do not have access to output of that particular process.
If I run the command above in the terminal (from the root folder of the project, to be precise), it works fine and I see the output of the script. But if I press the button on the webpage to make a request, I am pretty sure that the script does not execute, because it has to make an update to database and I do not see any changes. I also tried to use child_process.spawn and child_process.fork and failed to get it working.
I also tried to kill nodemon and quickly start the project again to the see console output. If I do this, everything works.
What am I doing wrong ?
The process invoked may be in a blocking state, hence the parent script is simply waiting for the children process to terminate, or return something.
We can avoid this behaviour right into the shell command, by adding & (ampersand control operator) at the end.
This makes a command running in the background. (Notice, you can still control the children(s) process using the PID's and POSIX signals, this is another subject, but very related and you might find it very handy pretty soon).
Also notice that killing/stopping the parent script will also kill the children(s). This can be avoided using nohup.
This is not linked to JavaScript or node.js, but to bash, and can be used with anything in the shell.
cp.exec(`node script.js ${ip} &`, function (err, stdout, stderr) {
if (err) {
console.log(err);
}
console.log(stdout);
console.log(stderr);
});
Bash reference manual

Execute NPM module through cordova

I created an app using cordova and everything is fine, expect I need to use a node module which doesn't have a client-side equivalent because I'm dealing with file write streams etc. I have found Cordova hooks to be my best shot so far, where I create an app_run hook to execute a node file that runs a socket server to listen for events from the client side.
I know, a very longwinded solution, but seems logically correct to me, the issue is that when I do create the server, building the app through Visual Studio 2017, the app launches on my android phone, but VS hangs on the "deploy" stage. I guess that it has to do with the event chain, so I created an asynchronous script like this:
(async function () {
const server = require('http').createServer()
const io = require('socket.io')(server)
io.on('connection', function (socket) {
console.log('heyo')
socket.emit('hello world', 'hi')
})
server.listen(3000, function (err) {
if (err) throw err
console.log('listening on port 3000')
})
})();
but this doesn't seem to work either, somehow VS hangs on "deploy". If anyone can possibly guide me in the right direction, that would be highly appreciated.
PS: I know the title is off, but every time I use StackOverflow to get help with a particular attempt, I'm told to do it another way, so I'll leave it open.
If the goal is to use socket.io in your cordova app, there IS a JS client for the web that you need to use and you don't need to use npm for that, just add a link to your client js file in your index file. (should be in a "client" folder when you init socket.io via npm).
<script src="/socket.io/socket.io.js"></script>
<script>
const socket = io('http://localhost');
</script>
https://socket.io/docs/client-api/

How to execute a Node.js script on the server?

I'm beginning to learn web technologies and programming and I'm setting up my own local webserver. I have HTTPD, PHP, Python, MySQL all up and running on Windows. Now I want to add Node.js to the mix. I installed the Windows 64 bit installer. Now how do I begin? I have a basic Hello World script in a test.js file. But when I access this file in the browser it only displays as plain text. It's not executed. How to execute a Node.js script on the server?
Starting a node script is pretty simple. Just use your command line or terminal and execute the following command.
node /path/to/your/file.js
Doing so you'll start your node script. If you're going to start a server it's pretty much the same. Just keep in mind to define a server in your node file and start it. A simple server using express could look like this (You can also use a fully node way, this is just a simple example using express. You may check google for how to set up a simple node http server).
var express = require('express');
var app = express();
var port = 4000;
app.listen(process.env.port || port);
As you can see the specified port is set to 4000. You can simply adjust this by changing the value itself or passing in a node environment variable. To pass in an environment variable just start your server like this.
node port=3000 /path/to/your/file.js
This will finally pass the value of port to process.env.port which obviously will start your server on the port 3000.
you can use these packages to keep the file running so you won't have to login to server every time :-
forever
and you can just write :-
forever start app.js
nodemon
nodemon app.js
pm2
which is very useful , as it will auto restart your app when it crash or any error happens
pm2 start app.js
Your run your file: node server.js
Then it starts.
There should be specified in code on which port you run your server. Then it is accessible for example at http://localhost:3000/
As Quentin noted, I was thinking about "creating web server". Of course, you can run javascript code with Node.js without server. Then skip the part abot localhost, just use node test.js in console.

Node's spawn() silently failing when called from a forever script scheduled on boot

This is kind of a doozy. This issue is most likely server related and so my first recourse was AskUbuntu over here.
I'm trying to have crontab or rc.local or init.d to start a forever script on boot. It attaches a server to a port I can ping with some information and have it run a headless browser for me.
That said, it seems that I'm unable to get a response from Node.js's spawn():
var CASPER_PATH = '/home/ubuntu/dev/casperjs/bin/casperjs'; // actual binary location, not a symlink
var SCRIPTS_PATH = '/home/custom_user/endpoints/server.js';
var fileName = req.body.source + '_' + req.body.type + '.coffee'; // looks like: mysource_my_scrape_type.coffee
var scrapeId = 'test_scrape';
var user = 'user123';
var pass = 'pass123';
if (fs.existsSync(SCRIPTS_PATH + fileName)) {
// If file is in place, spawn casperjs
var sP = spawn(CASPER_PATH,
[SCRIPTS_PATH + fileName, '--ssl-protocol=any', '--user='+user, '--scrapeId='+scrapeId, '--pass='+pass],
{ detached: true },
function (err, stdout, stderr) {});
sP.stdout.on('data', function(data) { console.log('stdout', data.toString('utf8')); });
sP.stderr.on('data', function(data) { console.log('stderr', data.toString('utf8')); });
sP.stdout.on('close', function(code) { console.log('close', code); });
res.send({ scheduled: true, key: scrapeId });
} else {
res.send({ scheduled: false, error: 'Incorrect source, type or the script is missing.' });
}
Before I added the PHANTOMJS_EXECUTABLE env to crontab or rc.local (doesnt seem to matter no matter the user level), stdout was useful:
stdout Fatal: [Errno 2] No such file or directory; did you install
phantomjs?
close false
Now that the environment var is there, there is no output at all after spawn().
Mind you, Casper starts up just fine if a user (of any privilege level) runs node/forever from bash.
How can I see why spawn() is failing?
This actually looks like a combo-bug between forever, spawn and casperjs (maybe phantomjs).
I was able to reproduce your problem, here is the full code of my test application.
You didn't show the full code, so my guess is that you have an express application and there is a special URL to run the casperjs script.
I build a simple app like this and it behaved this way:
Just start app with node script.js (script.js is the express app which runs the casperjs script in server.js) - it works OK, renders response and writes output from the child process event handlers to console
Start app as root with init.d script - doesn't work, once the child is spawned, no event handlers are triggered
Start app as root with init.d script, replace casperjs with echo - the same, doesn't work (see, here we have this problem with just forever running as root, spawn and echo)
Start app as a regular user (not root) with init.d, replace casperjs with 'echo' - it works, event handlers are triggered, here I was almost sure the issue is solved, but ... :(
Start app as a regular user (not root) with init.d, put back casperjs - it doesn't work again, event handlers are not triggered
The practical solution to this it to use pm2, I did this:
# install pm2
sudo npm install -g pm2
# generate init.d scripts for pm2
# this command will fail, but hint about the correct format with sudo
pm2 startup ubuntu
# do this in the folder with your application
pm2 start script.js
# remember your application
pm2 save
# also useful
# sudo service stop/start/restart pm2
# pm2 stop/start/restart script
Now pm2 will start automatically with the system and it will launch your application. Everything works, child process event handlers are triggered.
I did not understand your requirement completely. But i do have a similar situation with Ubuntu headless server.
what i am trying to do here is what i did
First, How is my crontab ?
crontab -u USER -e
#reboot exec sudo -u USER /bin/bash /home/USER/SHELL_SCRIPT.sh
See, here i am actually starting a shell script, and not a node server
Now inside this shell script(SHELL_SCRIPT.sh)
#! /bin/bash
# SHELL_SCRIPT.sh
cd /home/USER/
/home/USER/.npm-packages/bin/forever start -p /home/USER -a -d --watch false --pidFile /home/USER/forever.pid -l /home/USER/forever.log -o /home/USER/forever.out -e /home/USER/forever.err /home/USER/MY_NODE.js
and even inside my MY_NODE.js i follow absolute path, i just ignore $PATH, and don't use that.
Inside this node server, I do 100's of spawn
Now, i did this around 2 years back, so if you ask me why do this way, which i cannot answer

Killing a Node.js program from a shell script

I'm running a node.js application which is acting as a man-in-the-middle proxy to proxy all of the requests I'm making through a PhantomJS headless testing environment. I want to spin up this proxy from either my PhantomJS test script (though I've looked into it and it seems that phantom does not have an exec() command for executing shell commands) or a small shell script which manages both processes. Ideally, it would do something like
#!/bin/bash
node proxy.js
phantomjs runTests.js
kill node process here
Is there any way that I can do this?
Moments after asking this question, I found a much better way to execute the phantom program from within my node app by using a child process. I placed my phantom script within the folder which contained my node app, and then used exec like this:
var exec = require('child_process').exec;
var _phantom = exec('phantomjs runTests.js',function(error,stdout,stderr){
console.log(stdout);
};
_phantom.on('exit',function(code,sig){
process.exit(code);
});
This means I could spin up my proxy server, then execute the child process. The _phantom.on('exit') block allows me to detect when the process exits on a code. Then, it's very simple to signal the node app to quit, using process.exit.

Categories