gulp command to take parameters - javascript

my package.json has scripts like this
{
"scripts": {
"pretest": "npm run tsc",
"test": "gulp e2e",
}
}
we use typescript and webdriverIO for automation. I want to use gulp so that i can pass parameters to my test framework. Example:
npm test --suite HomePageTests
then the specs related to Home page must run.
I have the gulp file like this
// gulpfile.js
const gulp = require('gulp');
const Launcher = require('webdriverio/build/lib/launcher');
const wdio = new Launcher(path.join(__dirname,
'src/config/conf.ts'));
// fetch command line arguments
const arg = (argList => {
let arg = {}, a, opt, thisOpt, curOpt;
for (a = 0; a < argList.length; a++) {
thisOpt = argList[a].trim();
opt = thisOpt.replace(/^\-+/, '');
if (opt === thisOpt) {
// argument value
if (curOpt) arg[curOpt] = opt;
curOpt = null;
}else {
// argument name
curOpt = opt;
arg[curOpt] = true;
}
}
console.log("arg", arg)
return arg;
})(process.argv);
gulp.task('e2e', () => {
return wdio.run(code => {
process.exit(code);
}, error => {
console.error('Launcher failed to start the test',error.stacktrace);
process.exit(1);
});
});
So when I call gulp directly like
gulp e2e --suite HomePageTests
it gets printed as
suite: HomePageTests
But if i use
npm test --suite HomePageTests
It fails as it prints gulp e2e HomePageTests
questions
How do I pass these values from npm to make gulp understand
If I am pass to another value like gulp e2e --server staging and would like to use the variable "staging" in my spec file like
if server=== staging{
// do this
} else {
// do that
}
How should I pass them from gulp file to my spec file?
Thanks!!

You could use the yargs dependence
var argv = require('yargs').argv;
gulp.task('test', function(){
console.log(argv.arg);
});
then if you run a command on a gulp passing the arg like this
gulp test --arg HomePageTests
it will output on console HomePageTests

Related

Why would gulp.watch not run on a windows computer when the same code executes on other windows computers?

I'm helping a remote coworker to setup with gulp on their Windows 10 computer, and have ran into an issue where the watch function in gulp simply will not work.
Other gulp functionality works well, but watch in particular just hangs without any error to the screen.
To ensure I'm not missing anything in my code, I made a simple test gulpfile to be sure that this wasn't due to some other reason.
gulpfile.js
var gulp = require("gulp");
var fs = require('fs');
var compareToPreviousRead = require("./fileReaderTest.js");
gulp.task("watch", function(){
return gulp.watch("Test.txt", async function(){
var diff = await compareToPreviousRead();
console.log(`Diff: "${diff}", Time: "${new Date().toGMTString()}"`);
Promise.resolve(true);
});
});
fileReaderTest.js
var fs = require('fs');
var readTestFile = () => new Promise(resolve => {
fs.readFile('Test.txt', 'utf8', (err, contents) => resolve(contents));
});
var originalValue = "";
var compareToPreviousRead = () => new Promise(resolve => {
readTestFile().then(updatedValue => {
var diff = updatedValue.replace(originalValue, "");
originalValue = updatedValue;
resolve(diff);
});
});
module.exports = compareToPreviousRead
I also included a few PowerShell Scripts to install and run the app from the same directory.
Someone could also just manually edit a file called "Test.txt" in the same directory (only appending to the file) and the gulp task would work correctly.
WriteToFileEverySecond.ps1
param ($testFileLocation)
Start-Sleep -Seconds 1
$i = 0
for ($i=0; $i -lt 10; $i++){
[System.IO.File]::AppendAllText($testFileLocation, "$i--", [System.Text.Encoding]::Ascii)
Start-Sleep -Seconds 1
}
TestGulpWatch.ps1
$currDir = $PSScriptRoot
cd $currDir
npm install --silent
Remove-Item "$currDir/Test.txt" -ErrorAction SilentlyContinue > $null
New-Item "Test.txt" -ItemType File > $null
$job1 = Start-Job -ScriptBlock {
param($currDir)
cd $currDir
gulp watch --silent
} -ArgumentList $currDir
Start-Sleep -Seconds 1
$job2 = Start-Job -FilePath "$currDir/WriteToFileEverySecond.ps1" -ArgumentList "$currDir/Test.txt"
while ($job1.HasMoreData -and $job2.HasMoreData) {
$job1,$job2 | Receive-Job
}
$job1,$job2 | Stop-Job
$job1,$job2 | Remove-Job
pause
They are using the following versions:
npm: 6.13.1
gulp cli version: 2.2.0
gulp repo version: 4.0.2

Gulp watch /tmp permission denied

