I'm trying to write a gulp tasks that takes some user input via the gulp-prompt plugin. But I'm having trouble passing that input along to other eg:
gulp.task('userinput', function(){
var myVar = 'MONKEY';
gulp.src('./templates/_component.*')
.pipe(prompt.prompt([
{
type: 'input',
name: 'userInput',
message: 'Say something'
}
], function(res){
myVar = res.userInput;
}))
.pipe(prompt.confirm('You said ' + myVar));
});
Assuming I enter hello at the prompt, I was expecting the confirmation to say You said Hello, but it says You said MONKEY.
Is this possible with Gulp?
The issue here is that you are creating the second prompt ('You said ' + myVar) before the first prompt has been executed:
Set myVar to 'MONKEY'
Create streams
Create src stream, which is asynchronous
Create first prompt, and add it to the src stream
Create second prompt using current value of myVar, and add it to the first prompt stream
Only now are the streams executed processed
Load sources
Run first prompt, set the myVar
Run the second prompt using previously generated message
The only solution if you want to keep it all as a single stream is to use the variable within something that allows for a closure (function). Some plugins already accept a closure as an argument, but most don't.
One solution to wrap a stream in a closure that would work here is gulp-tap, which isn't designed for this scenario specifically, but should work. it looks like this:
var tap = require('gulp-tap');
//...
gulp.task('userinput', function(){
var myVar = 'MONKEY';
gulp.src('./templates/_component.*')
.pipe(prompt.prompt([
{
type: 'input',
name: 'userInput',
message: 'Say something'
}
], function(res){
myVar = res.userInput;
}))
.pipe(tap(function(file, t) {
// format is t.through(stream-function, [arguments...])
return t.through(prompt.confirm, ['You said ' + myVar]);
});
});
Because this is wrapped in a closure, and evaluated for each file, it will pick up the current value for the variable. However, because it works on each file, you'll see the prompt once for each file processed.
An better solution would be to separate your task into multiple, dependent tasks. That would look something like this:
var myVar = 'MONKEY';
gulp.task('userinput1', function(){
return gulp.src('./templates/_component.*', {read: false})
.pipe(prompt.prompt([
{
type: 'input',
name: 'userInput',
message: 'Say something'
}
], function(res){
myVar = res.userInput;
}));
});
gulp.task('userinput', ['userinput1'], function() {
return gulp.src('./templates/_component.*')
.pipe(prompt.confirm('You said ' + myVar));
});
Now the first task (userinput1) will run and complete before the second one is processed (userinput2), so the variable will be set correctly.
NOTE: Make sure you return the stream from your tasks, otherwise they are processed synchronously, and your variable won't get set.
Finally, it might make more sense to forgo the gulp-prompt task altogether, because it doesn't really have much to do with the stream. You'd probably be better off using straight Node JavaScript within your task to gather the user's input (preferably in a synchronous manner), then processing your files in a gulp-stream after that.
Related
I have one really long function tests, that starts from the login panel of my web application and goes all the way through deeper features. It is my first time using nightwatch.js - I'm wondering if there is a way to break this huge function up, into multiple, segmented functions, that run sequentially. I tried, literally breaking it up into separate functions, just like my main, large one, I also tried wrapping each separated function in between 'browser' and 'browser.end();' but this also did not work - what happens is, they don't run sequentially - so of course they don't find the next underlying elements, etc. because it starts over. Any advice?
this.LoginScreen = function(browser) {
browser
.url(Data.urls.home)
.waitForElementVisible('#login', 1000, false)
.click('#login')
.waitForElementVisible('div.side-panel.open', 4000, false)
// Ton more here, i'd like to modulate
Errors.checkForErrors(browser);
browser.end();
};
That's very simple and available in Nightwatch Getting Started Page http://nightwatchjs.org/gettingstarted
module.exports = {
'Verify Added customer': function (browser) {
// In above first function with name 'Verify Added customer'
browser
.click(rc.registeredCustomers)
.pause(t.averagePauseLimit)
},
'Verify Email Button Present': function (browser) {
// in above there is second function
browser
.click(rc.registeredCustomers)
.pause(t.averagePauseLimit)
.getText(rc.primaryEmail, function (result) {
this.assert.equal(result.value, 'Primary : ' + email)
})
.pause(t.minimumPauseLimit)
.click(rc.verifyCustomer)
.pause(1000)
.assert.elementNotPresent(rc.verifyEmail, 'Verify Email is not present')
},
This question is different from the one linked as already having an answer. It is specifically this piece of code adapted from node.js documentation regarding the use of fs and readfile and looking for an end of file flag, which I've learned is readfile.close method. Thanks for the answer.
I wrote a small utility locally to try to convert a text file of key:value pairs with a blank line separating programs into a JSON file to use in a React project.
I got the foundation of the readline function directly from node.js documentation. I'm using node 6.9.0 on my mac
here is the full script:
const readline = require('readline');
const fs = require('fs');
const rl = readline.createInterface({
input: fs.createReadStream('usat-ncaa-programs.txt')
});
var newPairs=["test"];
rl.on('line',
function (line) {
if (line===null){
newPairs.push("}], [ {")
} else if (line) {
var keyValue = line.match(/^(.*):(.*)/)
var newKeyValuePair = "'" + keyValue[1].trim() + "': '" + keyValue[2].trim() + "'"
newPairs.push(newKeyValuePair)
//console.log (newKeyValuePair)
}
})
console.log(newPairs)
The input file looks like this (there are about 12 programs), i've only included 2 1/2 so you can see the format:
University: Arizona State University
Division: I
University Home Page: http://www.asu.edu/
Recruiting Link: https://questionnaire.acsathletics.com/Questionnaire/Questionnaire.aspx?&SPSID=1061112&SPID=177408&DB_LANG=C&DB_OEM_ID=30300&q=2015&s=159130&o=143
Team Homepage: http://www.thesundevils.com/index.aspx?path=triathlon
Head Coach: Cliff English
w: 480.965.0546
e: cliff.endlish#asu.edu
bg-color: #990033
color: #FFB310
University: Belmont Abby College
Division: II
University Home Page: http://belmontabbeycollege.edu/
Recruiting Link: https://coach.scoutforce.com/p/414f3219dd
Team Homepage: http://abbeyathletics.com/sports/wtri/index
Head Coach: Nick Radkewich
w: 704.461.5010
e: NicholasRadewich#bac.edu
Twitter: https://twitter.com/AbbeyTri
bg-color: #FFFDD0
color: #DC143C
University:Black Hills State University
Division: II
University Home Page: http://www.bhsu.edu/
...
My problem is that while I can read the text file line by line and parse some information that looks like a JSON file, I am unable to access that data outside of the callback function.
I don't know how to save this data into a new file, or even just output the object to my console for a cut & paste and manually edit.
In teh above script the logged output of the variable newPairs is ["test"] rather than the line by line parsing that I'm trying to acccomplish.
If I place the console.log inside the callback, I get information logged with every iteration of the file read. I only want to work with the data when the file is done.
I did not find an EOF or similar flag in the node documentation for either fs or readline.
Additionally, if there is an easier way to get the data I am inputting into JSON format, I'd love to hear. Thanks in advance.
You have to understand that the callback function is executed asynchronously. This means that console.log(newPairs) gets executed before your callback, therefore it only results in "test".
You should listen to Readline's close event, like so:
rl.on('close', function() {
console.log(newPairs);
});
As the documentation states:
The 'close' event is emitted when one of the following occur:
The rl.close() method is called and the readline.Interface instance
has relinquished control over the input and output streams;
The input stream receives its 'end' event; The input stream receives -D to signal end-of-transmission (EOT);
The input stream receives -C to signal SIGINT and there is no SIGINT event listener registered on the readline.Interface instance.
The listener function is called without passing any arguments.
The readline.Interface instance should be considered to be "finished"
once the 'close' event is emitted.
So this would be the 'EOF' you're looking for :-)
i know its an old question but the answer didn't help me. You can use an promisse like this:
function readLineAsync(){
var data = [];
var i = 0;
return new Promise((resolve,reject)=>{
var lineRead = readLine.createInterface({
input:fs.createReadStream('path.to.file')
})
lineRead.on('line',(line)=>{
data[i] = line;
i++;
})
lineRead.on('close',()=>{
resolve(dataCsv);
})
})
}
(async function(){ console.log(await readLineAsync())}())
So I'm using inquirer to ask a question from my users via terminal:
var inquirer = require('inquirer');
var question = {
name: 'name',
message: '',
validation: function(){ ... }
filter: function(){ ... }
};
but at the same time let my users pass this field via --name command line argument. (say arg.name)
Question is: How can I tell inquirer to take this arg.name value and use it as if user entered it for the answer of this question.
Note that I DO need the validation and filter to also kick-in for this value. (for example if value passed via --name is invalid, the user is presented with the error message and asked to enter another value)
I'm hoping there is a way to solve this problem without having to hack-around manually calling my validation/filter methods.
You could set up a default value to a variable from arg.name:
let argument = args.name;
const question = {
name: 'name',
message: 'Name?',
default: argument
};
I tried testing this and it works. The user just has to hit enter to use the name passed in the arguments so maybe tell them that in the prompt. Also be aware that your validation will take place AFTER your filters. You just need to make sure whatever your filters are doing will pass validation.
How I can set two different test messages for fail and pass test cases and after running all test cases how I can get list of all fail and pass messages which I can print in log file or xml file.
What is better way to store all messages and get in correct format.
Here is my Sample Home page.js
HomePage = function () {
var PageTestParams = TestParams.Modules.HomePage,
PageLangText = Lang.Modules.HomePage;
SearchResult = function(test){
},
SearchTextField = function(test){
test.assertExists(PageTestParams.SearchFormSelector, PageLangText.SuccessMsg["SearchForm"]);
SearchResult(test);
},
NavigationCount = function(test){
test.assertElementCount(PageTestParams.NavigationSelector, PageTestParams.NavigationCount,PageLangText.SuccessMsg["NavigationCount"]);
SearchTextField(test);
},
CheckTitle = function(test){
test.assertTitle(PageTestParams.Title, PageLangText.SuccessMsg["TitleText"]);
casper.test.pass("main fail ho gaya");
NavigationCount(test);
},
this.init = function(test){
CheckTitle(test);
}
};
I am passing this JS for test assertion if any test case fail or pass the same message is getting printed for same scenario. I have searched and got below syntax but its printing same message which I have setted in test assertion.
casper.test.on("fail", function(failure) {
casper.echo("FAIL " + failure.message);
});
To get two different messages when using a single test is something I have personally not come across yet. If you want a way to work around it you could do something like:
var x=4;
if(x>2){
casper.test.pass("PASS Message.");
}else{
casper.test.fail("FAIL Message.");
}
You could manipulate the if statement to have a boolean or whatever else you may like, but this seems like the most obvious way I would do it.
As for getting a list of all passing and failing messages, the extent I know about that is that there are the getFailures(); and a getPasses(); methods, these may or may not be what your looking for, but maybe they can help get you started! Good Luck!
You can do something like this (same logic for success or fail):-
var successes = [];
casper.test.on("success", function(success) {
successes.push(success);
});
Then on casper.run you can do a couple of things:-
1) To see the full dump of all successes (you can see all the properties) you can do this:-
casper.run(function () {
test.done();
require('utils').dump(successes);
});
2) to output the array of successes one by one (so you can format the output) you can do:-
casper.run(function () {
test.done();
successes.forEach(function(item){
casper.echo(item.standard);
});
});
3) I assume you know you can also output the full test assertions to xunit by passing in --xunit=output.xml
How can I check all Meteor helpers have run?
When I use this code, I get a new, empty div. When I remove the code from the rendered function and run it from my console, everything works fine.
Template.CasesShow.helpers({
value: function (n) {
if (this.data) {
var result = this.data.filter(function (obj) {
return obj.name == n;
});
if (result && result[0])
return result[0].value;
}
}
});
Template.CasesShow.rendered = function () {
$(document).ready(function () {
$textarea = $('[name=1]');
var content = $textarea.val().replace(/\n/g, '<br />');
$textarea.replaceWith($('<div class="box">' + content + '</div>'));
});
};
<template name="CasesShow">
<textarea class="w-input box" placeholder="{{_ 'laborauftrag.praxis'}}" name="1" data-name="1">{{value 1}}</textarea>
</template>
So I think, Meteor hasn't inserted the value yet, which is strange because it shouldn't run the rendered function then, right?
How can I make sure Meteor has run the helpers?
Template.rendered = func will run once before your template's helper (and long before your route provides you data). Your template isn't working when you have Template.rendered function because in your rendered function, you replace your textarea with div, and in helper you're returning value which is being set on the textarea which no longer exist (because Template.CaseShow.rendered has replaced it with <div>.
If you can provide more details about what you're actually trying to achieve here, we can solve that. What you have right now is intended behaviour of meteor.
If what you want to achieve is show your content in a div but after replacing /n with <br>, I believe you can do that by performing that regexp on your data in the template helper.
Put a console.log("FIRED VALUE HELPER"); and do the same for your .rendered console.log("TEMPLATE RENDERED"); The code will log in your client browser console. For chrome I right click on the browser and choose inspect element. Then choose console from the array of logs. Your client js code would look like this:
Template.CasesShow.helpers({
value: function (n) {
console.log("FIRED VALUE HELPER");
Template.CaseShow.rendered = function () {
console.log("FIRED RENDERED");
If you don't see the log in the client browser console, the helper/rendered function did not get called.