Terminate gulp-watch task - gulp-watch

I want my gulp watch task to run only once, then stop watching. Now, if I run 'gulp' from the command line, the watch tasks keeps the gulp task running. I have to hit Ctrl-C to stop it.

when you run gulp watch, it will keep watching for file changes until you cancel it with CTRL-C. I you do not want this, then you can make a separate gulp task to do your building.
You would have 2 tasks then: gulp watch and gulp build. As the build wouldn't run the watch task, it will stop when finished.
Please take a look at a GitHub project of mine where I do things like this: skeletonSPA on GitHub.
If you take a look at the gulpfile.js, you see that the default task will execute the build task.
The build task on its turn will execute info, clean, styles, scripts, images, copy, todo; leaving you with a full build and working frontend.
After running these tasks, it will stop and gives you focus to the command line.

Here's a very basic example GulpFile.js:
var gulp = require('gulp'),
watch = require('gulp-watch'),
runSequence = require('gulp-sequence'),
webpack = require('webpack-stream');
gulp.task('webpack', function() {
return gulp.src('client/index.js')
.pipe(webpack({
output: {
filename: 'dist/bundle.js'
},
devtool: 'source-map'
}))
.pipe(gulp.dest('.'));
});
// other tasks
gulp.task('build', ['webpack', 'other tasks... ']);
gulp.task('watch', function(callback) {
gulp.watch('./client/**/*.js', {}, ['webpack']);
// more watches if required
});
gulp.task('default', function(callback) {
runSequence('build', 'watch', callback);
});
$ gulp build > will just run build the once and then exit.
$ gulp watch > will start watching (ctrl-c to exit).
$ gulp > will execute build and after that's complete it will run watch (ctrl-c to exit).
Note: I'm using the gulp-sequence plug to ensure that when running $ gulp the build will complete before the watch begins.

gulp.watch returns a FSWatcher object, which has a .close() method you can call to cancel the watch task:
var watchStream = gulp.watch(
src,
{ignoreInitial: true},
myGulpTask)
.on("change", function (triggerFileName) {
watchStream.close();
});
ignoreInitial = true prevents the task from running when the watcher starts. watchStream.close() will cancel the watcher, but the task will run once. So all in all, you get one task run.
This is with Gulp 4.

Related

Can somebody explain the `clean` dependency in this gulpfile?

Trying to study https://github.com/jhades/angularjs-gulp-example/blob/master/gulpfile.js, and I have noticed that for the task build there is a dependency clean. However, for most of the other definitions clean is also specified as a dependency! So if I run build it will run clean, but then what about build-css and build-template-cache which both also have clean dependencies, etc... will it also run the clean for each of those dependencies? So basically will running the one command gulp build end up running clean more than once... wiping out the output from other dependencies.... or will running clean the first time explicitly satisfy the dependency for the other dependencies and prevent clean from running again!?
Any pointers will be appreciated.
Please Note
I am NOT asking about what the proper cleaning techniques are! I am specifically asking about the link that I posted... and how IT is handling the clean task.
Dependencies
Dependencies in a gulp file just say that it has to have run before it at least once. For example this code:
var gulp = require('gulp');
gulp.task('main', ['b', 'a'], function() {
return gulp;
});
gulp.task('a', ['b'], function() {
return gulp;
});
gulp.task('b', ['a'], function() {
return gulp;
});
Will run like this:
main
a
b
Not:
main
a
b
a
b
Repeating infinitely.
Dependencies execution order
However, it could just as easily be run in the order main, b, then a. This is because of synchronous tasks in gulp. The dependencies have to run before the task asynchronously, but they run together or synchronously, this answer explains the difference between synchronous and asynchronous.
To avoid this you can use this code in Gulp 4:
gulp.task('main', function() {
gulp.series('a', 'b');
});
This will always run in the order main, a, b
But below that, you need to use the run-sequence package. Here's an example:
var runSequence = require('run-sequence');
gulp.task('main', function() {
runSequence('a', 'b');
})

gulp 4 dependencies and plugins

