How is Mocha's basic functions 'describe/before/it' implemented? - javascript

I'm somewhat new to JS, very new to Mocha, so I apologize if this is a dumb question...
I recently started working with Mocha as I'm in the early stages of a new side-project. I have mocha installed locally by the way, npm i mocha --save-dev.
I start considering if I should implement portions of my project like mocha, since I'm so happy with how easy it is to get going. Trouble is I can't figure out how they have this set up. I've looked through some of the code on GitHub, but would like a high level summary.
This is my test.js file
const app = require('../src/app');
const assert = require('assert');
describe('my app', function(){
it('does something cool', function(){
assert.strictEqual(app.foo(), true);
})
});
I'm confused because I don't have const mocha = require('mocha'); in there but VS Code still recognizes identifiers like describe before, and it. VS Code even tells me when I hover on describe that it's var describe: Mocha.SuiteFunction.
How is this code working, let alone with IntelliSense? I was expecting to have to do something like mocha.describe().

As mocha loads the test files, it adds it to the global context.
Seen here: suite.emit(EVENT_FILE_PRE_REQUIRE, global, file, self) (note the global argument here),
Handled here: suite.on(EVENT_FILE_PRE_REQUIRE, function(context, file, mocha) {}) (note that context is global from suite.emit)
VS Code even tells me when I hover on describe that it's var describe: Mocha.SuiteFunction
Your project probably has #types/mocha package installed. Intellisense didn't come up for me until I ran npm install --save-dev #types/mocha.

Related

How can I use functions and objects without require them in NodeJS

I have been studying NodeJS for about a year and today I found something strange for me. We all know that in order to use a module (function, object or variable) in another module we must export and import it except for the native modules like String, Number, Promise, etc. I installed an external package for unit testing called Jest.
The strange thing here is that I have created two test modules called: logic.js and logic.test.js, in none I have imported the Jest module, however I can access all its methods. Let's show some code:
logic.js
module.exports.add = function(a, b){
return a + b;
}
logic.test.js
const lib = require('../logic')
test('Add - Should return the sum of two numbers', () => {
const result = lib.add(1,3);
expect(result).toBe(4);
});
As you can see in logic.test.js I have access to expect and test methods and i have not impoted nothing about Jest.
The questions here are:
How is this posible?
Its a good practice to do this with my modules
As Jonas W stated in the comments, they make use of the global variable that is common to all your application.
The use of the global variable is very simple
test.js
global.myObject = 'MyMan'
app.js
require('./test')
console.log(myObject)
Loading app.js will render MyMan
You might say that I actually import the test module and that Jest does not.
The thing is that you execute your node application using node yourFile.js but you instanciate your jests tests with the jest command line.
It's the jest command line that handles the binding between its framework (the expect and test methods.) and your script.
Is it a good practice?
I would say no. Except if you plan to make a library like Jest that have its own command line launcher and that you want to give tools like that to the users of your library.
The power of Node lives into the module organization, don't be afraid to use them.

Using Jest, getting internal function

I am just re-looking at Jest as it's been getting a lot of good reports. However struggling to find a good way the access internal functions to test them.
So if I have:
const Add2 = (n)=> n+2;
export default (list)=>{
return list.map(Add2());
}
Then if I was using Jasmine or Mocha I'd use rewire or babel-plugin-rewire to get the internal Add2 function like this:
var rewire = require('rewire');
var Add2 = rewire('./Adder').__get__('Add2');
it('Should add 2 to number', ()=>{
let val = Add2(1);
expect(val).toEqual(3);
});
However neither of them seem to work with jest and while there looks like an excellent mocking syntax I can't see any way to get internal function.
Is there a good way to do this, something I'm missing on the jest api or set up?
You can actually achieve this if you are willing to use babel to transform your files before each test. Here's what you need to do (I'll assume you know how to get babel itself up and running, if not there are multiple tutorials available for that):
First, we need to install the babel-jest plugin for jest, and babel-plugin-rewire for babel:
npm install --save-dev babel-jest babel-plugin-rewire
Then you need to add a .babelrc file to your root directory. It should look something like this:
{
"plugin": ["rewire"]
}
And that should be it (assuming you have babel set up correctly). babel-jest will automatically pick up the .babelrc, so no additional config needed there unless you have other transforms in place already.
Babel will transform all the files before jest runs them, and speedskater's rewire plugin will take care of exposing the internals of your modules via the rewire API.
I was struggling with this problem for some time, and I don't think the problem is specific to Jest.
I know it's not ideal, but in many situations, I actually just decided to export the internal function, just for testing purposes:
export const Add2 = x => x + 2;
Previously, I would hate the idea of changing my code, just to make testing possible/easier. This was until I learned that this an important practice in hardware design; they add certain connection points to their piece of hardware they're designing, just so they can test whether it works properly. They are changing their design to facilitate testing.
Yes, you could totally do this with something like rewire. In my opinion, the additional complexity (and with it, mental overhead) that you introduce with such tools is not worth the payoff of having "more correct" code.
It's a trade-off, I value testing and simplicity, so for me, exporting private functions for testing purposes is fine.
This is not possible with jest. Also you should not test the internals of a module, but only the public API, cause this is what other module consume. They don't care how Add2 is implemented as long as yourModule([1,2,3]) returns [3,4,5].

