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
Related
I am looking to make my automation tests a bit more flexible. I have a QA team that does not know much javascript and possibly have to design the tests for users with no or little programming skills.
I had a few scripts created using mocha test framework and spectron.js (for an app built with electrion.js) test a few features of the product I dont want to run every single test every time I run the script. My temporary solution is bundle the tests in to a function as a "suite". Like this -
function DiagnosticSuite(location, workstation, workflowName){
CreateWorkflow(location, workflowName);
SetWorkFlowToStation(location, workstation, workflowName);
DiagnosticTestFlow();
return;
}
function PowerflowSuite(imei, location, workstation, workflowName){
SetWorkFlowToStation(location, workstation, workflowName);
powerOffFlow(imei);
return;
}
I was thinking of using Inquirer and use a conditional based on input to run one of the tests above. Like this -
inquirer.prompt([
{
type: 'list',
name: 'Which workflow do you want to run?',
choices: ['Power Off', 'Diagnostic']
}
]).then((answers) => {
if(answers == 'Power Off'){
PowerflowSuite(imei, location, workstation, workflowName);
}
})
How ever when I test that Mocha seems to not wait for the user input from inquerior to run the tests and I get an output like this -
$ npm test
> metistests#1.0.0 test C:\Users\DPerez1\Desktop\metis-automation
> mocha
? Which workflow do you want to run?: (Use arrow keys)
> Power Off
Diagnostic
0 passing (0ms)
Seems like it runs and doesnt see a any tests and finishes and when I select the answer the program just closes.
I am wondering why Mocha does this and if its possible to run my existing mocha scripts with a library like inquirer.
So I found a solution to my problem in case anyone stumbles here and is wondering.
I separated the CLI portion and the Mocha portion into different scripts on the package.json file. That way I can use nodes child process library to run the mocha part and pass the information from the CLI part via the process.argv objject.
So the CLI part will ask me what test to run, what env, and what user. And I create a command to put in child process exec function (I think there are others to use but not important.) When mocha tests run I parse the argvs and pass them into the functions so that the test can run based on that.
I'm using mocha for node.js functional testing.
There are several files in my test.
How can I run a piece of code for only one time before all tests start?
For example, I may have to set up a docker container before all tests start.
Is it possible to do this with mocha?
The before hook runs 1 time for every test file. This doesn't meet my needs.
You can have 'root' level hooks, if you put them outside of any describe blocks. So you can put your relevant code in any files inside of the test folder.
before(function() {
console.log('before any tests started');
});
See the docs: http://mochajs.org/#root-level-hooks
Mocha 8 introduces the concept of root hook plugins. In your case, the relevant ones are beforeAll and afterAll, which will run once before/after all tests, so long you tests run in serial.
You can write:
exports.mochaHooks = {
beforeAll(done) {
// do something before all tests run
done();
},
};
And you'll have to add this file using the --require flag.
See docs for more info.
There is a very clean solution for this. Use --file as parameter in your mocha command. It works like a global hook for your tests.
xargs mocha -R spec --file <path-to-setup-file>
A setup file can look like this:
'use strict';
const mongoHelper = require('./mongoHelper.js');
console.log("[INFO]: Starting tests ...");
// connect to database
mongoHelper.connect()
.then(function(connection){
console.log("[INFO]: Connected to database ...");
console.log(connection);
})
.catch(function(err){
console.error("[WARN]: Connection to database failed ...");
console.log(err);
});
Unfortunately I have not found a way to use async/await in this setup files. So I think you may have to be conent with using "old" promise and callback code.
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.
I would like to have access to the many available plugins and tasks in the grunt ecosystem to make my life easier, but I would like control over when and how each task is run. Most importantly, I want a way to run grunt tasks programmatically instead of running grunt from the command line in a folder with a Gruntfile. So I started poking around grunt-cli and grunt for a "way in."
From the source code of GruntJS:
// Expose the task interface. I've never called this manually, and have no idea
// how it will work. But it might.
grunt.tasks = function(tasks, options, done) {
...
As you can see, Mr. Allman cautions us about the interface... my question is, has anyone gotten this to work?
My experiments, so far, have led me to believe the best way to programmatically control grunt is by mimicking the command line call with a child process:
$ npm install grunt-cli //notice no -g flag
// From runner.js
var exec =require('child_process').exec
exec('node_modules/.bin/grunt-cli tasks to run', {
cwd: 'path/to/directory/with/a/gruntfile'
}, function() { /* do stuff here */ });
This seems dirty so I'm thinking about simply writing my own task-runner that exposes an interface for grunt tasks. However, I don't want to dup work if someone has had success with grunt.tasks() despite Mr. Allman's warnings.
The obvious answer seems like it should be write a grunt task to do whatever you want to do :)
Then you can use grunt.task.run() to control other grunt tasks: http://www.gruntjs.org/article/grunt_task.html
You can also update their configs dynamically before running them very easily by messing with grunt.config
There's also this answer which may answer your question:
How can I run a grunt task from within a grunt task?
Also check out grunt.task.start() which is not publicy documented, but it seems to kick off all of the tasks https://github.com/gruntjs/grunt/blob/master/lib/util/task.js#L246 (hat tip: #jibsales)
Maybe this would help you to write a custom handler : https://www.npmjs.com/package/rungrunttask
Usage details
var RunGruntTask = require('rungrunttask').RunGruntTask;
var taskname = 'some grunt task such as backup database every 24hours';
RunGruntTask(taskname);
For example I define my own task named jasmine. It is based on the task server.
If I call grunt server jasmine - it's ok. But I want to declare that dependency inside my task.
grunt.task.run - add task to the queue (after my task).
grunt.task.requires - only check dependency, not run it...
Does any way exist to run server task before my jasmine task?
P.S. I don't want to create jasmine_orig task and then .registerTask('jasmine', 'server jasmine_orig'). It looks like silly.
The way the server task is currently written, no this isn't possible. However, you may be able to do what you want by using the grunt-connect plugin, or rolling your own grunt server task. The source for the built-in one is here:
https://github.com/gruntjs/grunt/blob/0.3-stable/tasks/server.js
As you can see, there isn't much to it, other than reading a config, starting a connect server, and possibly logging when --debug is passed. You could, in fact, copy all of that code into a helper (woefully underdocumented, I'm afraid), and call it from your jasmine task.
It's probably a good idea to start a separate server for your tests (for test independence), but if you needed to save the resources for some reason, or you find multiple servers distasteful in some other way, you'll have to write some custom task code to check if the server is there, and then start the server if it's not.
Probably the best solution is the following:
install the grunt-contrib-connect npm package:
npm install grunt-contrib-connect --save-dev
Make configurations for your dev and test environments:
connect: {
dev: {
base: 'path/to/serve',
port: 8000
},
test: {
base: 'path/to/serve',
port: 8001
}
}
Register a test task that runs grunt server:test jasmine for you.
grunt.registerTask('test', 'server:test jasmine')
One partial solution is to define the steps for specific tasks as variables. Then, you can concatenate them like such:
var buildSteps = [ ... ];
var distDevSteps = [ ... ];
grunt.registerTask('build', buildSteps);
grunt.registerTask('dist_dev', [].concat(buildSteps, distDevSteps));