I have some JavaScript that is going to run in the browser, but I have broken the logic based functions that have nothing to do with the DOM into their own js files.
If it's possible, I would prefer to test these files via command line, why have to open a browser just to test code logic? After digging through multiple testing libraries for Node.js. I suppose it's not a big deal, but that seems to require that I build a whole node project, which requires that I provide a main, which doesn't really exist in my project since it's just functions that get fired from a web page.
Is there a solution for testing JavaScript functions that can be as simple as just writing a .js file with tests in it and calling a utility to run those tests? Something more simple than having to set up a runner, or build a project and manage dependencies? Something that feels like writing and running JUnit Tests in Eclipse, and a little less like having to set up a Maven project just to run MVN test?
As a follow-up question, is this even the right way to go about it? Is it normal to be running tests for JavaScript that is meant to run in the browser in Node.js?
Use test runners like mocha or jasmine. Very easy to setup and start writing test code. In mocha for example, you can write simple test cases like
var assert = require('assert');
var helper = require('../src/scripts/modules/helper.js');
var model = require('../src/scripts/modules/model.js');
model.first.setMenuItem ({
'title': 'Veggie Burger',
'count': 257,
'id': 1
});
describe('increment', function(){
console.log ("Count : " + model.first.getMenuItem().count);
it('should increment the menu item', function(){
helper.increment();
assert.equal(model.first.getMenuItem().count, 258);
});
});
and run them like
$ ./node_modules/mocha/bin/mocha test/*.js
where test/*.js are the specifications file (unit test file like the one above)
the output will be something like:
Count : 257
increment
✓ should increment the menu item
1 passing (5ms)
You can even use headless browser like PhantomJS to test containing DOM manipulation code.
I'm going to accept Ari Singh's answer for recommending Mocha, and special kudos to Ayush Gupta for leading me down a road that eventually let me write my js files in a format that could be ran in the browser and node.js.
Just to expand on Ari's answer a bit on some things that made life a little easier.
I installed mocha globally using npm install -g mocha. Additionally, I created a test directory that I put all my test in. By doing this, all I had to do to run my unit tests was call mocha test. No package.json, no lengthy paths into node_modules to run mocha.
Node js requires you to export the functions in one file that you want to use in another file, which JavaScript in browsers does not. In order to support both Node.js and JavaScript, I did the following:
In my root directory, I have foo.js with the following contents:
function bar() {
console.log("Hi")
}
module.export = bar
Then in the test directory I have test_foo.js with the following contents (Note this example doesn't have a test, see Ari's answer for an example of writing tests in Mocha):
var bar = require('../foo.js')
bar()
Using this approach, I can test the bar function in node using mocha test and still use it in my HTML page by importing it as a script.
Related
I'm developing using node/webpack/reactjs with testing leveraged by mocha.
My productivity is vastly better than it was when using other javascript ecosystems but is still well below that which I achieve in Python when working on the service side.
In Python, I can develop using ipdb.set_trace() or ipython.embed() to open a command line in the context of a test. This is an excellent way to accelerate development because I can inspect and interactively tinker with all aspects of the data and code at the line where I am investigating or changing stuff.
Is there any way to do this using mocha tests? It would mean I could use javascript at the command line to inspect the current variable context interactively. I can painstakingly emulate it by requiring bits and pieces in babel-node and then copy pasting lines of code.
In short, I'd like to be able to do something like this inside a test file:
it('thingy meets expectations', () => {
let thingy = {name: 'thingy'};
node-babel.embed();
});
so that when I run the test at the command line, something like this happens (where I type thingy at the command line which appears during the test):
$ npm run test -- --grep='thingy meets expectations'
> sosadmin_front_end#1.0.0 test ...front_end
> mocha --compilers js:babel-core/register --require ./test/test_helper.js --recursive "--grep=object: Form"
object: Form
// babel-node version=6.11.4 embeded at L223 ...front_end/tests/foo.js
> thingy
{ name: 'thingy' }
I'm completely new to sails, node and js in general so I might be missing something obvious.
I'm using sails 0.10.5 and node 0.10.33.
In the sails.js documentation there's a page about tests http://sailsjs.org/#/documentation/concepts/Testing, but it doesn't tell me how to actually run them.
I've set up the directories according to that documentation, added a test called test/unit/controllers/RoomController.test.js and now I'd like it to run.
There's no 'sails test' command or anything similar. I also didn't find any signs on how to add a task so tests are always run before a 'sails lift'.
UPDATE-2: After struggling a lil bit with how much it takes to run unit test this way, i decided to create a module to load the models and turn them into globals just as sails does, but without taking so much. Even when you strip out every hook, but the orm-loader depending on the machine, it can easily take a couple seconds WITHOUT ANY TESTS!, and as you add models it gets slower, so i created this module called waterline-loader so you can load just the basics (Its about 10x faster), the module is not stable and needs test, but you are welcome to use it or modify it to suit your needs, or help me out to improve it here -> https://github.com/Zaggen/waterline-loader
UPDATE-1:
I've added the info related to running your tests with mocha to the docs under Running tests section.
Just to expand on what others have said (specially what Alberto Souza said).
You need two steps in order to make mocha work with sails as you want. First, as stated in the sails.js Docs you need to lift the server before running your test, and to do that, you create a file called bootstrap.test.js (It can be called anything you like) in the root path (optional) of your tests (test/bootstrap.test.js) that will be called first by mocha, and then it'll call your test files.
var Sails = require('sails'),
sails;
before(function(done) {
Sails.lift({
// configuration for testing purposes
}, function(err, server) {
sails = server;
if (err) return done(err);
// here you can load fixtures, etc.
done(err, sails);
});
});
after(function(done) {
// here you can clear fixtures, etc.
sails.lower(done);
});
Now in your package.json, on the scripts key, add this line(Ignore the comments)
// package.json ....
scripts": {
// Some config
"test": "mocha test/bootstrap.test.js test/**/*.test.js"
},
// More config
This will load the bootstrap.test.js file, lift your sails server, and then runs all your test that use the format 'testname.test.js', you can change it to '.spec.js' if you prefer.
Now you can use npm test to run your test.
Note that you could do the same thing without modifying your package.json, and typying mocha test/bootstrap.test.js test/**/*.test.js in your command line
PST: For a more detailed configuration of the bootstrap.test.js check Alberto Souza answer or directly check this file in hist github repo
See my test structure in we.js: https://github.com/wejs/we-example/tree/master/test
You can copy and paste in you sails.js app and remove we.js plugin feature in bootstrap.js
And change you package.json to use set correct mocha command in npm test: https://github.com/wejs/we-example/blob/master/package.json#L10
-- edit --
I created a simple sails.js 0.10.x test example, see in: https://github.com/albertosouza/sails-test-example
Given that they don't give special instructions and that they use Mocha, I'd expect that running mocha from the command line while you are in the parent directory of test would work.
Sails uses mocha as a default testing framework.
But Sails do not handle test execution by itself.
So you have to run it manually using mocha command.
But there is an article how to make all Sails stuff included into tests.
http://sailsjs.org/#/documentation/concepts/Testing
I have a file named test/helper.js that I use to run Mocha tests on my Node.js apps. My tests structure looks like:
test/
test/helper.js # global before/after
test/api/sometest.spec.js
test/models/somemodel.spec.js
... more here
The file helper.js has to be loaded because it contains global hooks for my test suite. When I run Mocha to execute the whole test suite like this:
mocha --recursive test/
the helper.js file is loaded before my tests and my before hook gets executed as expected.
However, when I run just one specific test, helper.js is not loaded before the test. This is how I run it:
mocha test/api/sometest.spec.js
No global before called, not even a console.log('I WAS HERE');.
So how can I get Mocha to always load my helper.js file?
Mocha does not have any notion of a special file named helper.js that it would load before other files.
What you are trying to do works when you run mocha --recursive because of the order in which Mocha happens to load your files. Because helper.js is one level higher than the other files, it is loaded first. When you specify an individual file to Mocha, then Mocha just loads this file and, as you discovered, your helper.js file is not loaded at all.
So what you want to do is load a file such that it will set top level ("global") hooks (e.g. before, after, etc.). Options:
You could use Mocha programmatically and feed it the files in the order you want.
You could force yourself to always specify your helper file on the command line first before you list any other file. (I would not do this, but it is possible.)
Another option would be to organize your suite like I've detailed in this answer. Basically, you have one "top level" file that loads the rest of the suite into it. With this method you'd lose the ability of running Mocha on individual files, but you could use --grep to select what is being run.
You cannot use the -r option. It loads a module before running the suite but, unfortunately, the loaded module does not have access to any of the testing interface that Mocha makes available to your tests so it cannot set hooks.
What I do is create a test/test_helper.js file, which exports all the helpers I create:
// test/test_helper.js
module.exports = {
MyHelper: require('./helpers/MyHelper')
}
Then I require the helper on any test I need to use it:
// test/spec/MySpec.js
var helper = require('../test_helper');
// Or if you need just "MyHelper"
var myHelper = require('../test_helper').MyHelper;
describe('MySpec', function () {
// Tests here...
});
I prefer the above approach because its easy to understand and flexible. You can see it in action here in my demo: https://github.com/paulredmond/karma-browserify-demo/tree/master/test
First, I would definitely use mocha.opts so that you don't have to include the options you want every time. As pointed out, one option is to use --grep, but I am not a huge fan of that personally. It required you name everything in an overly simplistic way. If the before hook is NOT async you can use --require in your mocha.opts. e.g.
#mocha.opts
--recursive
--require test/helpers.js
It sounds like this wouldn't work for you because you want global after hook as well. What I have done is I just call the full test suite every time, but if I am in the middle of deving and only want to test one suite, or even one specific test, I use the exclusivity feature, only https://mochajs.org/#exclusive-tests. You can make it it.only('... or describe.only('... If you do this it looks through all tests and sets up exactly like your full test harness would, but then only executes the test or suite you have specified.
Now you can include those global hooks no problem. #Louis mentions that your helpers.js are loading in the proper order only coincidently. That is not true. If you place any hooks outside of a describe block, it automatically becomes a global hook. This can be accomplished by either putting it in its own file
// helpers.js
before(function() { console.log('testing...'); });
or within a test file
// some.spec.js
before(function() { console.log('testing...'); });
describe('Something', function() {
it('will be tested', function() {
...
});
});
Obviously, I think putting it in its own file is cleaner. (I called it hooks.js). Point is, this is not a result of the order in which files were loaded.
Just one gotcha that might be obvious to other but I struggled with briefly -- hooks not placed in a describe block are ALL global. They are not directory specific. So if you copy helpers.js into a sub-directory of tests, the before and after hook will now fire twice. Also, if you place a beforeEach hook in there, it will fire before every single test, not just those tests in that directory.
Anyway, I know this post is a bit old, but hopefully this will help others having similar issues.
Late addition to the answer:-
Mocha (v7.0.0 as of writing) support specifying file as an option:-
As per the docs
--file Specify file(s) to be loaded prior to root suite
execution
.mocharc.json
{
"watch-files": [
"test/**/*.js"
],
"recursive": true,
"file": "test/setup"
}
./test/setup.js
const request = require('supertest');
const app = require('../app'); // express app
global.request = request(app);
A Worthy Mention:
I found that the above setup loaded all .js files anyway, probably because of the mocha config extension which is set to js by default. Since I had the convention of naming all tests file with .spec.js, I can ignore other files by adding "ignore": ["test/**/!(*.spec.js)"]
I came to this question after trying all sorts of things to get my tests to connect once to a database before subsequently running a bunch of crud tests on my models.
Then I found mocha-prepare which solved my problems.
In your helper.js file you can just define a prepare function.
prepare(done => {
console.log('do something asynchronously here')
done()
}, done => {
console.log('asynchronously clean up after here')
done()
})
works a treat.
In our project, we are using helpers somewhat like this:
clientHelper = require("../../../utils/clientHelper")
You need to configure relative path of your helper properly.
And then calling it like this:
clientHelper.setCompanyId(clientId)
I recently started working on a Rails app that has a large amount of QUnit tests already in place for testing ember. I have been charged with the task of setting the app with a CI (I decided to use CodeShip). The issue I currently face is that the only way for me to run the qunit tests is to go to http://localhost:3000/qunit. I need to setup a way to run the tests from the command line. I have done a large amount of research, and have tried at least 10 different solutions but non have managed to work.
Currently I am attempting to use teaspoon but it I have not managed to get it to work. Any help would be much appreciated. Please let me know if I need to post more information about the setup.
node-qunit-phantomjs gets the job done easy enough and is standalone, not a Grunt-, Gulp-, whatever-plugin:
$ npm install -g node-qunit-phantomjs
$ node-qunit-phantomjs tests.html
Testing tests.html
Took 8 ms to run 1 tests. 0 passed, 1 failed.
...
$ echo $?
1
TL;DR
Use out-of-the-box qunit command (do npm install -g qunit beforehand), so you don't need additional dependencies.
Extending a bit Arthur's answer because he mentioned only simplest case which works only for simplest projects.
As mentioned on QUnit page, there is built-in possibility to run tests from command line. There is no need to install additional weird frameworks on top of QUnit!
npm install -g qunit
qunit # Will search for tests in "test" directory
This works for artificial tests as on their website, but in real project you probably will have your logic in some other .js file.
Having following structure:
project
│ index.js <--- Your script with logic
│ package.json <--- most probably you'll have npm file since qunit executable is installed via npm
└───test
tests.html <--- QUnit tests included in standard HTML page for "running" locally
tests.js <--- QUnit test code
And let's imagine that in your index.js you have following:
function doSomething(arg) {
// do smth
return arg;
}
And the test code in tests.js (not that it can be the whole content of the file - you don't need anything else to work):
QUnit.test( "test something", function( assert ) {
assert.ok(doSomething(true));
});
Running in browser
This is not related directly to the question, but just want to make a reference here.
Just put both your script and tests to tests.html and open the page in browser:
<script type="text/javascript" src="../index.js"></script>
<script src="tests.js"></script>
Running from command line
With the setup described below you can try to run qunit, but it will not work because it cannot find your function doSomething. To make it accessible you need to add two things to the scripts.
First is to explicitly "import" your script from tests. Since JS doesn't have sunch a functionality out-of-the box, we'll need to use require coming from NPM. And to keep our tests working from HTML (when you run it from browser, require is undefined) add simple check:
// Add this in the beginning of tests.js
// Use "require" only if run from command line
if (typeof(require) !== 'undefined') {
// It's important to define it with the very same name in order to have both browser and CLI runs working with the same test code
doSomething = require('../index.js').doSomething;
}
But if index.js does not expose anything, nothing will be accessible. So it's required to expose functions you want to test explicitly (read more about exports). Add this to index.js:
//This goes to the very bottom of index.js
if (typeof module !== 'undefined' && module.exports) {
exports.doSomething = doSomething;
}
When it's done, first check tests.html still working and not raising any errors (testing test infrastructure, yeah) and, finaly, try
qunit
And the output should be like
TAP version 13
ok 1 Testing index.js > returnTrue returns true
1..1
# pass 1
# skip 0
# todo 0
# fail 0
I don't want to deal with node for my simple (or not) project
This is an open question and I cannot answer this. But you'll need some runner to run QUnit tests anyway. So maybe having package.json with one devDependency like "qunit": "^2.6.1" is not the worst option here. There are several 3rd-party runners: grunt-qunit, PhantomJS runnner, ember-qunit-cli, also see more on official QUnit Plugins page
What if I have class, not function?
In JS everything is a function, right :)? So no problem, just change your script exports and tests import acordingly
exports.exportedMyClass = MyClass; // in index.js
MyClass= require('../index.js').exportedMyClass ; // in tests.js
See example a.k.a. small getting started here.
QUnit now has its own CLI:
$ npm install -g qunit
$ qunit 'tests/*-test.js'
TAP version 13
ok 1 Module > Test #1
ok 2 Module > Test #2
1..2
# pass 2
# skip 0
# todo 0
# fail 0
Run qunit --help for more usage information.
You can use Grunt (task runner) for this. You would also need to install these two packages: grunt-contrib-qunit and grunt-contrib-connect
I did just recently set up a GitHub repository when trying to figure out how to run QUnit on Travis CI: https://github.com/stebru/travis-qunit-test
You're welcome to fork it and try it out for yourself.
My use case is the following:
I decided to try coffeescript for some nodejs project and i want some of my source files to begin with #!/usr/bin/env node
Coffeescript treats lines that begin with # as comments.
I know that you can embed js code in .coffee but that is not the case because
file.coffee
`#!/usr/bin/env node`
foo = 'bar'
Compiles to:
file.js
(function() {
#!/usr/bin/env node;
var foo;
foo = 'bar';
}).call(this);
The compiler doesn't support this. See: https://github.com/jashkenas/coffee-script/issues/2215
But why not run it with coffee instead?
#!/usr/bin/env coffee
console.log 'Hello World'
Then just run ./my_code.coffee. The coffee executable is simply a wrapper around node, and can be used instead in nearly all circumstances.
Or create some sort of build system that tacks it on after the compile step. But you shouldn't really need to.
What you want is not possible with CoffeeScript, though you could - as Alex Wayne suggested - prepend the shebang manually to the file if you want to.
What I did for a project of mine, is making a very small JS script with a she-bang, that loads the JS code compiled from CoffeeScript. See this file https://github.com/meryn/jumpstart/blob/master/bin/jumpstart . This works well.
Another advantage of doing this is easier testing. You don't have to start a new child process to run the code. Instead, you can use call the run function, or however you have called it. This of course leaves the problem of passing proper parameters. I did this by making the run function (see https://github.com/meryn/jumpstart/blob/master/src/run.coffee for source) delegate practically everything to runWith function which can be passed all the input variables (environment, cli args, etc) the script needs.