using mocha-phantomjs to automate functional testing - node.js

My project is using: Node, Coffeescript, SocketIO, Browserify and Mocha. (mocha for standard server-side unit tests)
I would like to automate some client-side interface testing using a headless browser. PhantomJS looked like the ideal choice (picked over Zombie due to web socket support).
The PhantomJS pages warn it is not a test runner, which I understand, and they recommend using the mocha-phantomjs project to drive your tests.
So I've been able to get the sample tests running (e.g. mocha-phantomjs tests/mixed.html), but my current problem is actually using PHANTOM within the tests. All the sample tests in the mocha-phantomjs repo seem to use standard mocha server-side unit test.
e.g. I can easily run mocha-phantomjs tests/mixed.html to view boring old unit tests. Or I can run phantomjs tests/login.coffee to load up my login screen... but how do I combine the two to make assertions on what I should expect to see on my login screen?
I can't find any examples of this on the web, and I'm struggling with understanding the best way to go about this.
Hope this all makes sense. Thanks in advance for any assistance.
UPDATE: I found the following suggestion by the author (here), but I don't really understand exactly what to do with it: phantomjs lib/mocha-phantomjs.coffee test/mixed.html

There's a fairly nice tutorial for testing with Mocha and Phantom.JS here.
The section on Mocha and PhantomJS is short, but the basic idea is to put DOM assertions and interactions into your Mocha test suite, run it a la client-side via a testrunner.html file, and then point mocha-phantomjs at the testrunner.html file.
To paraphrase, your Mocha test might look like this:
describe("DOM Test", function () {
var el = document.createElement("div");
el.id = "myDiv";
el.innerHTML = "Hello World!";
document.body.appendChild(el);
var myEl = document.getElementById('myDiv');
it("has the right text", function () {
(myEl.innerHTML).should.equal("Hello World!");
});
});
And the testrunner.html file would be the normal setup:
<html>
<head>
<title> Tests </title>
<link rel="stylesheet" href="./node_modules/mocha/mocha.css" />
</head>
<body>
<div id="mocha"></div>
<script src="./node_modules/mocha/mocha.js"></script>
<script src="./node_modules/chai/chai.js"></script>
<script>
mocha.ui('bdd');
mocha.reporter('html');
var should = chai.should();
</script>
<script src="test/test.js"></script>
<script>
if (window.mochaPhantomJS) { mochaPhantomJS.run(); }
else { mocha.run(); }
</script>
</body>
</html>
If you'd prefer a solution run entirely from the node.js ecosystem, it's worth considering Zombie.JS. This Stack Overflow question provides a basic example.
The tradeoff is that while Zombie.JS can be used simply by requiring the node module, and is extremely fast, it's not a "real" web browser. PhantomJS is closer, as its based on webkit. Also, the first approach with mocha-phantomjs would allow you to run the client-side Mocha tests in different browsers of your choice, PhantomJS being just one of them.

Related

How to send server-side variables to vue instance using webpack & vue-cli?