Sails.js: How to actually run tests

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

How to run JavaScript test script in multiple environments (terminal and browser)?

Let's say I have some tests that require jQuery. Well, we don't have to make believe, I actually have the tests. The test themselves are not important, but the fact they depend on jQuery is important.
Disclaimer: this is node.js so you cannot depend on global variables in your solution. Any dependency must be called into the file with require.
On the server we need this API (to mock the window object required by server-side jquery)
// somefile.js
var jsdom = require("jsdom").jsdom;
var window = jsdom().parentWindow();
var $ = require("jquery")(window);
// my tests that depend on $
// ...
On the client we need a slightly different API
// somefile.js
// jsdom is not required obviously
// window is not needed because we don't have to pass it to jquery explicitly
// assume `require` is available
// requiring jquery is different
var $ = require("jquery");
// my tests that depend on $
// ...
This is a huge problem !
The setup for each environment is different, but duplicating each test just to change setup is completely stupid.
I feel like I'm overlooking something simple.
How can I write a single test file that requires jQuery and run it in multiple environments?
in the terminal via npm test
in the browser
Additional information
These informations shouldn't be necessary to solve the fundamental problem here; a general solution is acceptable. However, the tools I'm using might have components that make it easier to solve this.
I'm using mocha for my tests
I'm using webpack
I'm not married to jsdom, if there's something better, let's use it !
I haven't used phantomjs, but if it makes my life easier, let's do it !
Additional thoughts:
Is this jQuery's fault for not adhering to an actual UMD? Why would there be different APIs available based on which env required it?
I'm using karma to run my unit tests from the command line directly (CI too, with gulp).
Karma uses phantomjs to run the tests inside of a headless browser, you can configure it to run in real browsers too.
Example of karma configuration inside of gulp:
// Run karma tests
gulp.task("unit", function (done) {
var parseConfig = require("karma/lib/config").parseConfig,
server = karma.server,
karmaConfig = path.resolve("karma.conf.js"),
config = parseConfig(karmaConfig, {
singleRun: true,
client: {
specRegexp: ".spec.js$"
}
});
server.start(config, done);
});
In case of my tests it takes approx. 10 seconds to run 750 tests, so it's quite fast.

Testing in node.js with mocha - Newbie

I have started implementing TDD in my JS project. I've implemented mocha for that purpose. As these are my first steps what I did:
Installed node.js
Installed mocha globally and locally to my project.
Wrote package.json setting dependencies.
Wrote makefile.
Wrote .gitignore to avoid uploading node_modules folder.
Folder structure
project
-- js
----filetotest.js
-- test
---- test.js
What I want to do is to run the command make test in order to run the tests inside test.js that tests the filetotest.js file.
I read about the node.js approach using exports. But is there some way to include the file in the test suite?
I'm stuck here, and I think that my doubt is more about the concept than the tech thing. Will appreciate a lot your help.
To clarify a little bit what I would like to do:
https://nicolas.perriault.net/code/2013/testing-frontend-javascript-code-using-mocha-chai-and-sinon/
I would like to get a similar result through the command line.
Thanks so much,
Guillermo
You are doing it right.
Now export your function from filetotest.js, like this:
var f1 = function(params) {
// ...
}
exports.f1 = f1
In test.js, require this file
var f1 = require("./filetotest.js").f1
// test f1
Btw, if you will put your tests in /test directory, mocha will execute them automatically (given that it will be executed from the root of your project)

Categories