I have grunt task that starts the server:
module.exports = function(grunt){
grunt.registerMultiTask('connect', 'Run a simple Node Server', function(){
var options = this.options();
// Tell Grunt this task is asynchronous.
var done = this.async();
var server = connect();
server.use(function(request, response, nxt){
...
});
server.listen(port);
});
};
Now I want to use grunt to start this node server first and then open the browser using grunt-open plugin.
grunt.task.run(['startServer', 'open']);
But startServer task in blocking the open task as the server keeps on listening. What should I do to keep this node server running and open the browser once the server starts?
I had the same problem as yours and I worked in Windows environment. My solution was to put the web server codes in a file for example myServer.js, and use cmd: "start node \"path\to\myServer.js" within the grunt-exec settings.
Example:
Let's assume my server file is located on the following path: D:\SourceCodes\WebServer\myServer.js
ip address and port of my server is 192.168.1.1:8080,
and my webpage is index.html
Then the Gruntfile.js would be:
module.exports = function (grunt) {
grunt.initConfig({
exec: {
run_server:{
cwd: "D:/SourceCodes/WebServer/",
cmd: "start node \"D:/SourceCodes/WebServer/myServer.js\""
},
open_web:{
cmd: "start chrome http://192.168.1.1:8080/index.html"
}
});
grunt.loadNpmTasks('grunt-exec');
grunt.registerTask('default', ['exec']);
}
Two things:
your 'connect' task currently blocks while waiting, you have to tell it to let the grunt process run asynchronously: call done() at the end
...
server.listen(port);
done();
});
now your build will end at the end of your task list, and take down your server with it. So you have to add a task to keep it alive. I suggest using grunt-contrib-watch, but you may choose any one you like, as long as it's a blocking task:
grunt.task.run(['startServer', 'open', 'watch]);
By the way, why are you calling grunt.task.run instead of defining your own task sequence grunt.registerTask('default', ['startServer', 'open', 'watch]); ?
Related
I have node file that is running a karma test in a node app using the karma public api (I'll save writing out the code because it comes straight from http://karma-runner.github.io/0.13/dev/public-api.html).
All is fine so far, the test runs. Now I need to start serving different files to the karma run. For example, I might have exampleSpec.js, example1.js, example2.js, and example3.js. I need to serve exampleSpec and then example1-3 in sequence.
However, I don't see any documentation on this, and can't seem to get anywhere on.
So, The answer ended up being pretty simple. The first argument to the server constructor is a config object, that can replace or augment the karma.conf.js, so it is posible to send in altered files arrays. Code below for posterity:
"use strict";
var Server = require('karma').Server;
var filePath = process.cwd();
filePath += "/karma.conf.js";
console.log(filePath);
//files needs to be an array of string file matchers
function runTests(files, port) {
var config = {
configFile: filePath,
files: files,
port: port
};
var server = new Server(config, function(exitCode) {
console.log('Karma has server exited with ' + exitCode);
process.exit(exitCode)
});
server.on('run_complete', function (browser, result) {
console.log('A browser run was completed');
console.log(result);
});
server.start();
}
runTests(['test/**/*Spec.js', 'tmp/example.js'], 9876);
runTests(['test/**/*Spec.js', 'tmp/example2.js'], 9877);
runTests(['test/**/*Spec.js', 'tmp/example3.js'], 9878);
Here is my setup.
I have a grunt task that does 2 things: 1) start a http server listening on some port 2) triggers another grunt task
The grunt task triggered above is a testem task that runs tests on test-index.html page in PhantomJS.
The test-index.html page sends a POST call on the port on which I start a server in the first grunt task.
Issue: The POST call doesn't hit my server.
Note: If I run the same server manually (not from grunt) and then run the test grunt task, the POST call hits the server.
Heres the code:
Grunt task
grunt.registerMultiTask('coverage', 'Generates coverage reports for JS using Istanbul', function () {
var server = http.createServer(function(req, resp) {
resp.setHeader("Access-Control-Allow-Origin", "*");
console.log('Got something');
req.pipe(fs.createWriteStream('coverage.json'))
resp.end();
});
var port = 7358;
server.listen(port);
// This task simply executes a command: `testem.js ci`
grunt.task.run('testem').then(function() {
server.close();
});
});
test-index.html (somewhere in the )
function onTestemLoad() {
Testem.on('all-test-results', function(results){
var xhr = new XMLHttpRequest();
xhr.open('POST', 'http://localhost:7358/');
xhr.send(JSON.stringify(window.__coverage__))
});
}
Can anyone point what might be going wrong here?
you've been misled by grunt.task.run!
This line does NOT run the task, it just puts it on the top of the list of tasks to run once the current task is done (http://gruntjs.com/api/grunt.task#grunt.task.run).
A second issue is that when a task completes, it takes down all its running processes with it.
So what happens is:
coverage starts, spins on your server, then register testem as next task
coverage ends, taking down your server
next task (= testem) runs, but no server is here to answer...
You can fix it by doing the following 2 things:
inline your test: replace grunt.task.run('testem') with a direct call to testem
ensure your tests run synchronously - or keep your task alive until your tests are done (using this.async - see http://gruntjs.com/api/inside-tasks#this.async).
I am trying to setup environment for headless testing using Selenium and PhantomJS.
Setting UP phantomjs:
I have made a folder c:/phantomjs and put all the phantomjs script files there (after downloading).
Then I created a folder C:\xampp\htdocs\testPhantomJS
Now I installed nodeJS in my system.
Then I traversed to the C:\xampp\htdocs\testPhantomJS in the command prompt and installed phantomJS like this:
C:\xampp\htdocs\testPhantomJS>npm install -g phantomjs
The image states a different location. Thats because it was taken from my colleague's computer. We both are working on same installation, and he sent me the image for reference. That's why its different with my folder location, but the location I stated, it is the one I worked on.
Now on typing phantomjs on command prompt, when we are typing
C:\xampp\htdocs\testPhantomJS>phantomjs
phantom>
Setting Up Selenium-Webdriver
I traversed to C:\xampp\htdocs\testPhantomJS in the command prompt and installed selenium webdriver like this:
C:\xampp\htdocs\testPhantomJS>npm install selenium-webdriver
After installation, the folder structure is like this:
Now I have a test-script test.js which is like this:
describe('Test example.com', function(){
before(function(done) {
client.init().url('http://google.com', done);
});
describe('Check homepage', function(){
it('should see the correct title', function(done) {
client.getTitle(function(err, title){
expect(title).to.have.string('Example Domain');
done();
});
});
it('should see the body', function(done) {
client.getText('p', function(err, p){
expect(p).to.have.string(
'for illustrative examples in documents.'
);
done();
})
});
});
after(function(done) {
client.end();
done();
});
});
The problem is, where should I put the above script, and how shall I run it?
I just don't need to run using the phantomjs only, I need to test with both phantomjs and selenium.
This solution is coming from this pretty neat tutorial on how to setup testing with selenium and phantomjs: http://code.tutsplus.com/tutorials/headless-functional-testing-with-selenium-and-phantomjs--net-30545
Here is some of the tutorial below:
Combining Everything
Now that we have all the pieces, we have to put everything together.
Remember: before running any tests, you have to run Selenium Server:
1
java -jar selenium-server-standalone-2.28.0.jar
Selenium will run PhantomJS internally; you don't have to worry about that.
Now, we need to connect to Selenium from our JavaScript. Here's a sample snippet, which will initiate a connection to Selenium and have a ready object to control our Selenium instance:
// Use webdriverjs to create a Selenium Client
var client = require('webdriverjs').remote({
desiredCapabilities: {
// You may choose other browsers
// http://code.google.com/p/selenium/wiki/DesiredCapabilities
browserName: 'phantomjs'
},
// webdriverjs has a lot of output which is generally useless
// However, if anything goes wrong, remove this to see more details
logLevel: 'silent'
});
client.init();
Now, we can describe our tests and use the client variable to control the browser.
A full reference for the webdriverjs API is available in the documentation, but here's a short example:
client.url('http://example.com/')
client.getTitle(function(title){
console.log('Title is', title);
});
client.setValue('#field', 'value');
client.submitForm();
client.end();
Let's use the Mocha and Chai syntax to describe a test; we'll test some properties of the example.com web page:
describe('Test example.com', function(){
before(function(done) {
client.init().url('http://example.com', done);
});
describe('Check homepage', function(){
it('should see the correct title', function(done) {
client.getTitle(function(title){
expect(title).to.have.string('Example Domain');
done();
});
});
it('should see the body', function(done) {
client.getText('p', function(p){
expect(title).to.have.string(
'for illustrative examples in documents.'
);
done();
})
});
});
after(function(done) {
client.end();
done();
});
});
You might want to share one client initialization over many test files. Create a small Node module to initialize and import it into every test file:
client.js:
exports.client = require('webdriverjs').remote({
// Settings
};
test.js:
var client = require('./client').client;
var expect = require('chai').expect;
// Perform tests
EDIT based on the question in the comments:
Here is how to install the selenium server, and yes you need to do it.
Selenium
Download Selenium Server. It is distributed as a single jar file, which you run simply:
java -jar selenium-server-standalone-2.28.0.jar
As soon as you execute this command, it boots up a server to which your testing code will connect later on. Please note that you will need to run Selenium Server every time that you run your tests.
That's my question, every time I go to the console and try to restart the server by doing gulp, a new tab is open in the browser, so I have to close the one I have open and start working on the new one.
And another question regarding the same:
sometimes there is an error on the code styling and the tab is open anyways once you do gulp, but you can not start working on it until you fix the error on the code style, then you go and do gulp and the new tab comes up.
here is my gulpfile.js
var gulp = require('gulp');
var paths = {
sass: ['scss/**/*.scss'],
js: ['www/js/*.js', 'www/js/**/*.js', '!www/js/lib.min.js', '!www/js/code.min.js']
};
// Dev task
gulp.task('dev', ['sass', 'lint', 'compress-lib', 'compress-js', 'run-ionic'], function() { });
// Build task
gulp.task('default', ['dev', 'lint', 'sass', 'compress-lib', 'compress-js', 'watch']);
//Ionic Serve Task
gulp.task('run-ionic',shell.task([
'ionic serve'
]));
gulp.task('compress-lib', function() {
gulp.src([
'./www/lib/ionic/js/ionic.bundle.min.js'
])
.pipe(concat('lib.min.js'))
.pipe(gulp.dest('./www/js'))
.pipe(livereload());
});
gulp.task('compress-js', function() {
gulp.src([
'./www/js/app.js'
])
.pipe(ngAnnotate())
.pipe(concat('code.min.js'))
.pipe(gulp.dest('./www/js'))
.pipe(livereload());
});
// JSHint task
gulp.task('lint', function() {
gulp.src(paths.js)
.pipe(jscs())
.pipe(jshint())
.pipe(jshint.reporter('default'))
.pipe(livereload());
});
gulp.task('sass', function(done) {
gulp.src('./scss/ionic.app.scss')
.pipe(sass({onError: function(e) { console.log(e); } }))
.pipe(autoprefixer('last 2 versions', 'Chrome', 'ios_saf','Android'))
.pipe(gulp.dest('./www/css/'))
.pipe(minifyCss({
keepSpecialComments: 0
}))
.pipe(rename({ extname: '.min.css' }))
.pipe(gulp.dest('./www/css/'))
.on('end', done)
.pipe(livereload());
});
gulp.task('watch', function() {
gulp.watch(paths.sass, ['sass']);
gulp.watch(paths.js, ['lint', 'compress-lib', 'compress-js']);
livereload.listen(9000);
});
gulp.task('install', ['git-check'], function() {
return bower.commands.install()
.on('log', function(data) {
gutil.log('bower', gutil.colors.cyan(data.id), data.message);
});
});
Live Reload App During Development (beta)
The run or emulate command will deploy the app to the specified platform devices/emulators. You can also run live reload on the specified platform device by adding the --livereload option. The live reload functionality is similar to ionic serve, but instead of developing and debugging an app using a standard browser, the compiled hybrid app itself is watching for any changes to its files and reloading the app when needed. This reduces the requirement to constantly rebuild the app for small changes. However, any changes to plugins will still require a full rebuild. For live reload to work, the dev machine and device must be on the same local network, and the device must support web sockets.
With live reload enabled, an app's console logs can also be printed to the terminal/command prompt by including the --consolelogs or -c option. Additionally, the development server's request logs can be printed out using --serverlogs or -s options.
Command-line flags/options for run and emulate:
[--livereload|-l] ....... Live Reload app dev files from the device (beta)
[--consolelogs|-c] ...... Print app console logs to Ionic CLI (live reload req.)
[--serverlogs|-s] ....... Print dev server logs to Ionic CLI (live reload req.)
[--port|-p] ............. Dev server HTTP port (8100 default, live reload req.)
[--livereload-port|-i] .. Live Reload port (35729 default, live reload req.)
[--debug|--release]
While the server is running for live reload, you can use the following commands within the CLI:
restart or r to restart the client app from the root
goto or g and a url to have the app navigate to the given url
consolelogs or c to enable/disable console log output
serverlogs or s to enable/disable server log output
quit or q to shutdown the server and exit
if using browsersync
// Stop the browser from automatically opening
open: false
https://www.browsersync.io/docs/options
browserSync.init({
proxy: 'localhost:8000',
open: false,
browser: "google chrome",
files: [
'./**/*.php'
]
});
I want to wait for a server to be ready, then run a task on top of it
EDIT:
I've got some of this figured out. I am properly filtering for my string. However, how can I keep this running in the background, and have it terminate when a grunt sequence is complete?
Consider
grunt common server spec-e2e
This will run the common tasks, run the grunt server, then (without stopping the server) runs the next task on top. After all of this is complete, it turns off the server automatically.
That's the kind of functionality that I'm trying to create.
A couple important points that I learned:
Processes started from node - e.g. require('child_process').spawn(...) - will continue to run for all subsequent grunt tasks (they won't be closed once the single task completes).
Once grunt is finished running the sequence of tasks, it will terminate all spawned processes.
Therefore, the command grunt selendroid:selendroid.jar spec-e2e - where the selendroid task starts a server - will keep the server running until after the spec-e2e task completes.
The code for my selendroid task is:
grunt.registerTask('selendroid', 'Start selendroid server', function (appLocation) {
var done = this.async();
var timeout = setTimeout(function() {
console.log('Selendroid took too long to start');
done(false);
}, 30000);
function checkLoaded(data) {
data = data.toString();
if (data.indexOf('Selendroid standalone server has been started on port') > -1) {
clearTimeout(timeout);
done();
}
}
if (typeof appLocation === 'undefined') {
console.log('App to test not set, aborting...'.red);
done(false);
}
var cmd = require('child_process').spawn('java', ['-jar', 'selendroid.jar', '-app', appLocation]);
cmd.stdout.on('data', function(data) {
checkLoaded(data);
});
cmd.stderr.on('data', function(data) {
checkLoaded(data);
});
});