I'm using gulp in one of my projects. When running gulp watch from OS (Arch Linux)
fs.js:921
return binding.readdir(pathModule.toNamespacedPath(path), options.encoding);
^
Error: EACCES: permission denied, scandir '/tmp/systemd-private-c33e4391b18f4b24af3055190fb15730-systemd-hostnamed.service-zrxyaX/'
at Object.fs.readdirSync (fs.js:921:18)
at Gaze._addToWatched (/home/majmun/code/wp/wp-content/plugins/project/node_modules/glob-watcher/node_modules/gaze/lib/gaze.js:274:22)
at Gaze._internalAdd (/home/majmun/code/wp/wp-content/plugins/project/node_modules/glob-watcher/node_modules/gaze/lib/gaze.js:191:10)
at /home/majmun/code/wp/wp-content/plugins/project/node_modules/glob-watcher/node_modules/gaze/lib/gaze.js:400:16
at Array.forEach (<anonymous>)
at /home/majmun/code/wp/wp-content/plugins/project/node_modules/glob-watcher/node_modules/gaze/lib/gaze.js:396:12
at FSReqWrap.oncomplete (fs.js:153:20)
I'm running gulp from host OS instead from a virtual machine because it's much faster.
I understand that problem is that gulp is doing something in /tmp folder of host OS, and some files have root privileges.
If I run sudo chown -R majmun:users /tmp, after while a new file with root privileges appears which break gulp.
Why gulp watch need /tmp folder.
Did someone resolve this problem?
Here is code of gulp watch task
// gulp watch
Gulp.task('watch', ['dev'], function() {
console.log('Initializing assets watcher:')
let stream = new Stream();
let filter = '*.{css,scss,sass,less,js,png,jpg,jpeg,svg}';
let tmp = Tmp.fileSync();
let glob = [
path.src.assets + '**/' + filter,
path.src.elements + '**/' + filter,
path.src.properties + '**/' + filter,
];
for (let i = 0; i < glob.length; i++) {
console.log('- ' + glob[i]);
}
let watcher = Gulp.watch(glob, ['dev']);
watcher.add(tmp.name);
process.on('SIGINT', function() {
stream.emit('end');
process.exit(0);
});
KeyPress(process.stdin);
process.stdin.on('keypress', function(char, key) {
if (key && key.ctrl && key.name == 'c') {
process.emit('SIGINT');
}
else if (key && key.ctrl && key.name == 'r') {
Fs.utimes(tmp.name, new Date(), new Date(), function() {});
}
});
process.stdin.setRawMode(true);
process.stdin.resume();
console.log('Watcher up and running, Ctrl+R to refresh, Ctrl+C to exit.');
return stream;
});
I fix this by adding some option when using tmp library. Instead of default options I specify where temporary folder will be and it's permission.
So instead of this:
let tmp = Tmp.fileSync();
I did this:
let tmp = Tmp.fileSync({
// Use settings from .env if defined
dir: process.env.MY_TMP_DIR || ''
mode: process.env.MY_TMP_MODE || '',
prefix: process.env.MY_TMP_PREFIX || '',
});

NodeJs: external javascript with dependencies