I am currently making a project using vue-cli which generates a Node project with webpack. I can build all scripts and use the pug language within .vue files. When building, the project uses HTML-Webpack-Plugin, though, which outputs the code as static HTML with client-side scripts.
How do I pass variables from the server-side to these client-side scripts? I previously was using pug, which made this process easy, but since it now gets built into .html files, this can no longer be done.
I have two attempts, both suboptimal:
1. Send variables into clientside scripts
script.
const clinetSideVar = `!{serverSideVar}`;
The problem with this approach is that I cannot pass this variable into the vue instance, since it gets obfuscated when built and I have no way of accessing it (or do I? I haven't found a way).
2. Using AJAX requests
I could also make a restful API for server-side site data and retrieve it using AJAX, but this seems like a real hack and this would lose quite a bit of performance over just sending the data plainly through a pug template (with no. 1 I'd too, since client-side JS would have to insert the data into the DOM).
I'd recommend using JSONP (since your index.html is built ahead of time in Vue-cli).
In your public/index.html (which is a template)
<head>
...
<script>function getServerData(data) { window.__SERVER_DATA__ = data; }</script>
<script src="/api/server-data.json?callback=getServerData"></script>
</head>
In your Node Express routes definition
const app = express();
// ...
app.get('/api/server-data.json', (req, res) => {
res.jsonp({
foo: 'foo',
bar: 'bar'
});
});
Then just access window.__SERVER_DATA__ from within any Vue component.

How to use npm-installed bootstrap in express?

I 'm a beginner of Node.js development,
Now I try to use bootstrap framework in my first Express web app.
I use
npm install bootstrap
to download the files,and it seems that npm puts them in my node_modules folder.
My question is how can I refer to the bootstrap files in my views in express?
I know a typical way is copying the bootstrap file into the public folder. So my html files can find them. But I don't think this is a good idea.
Thank you.
You need to use in your server.js:
app.use(express.static(__dirname + '/node_modules/bootstrap/dist'));
to define a static resourse and then use:
<script language="javascript" src="js/bootstrap.min.js"></script>
<link rel="stylesheet" href="css/bootstrap.min.css"/>
I found a similar question. In which the solution is explained better by #augusto-goncalves. His solution works for me. It is similar to the solution of #victor-behar but more elaborated and clears confusion.
You have to reference it in the <script> and <link> tags in the header or at the bottom of your main script.
If you're using express, you're probably using templating. To use it in your header part or in your main template (depending on how you've managed your views) like :
<script language="javascript" src="node_modules/bootstrap/.../bootstrap.min.js"></script>
and
<link rel="stylesheet" href="node_modules/bootstrap/.../bootstrap.min.css"/>
This works only if you didn't moved your files with a gulp or a grunt task
There's also a way to transpile scss in express using node sass middleware, for example https://github.com/sass/node-sass-middleware.
That way you can override bootstrap scss. You can do the same for JS with webpack: transpile client-side js and then include the bundle.js in your frontend.

RequireJS, Shim doesn't work correct when CDN failover occurs

I have the website, which is use intranet (small share) as well as on the internet (larger share). Intranet environment, doesn't have internet access. I was planning to load JavaScript from CDN for internet users, while using a local version for intranet user. I am using RequireJS library to dynamically load the scripts, and use failover, when it can't retrieve from the CDN.
I am using the following requireJS configuration to load jQuery library from CDN or use the local one.
Problem occurs, when RequireJS fails to load from CDN, it loads the bootstrap library prior of loading of local version of jquery. This cause two error, 'Bootstrap requires jQuery' from bootstrap and timeout error from requireJS.
My question, how to I avoid this? I want bootstrap to wait till any (CDN or local) version of jQuery is loaded. I have use Shim to define bootstrap dependency on jQuery library. But, it didn't work as anticipated. Is this known bug in requireJS?
Here, my configuration code
require.config({
paths: {
jquery: ['https://code.jquery.com/jquery-1.10.2'
, '/Scripts/_Ref/jquery-1.10.2'],
async: '/Scripts/_Ref/async',
propertyParser: '/Scripts/_Ref/propertyParser',
goog: '/Scripts/_Ref/goog',
bootstrap: '/Scripts/_Ref/bootstrap'
},
shim: {
'bootstrap': {
deps: ['jquery']
}
}
});
require.onError = function (err) {
console.log('RSC JS Error: ' + err.requireType);
if (err.requireType === 'timeout') {
var errorMessage = 'Following modules timeout: ' + err.requireModules;
console.log(errorMessage);
MyNamespace.ShowErrorMessage(errorMessage);
}
};
To demonstrate the problem, I have create a sample website, where I have block the internet and stimulate failover to occur.
Here, is the video link http://www.screencast.com/t/gcQ2I9aUdBY where I have shown problem in action
It sounds like CDN javascripts and RequireJS shims don't play well together. From the RequireJS documentation:
Do not mix CDN loading with shim config in a build. Example scenario:
you load jQuery from the CDN but use the shim config to load something
like the stock version of Backbone that depends on jQuery. When you do
the build, be sure to inline jQuery in the built file and do not load
it from the CDN. Otherwise, Backbone will be inlined in the built file
and it will execute before the CDN-loaded jQuery will load. This is
because the shim config just delays loading of the files until
dependencies are loaded, but does not do any auto-wrapping of define.
After a build, the dependencies are already inlined, the shim config
cannot delay execution of the non-define()'d code until later.
define()'d modules do work with CDN loaded code after a build because
they properly wrap their source in define factory function that will
not execute until dependencies are loaded. So the lesson: shim config
is a stop-gap measure for non-modular code, legacy code. define()'d
modules are better.
For explanations that are easier to understand, see this StackOverflow question.
We seem to have some luck not loading Bootstrap with RequireJS; instead, we're using script tags in <head>:
<script type="text/javascript" sync src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<script type="text/javascript">
// Load jQuery if CDN fails
window.jQuery || document.write('<script src="scripts/libs/jquery.min.js">\x3C/script>')
</script>
<script type="text/javascript" sync src="//maxcdn.bootstrapcdn.com/bootstrap/2.3.2/js/bootstrap.min.js"></script>
<script type="text/javascript">
// Load bootstrap if CDN fails
window.jQuery.fn.dropdown || document.write('<script src="scripts/libs/bootstrap.min.js">\x3C/script>')
</script>
<script type="text/javascript">
var require = {
baseUrl: "scripts/",
deps: ['main']
};
</script>
<script type="text/javascript" src="scripts/libs/require/require.js"></script>
jQuery and Bootstrap are loaded from CDN's with local fallback per Hanselman.

Mimicking the features of node-webkit using a client and a server

I'm trying to find out whether it's possible to invoke node.js functions from a web page. Is there any way to make node.js functions accessible from Google Chrome (so that they are run on the node.js server), as shown here?
(I'm aware that it's possible to do this using node-webkit (a non-standard Chromium implementation) without modifying the code, but I'd prefer to do this using an unmodified browser, which will require the code shown below to be modified in some way.)
<html>
<body>
<script type = "text/javascript">
var exec = require('child_process').exec; //node.js function
</script>
<p onclick = "exec('firefox')">
Click here to launch the Firefox web browser.
</p>
</body>
</html>
No, this is not possible, for clear security reasons.
You only have available to you what the browser gives you. node-webkit is the closest thing available, and does not meet your requirements.
NW has own method like node exec :
var gui = require('nw.gui');
gui.Shell.openItem('firefox', ,function(error, stdout, stderr) { });

Socket.io on Heroku: client-side code

I've been having trouble loading the socket.io library for my JS client code on a Node.js app hosted on Heroku.
For now, I have this line at the end of my index.html file:
<script type="text/javascript" src="/socket.io/socket.io.js"></script>
But then, when I do socket = io.connect('http://myherokuapp');in my JS client code, I get an expected 'io is not defined' error.
Any idea how to correctly load the library on Heroku?
Thanks!
Ok so I finally found my way through. I'm sharing in case it helps someone.
I load the script in index.html this way:
<script type="text/javascript" src="http://myapp.herokuapp.com/socket.io/socket.io.js"></script>
It makes sense because the client-side library is actually loaded from the node server and shouldn't be pushed manually.
In my client-side JS file, I instantiate the socket this way:
socket = io.connect('http://myapp.herokuapp.com/');
Also, and this goes beyond the scope of this question, but you can't use websocket on Heroku for now. They have a little note about that here.
Hope this helps!

Resources