Due to issues with gulp 3 forcing my tasks to run concurrently, I have starting investigating gulp 4 with the hope of exploiting its gulp.series and gulp.parallel functions but I have hit a wall.
After some research I came across the undertaker-forward-reference plugin that should allow me to have something like:
var gulp = require('gulp');
var FwdRef = require('undertaker-forward-reference');
gulp.registry(FwdRef());
gulp.task('biggie', gulp.series('smalls'));
gulp.task('smalls', function(cb){
console.log("This is awesome");
cb();
});
where task 'biggie' depends on task 'smalls' but smalls is defined lower in in the gulp file. I get the following error:
assert.js:86
throw new assert.AssertionError({
^
AssertionError: Task never defined: smalls
What am I getting wrong here....
P.S. I am new to this so please be kind.
You just need to define "smalls" first. like...
var gulp = require('gulp');
var FwdRef = require('undertaker-forward-reference');
gulp.registry(FwdRef());
gulp.task('smalls', function(cb){
console.log("This is awesome");
cb();
});
gulp.task('biggie', gulp.series('smalls'));

Pass data between gulp tasks without writing to disk

I'm trying to annotate and minify a systemjs angular project. Systemjs comes with a build function, but it is not `'gulp-aware'. There is the possibility to pass the builder an option to minify, but there is not one for ng-annotate, so I will need gulp to do both for me instead.
gulp.task('bundle', function () {
var options = {}
builder.buildStatic('./assets/app/app.js', options)
.then(function(data) {
console.log("then called");
// make data available for another task
});
How can I combine the above with
gulp.task('productionApp', function() {
return [source the output from 'bundle']
.pipe(ngannotate())
.pipe(uglify())
.pipe(gulp.dest('./dist'));
});
I could just output the first task to a file, and then .src that in, but that can't be the best way?
The simplest way is to save it inside a buffer (actually, a simple object), then make a stream of and continue as you would with src.
Gulp's repository contains a recipe how it's done.
Note: you should make all those load-* tasks to run at the very beginning, you can either use run-sequence as they've done or make them as dependencies of the "real" tasks.
The yargs package on npm exports the object argv, wich is a very clever representation of the command-line params. For example, the invocation
gulp -a test -b 123 my-task
is represented during the run by a param argv with value
{ a: 'test', b: 123 }
which is passed to the gulp task my-task and, before it, to all its predecessors.
If one of the predecessors assigns a new prop to argv
argv.newProp = 'newValue'
this prop will be available to all its successors, including the task that you really want to execute.
The instruction const { argv } = require('yargs') is to be put at the start of the gulpfile, and it can be enriched with aliases and defaults. Reference is here

Angular Protractor - Leave browser open after E2E tests

Is it possible to leave the test browser windows open after Angular Protractor tests run? I have a tough test failing in FireFox and it'd be useful to access the state of the web page to see what's going on.
You can use Protractor debug/pause feature to pause the e2e run which will ultimately leave the browser open: more info here
To do so, add this line on your protractor test before the failing one
browser.pause();
There is also a very useful tool called elementor that you may want to take a look later on.
browser.pause no longer works with current Node v8.1.0, see here, but you could use browser.sleep(10000); to keep the browser open for e.g. 10 seconds
If you configured the test script to run using grunt, you could use the following code:
grunt.initConfig({
// ...
protractor: {
options: {
configFile: "protractor.conf.js",
keepAlive: true, // If false, the grunt process stops when the test fails.
noColor: false // If true, protractor will not use colors in its output.
},
run: {}
},
// ...
});
If you have Node 8+, bumped into issue "Error: Cannot find module '_debugger'" while attempting browser.pause solution from the accepted answer and you couldn't fix it using this github solution then you can workaround it as follows:
Install protractor as a module of the automation framework (i.e. without -g flag)
npm install protractor
Run webdriver-manager update for this protractor instance as well:
node ./node_modules/protractor/bin/webdriver-manager update
Where you have browser.pause(); in your code, replace it with debugger; statement
Run your code as follows:
node inspect ./node_modules/protractor/bin/protractor protractorConf.js
Where protractorConf.js is the config file of your protractor instance
If debugger waits for an input from you at the command line, just type cont and hit enter (to continue the execution)
super simple solution, that does exactly what's needed
The idea is that you don't really want to keep alive the session but rather pause it for a very long time when tests are done and be able to resume on-close procedures at any time
So just add this to your config.js
async onComplete() {
await browser.waitForAngularEnabled(false);
await browser.wait(
async () => {
let url = await browser.getCurrentUrl();
return url.includes('close/');
},
5 * 60 * 1000,
'Keep-alive timeout reached, closing the session...',
);
},
What the code does is, after all tests passed or failed, it waits until you type and submit close/ in browser's url field, or times out itself in 5 mins.
The reason await browser.waitForAngularEnabled(false); is needed here, because the browser opens an empty page when you type close/ which is non angular
You can even improve it and make it conditional, based on a parameter you pass to protractor config

Code coverage for Protractor tests in AngularJS

I am running some e2e tests in my angularJS app with protractor (as recommended in the angularJS documentation).
I've googled around and cannot find any information on how to measure coverage for my protractor tests.
I think I'm missing something here... is there any way to get a code coverage report for protractor e2e tests? Or is it simply a feature for unit tests?
This is achievable using Istanbul. Here is the process, with some example configurations that I've extracted from our project (not tested):
Instrument your code using the command istanbul instrument. Make sure that istanbul's coverage variable is __coverage__.
// gulpfile.js
gulp.task('concat', function () {
gulp.src(PATH.src)
// Instrument for protractor-istanbul-plugin:
.pipe(istanbul({coverageVariable: '__coverage__'}))
.pipe(concat('scripts.js'))
.pipe(gulp.dest(PATH.dest))
});
Configure Protractor with the plugin protractor-istanbul-plugin.
// spec-e2e.conf.js
var istanbulPlugin = require('protractor-istanbul-plugin');
exports.config = {
// [...]
plugins: [{ inline: istanbulPlugin }]
};
Run your tests.
Extract the reports using istanbul report.
This approach has worked for me and is easy to combine with coverage reports from unit tests as well. To automate, I've put step 1 into my gulpfile.js and step 3 and 4 in the test and posttest scripts in package.json, more or less like this:
// In package.json:
"scripts": {
"test": "gulp concat && protractor tests/spec-e2e.conf.js",
"posttest": "istanbul report --include coverage/**/.json --dir reports/coverage cobertura"
},
if you are using grunt - you can use grunt-protractor-coverage plugin, it will do the job for you. You will have to instrument the code first and then use the mentioned plugin to create coverage reports for you.
To add to ryanb's answer, I haven't tried this but you should be able to use something like gulp-istanbul to instrument the code and override the default coverage variable, then define an onComplete function on the jasmineNodeOpts object in your Protractor config file. It gets called once right before everything is closed down.
exports.config = {
// ...
jasmineNodeOpts: {
onComplete: function(){
browser.driver.executeScript("return __coverage__;").then(function(val) {
fs.writeFileSync("/path/to/coverage.json", JSON.stringify(val));
});
}
}
};
I initially tried the onComplete method suggested by daniellmb, but getting the coverage results only at the end will not include all the results if there were multiple page loads during the tests. Here's a gist that sums up how I got things working, but basically I had to create a reporter that added coverage results to the instanbul collector every time a spec finished, and then wrote the reports in the onComplete method. I also had to use a "waitPlugin" as suggested by sjelin to prevent protractor from exiting before the results were written.
https://gist.github.com/jbarrus/286cee4294a6537e8217
I managed to get it working, but it's a hack at the moment. I use one of the existing grunt istanbul plugins to instrument the code. Then I made a dummy spec that grabs the 'coverage' global variable and write it to a file. After that, you can create a report with any of the reporting plugins.
The (very over-simplified) test looks like:
describe('Output the code coverage objects', function() {
it('should output the coverage object.', function() {
browser.driver.executeScript("return __coverage__;").then(function(val) {
fs.writeFileSync("/path/to/coverage.json", JSON.stringify(val));
});
});
});

Resources