We are trying to use only nodeJS with minimal dependencies to other packages, the challenge we now encounter is HandelbarsJS. We found a package, Assemble who can generate html for us. Only, it is very very slow, about 3 seconds each time, of these 3 seconds, there are 2,5 / 2,7 seconds of the next line:
var assemble = require('assemble');
Our package.json script section:
"scripts": {
"build:handlebars": "node scripts/handlebars.js",
"watch:handlebars": "nodemon --watch assets --exec \"npm run build:handlebars\"" }
the script/handlebars.js file
#! /usr/bin/env node
var assemble = require('assemble');
var extname = require('gulp-extname');
console.log(Date.now() - start);
assemble.data('assets/templates/data/*.json');
assemble.layouts('assets/templates/layouts/*.hbs');
assemble.partials('assets/templates/partials/*.hbs');
assemble.src('assets/templates/*.hbs', { layout: 'default' })
.pipe(extname())
.pipe(assemble.dest('build/'));
Each time, when we save a .hbs file, Nodemon restart and the external javascript file will be called.
How can we ensure that 'require' get called only once, or whether they remain in memory?
Thank you!
Since you want to accomplish using this with assemble, but without gulp, I recommend chokidar.
npm install chokidar --save
Now you can require chokidar like this:
var chokidar = require('chokidar');
Then define a little helper that runs handler whenever something in a pattern changes:
function watch(patterns, handler) {
chokidar.watch(patterns, {
ignoreInitial: false
}).on('add', handler).on('change', handler).on('unlink', handler);
}
Now we can alter the script like this:
#! /usr/bin/env node
var assemble = require('assemble');
var extname = require('gulp-extname');
var chokidar = require('chokidar');
console.log(Date.now() - start);
assemble.data('assets/templates/data/*.json');
assemble.layouts('assets/templates/layouts/*.hbs');
assemble.partials('assets/templates/partials/*.hbs');
// Enable --watch command line for Chokidar, otherwise, just run!
if (process.argv.pop() === '--watch') {
watch('assets', runOnce);
} else {
runOnce();
}
function watch(patterns, handler) {
chokidar.watch(patterns, {
ignoreInitial: false
}).on('add', handler).on('change', handler).on('unlink', handler);
}
function runOnce() {
assemble.src('assets/templates/*.hbs', { layout: 'default' })
.pipe(extname())
.pipe(assemble.dest('build/'));
}
And instead of nodemon, this will keep your script alive and running. So, in npm, you want this:
"scripts": {
"build:handlebars": "node scripts/handlebars.js",
"watch:handlebars": "node scripts/handlebars.js --watch"
}
Whenever a file changes, the script will now run, without re-invoking from scratch.
The beta version of assemble is based on gulp and has a cli that you can use just like you would use gulp, but if you don't want to use the cli and use npm scripts instead, you can do something based on #roel-van-uden's answer without chokidar and also be able to reload the actual assets (e.g. data, layouts, partials)
#! /usr/bin/env node
var start = Date.now();
var assemble = require('assemble');
var extname = require('gulp-extname');
assemble.task('assets', function () {
console.log(Date.now() - start);
assemble.data('assets/templates/data/*.json');
assemble.layouts('assets/templates/layouts/*.hbs');
assemble.partials('assets/templates/partials/*.hbs');
return assemble.src('assets/templates/*.hbs', { layout: 'default' })
.pipe(extname())
.pipe(assemble.dest('build/'));
});
assemble.task('watch', ['assets'], function () {
assemble.watch('./assets/**/*.*', ['assets]');
});
// Enable --watch command line
if (process.argv.pop() === '--watch') {
assemble.run(['watch']);
} else {
assemble.run(['assets']);
}

How to use gulp install bower

I want to do something like this when I run gulp:
1.use "gulp-bower" to install all dependency from bower.json.
2.Use "main-bower-files" to find all bower component and concat them into one file
var gulp = require('gulp');
var bower = require('gulp-bower');
var mainBowerFiles = require('main-bower-files');
gulp.task('default', function () {
return bower()
.pipe(gulp.src(mainBowerFiles()))
.pipe(concat('lib.js'))
.pipe(gulp.dest('static/lib'));
});
but this will give Error: Bower components directory does not exist first, then download the bower components after.
How can you download the components first then run main-bower-files
gulp-bower runs asynchronously, so it moves along to the next part of the pipe before the files have finished downloading. To solve this, you'll need to separate your tasks:
var gulp = require('gulp');
var bower = require('gulp-bower');
var concat = require('gulp-concat');
var mainBowerFiles = require('main-bower-files');
gulp.task('bower', function () {
return bower();
});
gulp.task('bower-concat', ['bower'], function () {
return gulp.src(mainBowerFiles())
.pipe(concat('lib.js'))
.pipe(gulp.dest('static/lib'));
});
gulp.task('default', ['bower-concat']);

Karma: how to change preprocessors on commandline (or switch preprocessors in config)

I want to run Karma a couple of times with different preprocessors. Based on the failures, the karma exec listens to --preprocessors on the commandline, but I can't get it set up properly.
The following all return the same error.
karma start --single-run web-app/karma.conf.js --preprocessors "{\"../grails-app/assets/javascripts/**/!(lib)/**/*.js\": \"jshints\"}"
karma start --single-run web-app/karma.conf.js --preprocessors {"../grails-app/assets/javascripts/**/!(lib)/**/*.js": "jshints"}
karma start --single-run web-app/karma.conf.js --preprocessors "{'../grails-app/assets/javascripts/**/!(lib)/**/*.js': 'jshints'}"
The error:
/usr/lib/node_modules/karma/lib/config.js:145
Object.keys(preprocessors).forEach(function(pattern) {
^
TypeError: Object.keys called on non-object
at Function.keys (native)
at normalizeConfig (/usr/lib/node_modules/karma/lib/config.js:145:10)
at Object.parseConfig (/usr/lib/node_modules/karma/lib/config.js:293:10)
at Object.exports.start (/usr/lib/node_modules/karma/lib/server.js:282:20)
Why am I doing this, are there any alternatives?
The coverage and jshint preprocessors aren't compatible. I could copy the karma.conf.js but that's not a great long-term option for maintainability.
Create a karma.conf.js template.
module.exports = {
...
}
Create a wrapper for karma (let's call it 'wrapper.js'):
var karma = require('karma');
function configurator(options){
var config = getTemplate();
// based on the options object will add different preprocessors
if(options.blah){
config.preprocessors["../grails-app/assets/javascripts/**/!(lib)/**/*.js"] = 'whatever';
}
return config;
}
function getTemplate(){
return {
// start with an empty object
preprocessors: {},
// point to the template, we will enrich it
configFile : __dirname + 'path/to/your/karma.conf.js'
};
}
function startKarma(options){
var config = configurator(options);
karma.server.start(config, function(exitCode){
// exit code === 0 is OK
if (!exitCode) {
console.log('\tTests ran successfully.\n');
// rerun with a different preprocessor
startKarma({blah1: true});
} else {
// just exit with the error code
process.exit(exitCode);
}
});
}
function passedArg(string){
// look at the arguments passed in the CLI
return process.argv.indexOf(string) > -1;
}
function start(){
// start with empty options
var options = {};
if(passedArg('blah')){
options.blah = true;
}
//start karma!
startKarma(options);
}
start();
At this point you can pass the parameter from the console:
$ node wrapper.js blah
For more information about the karma API have a look at: http://karma-runner.github.io/0.8/dev/public-api.html

Categories