How can I get a value from .getVisibleText() to my variable? - intern

How can I get a value from .getVisibleText() to my variable?
.getVisibleText return a command object to use .then with it. But is there any way to get the text to my own variable?

Writing a functional test shows an example that would make want to try
define(function (require) {
var registerSuite = require('intern!object');
registerSuite(function() {
var YOUR_VARIABLE;
return {
name: 'index',
'greeting form': function() {
return this.remote
.get(require.toUrl('index.html'))
.setFindTimeout(5000)
.findById('greeting')
.getVisibleText()
.then(function (text) {
YOUR_VARIABLE = text;
});
}
};
});
});

Related

Access variable inside function and block

I am playing around with some nodeJs things, I read about block and functions scooping but I was not able to access my variable jsonArrayObj:
csv({delimiter: [' ']})
.fromFile(csvFilePath)
.on('end_parsed', function(jsonArrayObj) {
console.log(jsonArrayObj);
function cssResult() {
return jsonArrayObj;
}
})
.on('error', (err) => {
console.log(err);
});
console.log('jsonArrayObj'); // I want to print the results here also
You can do it something like this.
csv({delimiter: [' ']})
.fromFile(csvFilePath)
.on('end_parsed', function(jsonArrayObj) {
console.log(jsonArrayObj);
myNewFunc(jsonArrayObj);
function cssResult() {
return jsonArrayObj;
}
})
.on('error', (err)=>{
console.log(err);
});
var myNewFunc = function(myVar){
console.log(myVar); // this will be your result
};
Your variable jsonArrayObj is just defined on your function's scope. So jsonArrayObj is just accessible in your function.
If you want to use it out of your function, you have to define a variable outside of your function, and then tell your function that this variable takes jsonArrayObj's value.
Like this :
var myRes;
csv({delimiter: [' ']})
.fromFile(csvFilePath)
.on('end_parsed', function(jsonArrayObj) {
myRes = jsonArrayObj;
console.log(jsonArrayObj);
function cssResult() {
return jsonArrayObj;
}
})
.on('error', (err)=>{
console.log(err);
});
console.log(myRes);

Node, mongo and loop, how to break loop when I find data

My code looks similar to that:
var mongo_client = require('mongodb').MongoClient, dataStorage;
lib = {
[...]
find: function(res, param, callback) {
var parentPath = param.path;
while (parentPath !== '/') {
collection.findOne({'paths' : parentPath}, {...}, function(err, data)) {
if (data) {
dataStorage = data;
callback(data, res);
}
}
if (dataStorage) {
return;
}
parentPath = lib.removeLastBlockOfPath(parentPath);
}
if (!dataStorage) {
callback(someDefaultData, res);
}
}
[...]
}
What I want to do is to find some path stored in mongo, or if there is no match, try do find first matching parent path.
I can't set dataStorage value from findOne callback is it any way to do that? Eaven if I find path it always run thru all path blocks.
Node is asynchronous, so your code must be written accordingly. An option is to use the async module, that has lots of tools to manage asynchronous flows.
For example, you could use the whilst function to manage your while loop:
find: function(res, param, callback) {
var parentPath = param.path,
dataStorage = null;
async.whilst(
function () { return parentPath !== '/'; },
function (done) {
collection.findOne({'paths' : parentPath}, {...}, function(err, data) {
if (data) {
dataStorage = data;
return callback(data, res);
}
parentPath = lib.removeLastBlockOfPath(parentPath);
done();
});
},
function (error) {
if (!dataStorage) return callback(someDefaultData, res);
}
);
}
Don't forget to install and require the async module:
var async = require('async');
Your code is written as if it is "traditional synchronous" -- which its not. You cannot check for dataStorage validity till results from findOne() come back -- so your checks need to be moved all the way into the inner "if (data)" statement. This is not a mongodb issue, this is purely how nodejs works and the fact that everything is asynchronous and works on callbacks.

Create/update with Sequelize on an array of items

I created a function to:
take an array of 'labels' and look for whether they have a record in the db already
create those which don't exist,
and update those which do exist
return a json array reporting on each item, whether they were updated/created, or resulted in an error
I managed to make it work but I feel like I just made some ugly dogs' dinner!
var models = require("../models");
var Promise = models.Sequelize.Promise;
module.exports = {
addBeans: function (req, callback) {
Promise.map(req.body.beansArr, function (bean) {
return models.Portfolio.findOrCreate({where: {label: bean}}, {label: bean});
}).then(function (results) { // Array of 'instance' and 'created' for each bean "findOrCreate(where, [defaults], [options]) -> Promise<Instance>"
var promisesArr = [];
results.forEach(function (result) {
if (result[1]) { // result[1] = wasCreated
promisesArr.push(Promise.resolve([result[0].dataValues.label, "created"]));
} else {
promisesArr.push(
models.Portfolio.update({label: result[0].dataValues.label},
{where: {label: result[0].dataValues.label}}).then(function () {
return Promise.resolve([result[0].dataValues.label, "updated"])
})
);
}
});
return promisesArr;
// When it's all done create a JSON response
}).then(function (results) {
var resultObj = {items: []}; // JSON to return at the end
Promise.settle(results).then(function (promiseinstances) {
for (var i = 0; i < promiseInstances.length; i++) {
if (promiseInstances[i].isFulfilled()) {
resultObj.items.push({
item: {
label: promiseInstances[i].value()[0],
result: promiseInstances[i].value()[1],
error: ''
}
});
}
else if (promiseInstances[i].isRejected()){
resultObj.items.push({
label: promiseInstances[i].value()[0],
result: 'error',
error: promiseInstances[i].reason()
});
}
}
// Send the response back to caller
}).then(function () {
return callback(null, resultObj);
}, function (e) {
return callback(e, resultObj);
});
});
}
};
Question:
Is there an easier or more obvious way to create/update values with Sequelize?
Is my use of Promise.settle() appropriate for this case? I have the feeling I made this more complicated than it needs to be.
I am new to Sequelize and using Promises, I'd appreciate if someone could advise on this.
I feel like this would work better on CodeReview.SE but I can see a few issues.
Is there an easier or more obvious way to create/update values with Sequelize?
Well, for one thing:
.then(function(array){
var newArr = [];
array.forEach(function(elem){
newArr.push(fn(elem);
}
return newArr;
});
Is just
.map(fn)
Additionally, promises assimilate so you can return val; from a .then you don't have to return Promise.resolve(val);.
So:
).then(function (results) { // Array of 'instance' and 'created' for each bean "findOrCreate(where, [defaults], [options]) -> Promise<Instance>"
var promisesArr = [];
results.forEach(function (result) {
if (result[1]) { // result[1] = wasCreated
promisesArr.push(Promise.resolve([result[0].dataValues.label, "created"]));
} else {
promisesArr.push(
models.Portfolio.update({label: result[0].dataValues.label},
{where: {label: result[0].dataValues.label}}).then(function () {
return Promise.resolve([result[0].dataValues.label, "updated"])
})
);
}
});
return promisesArr;
})
Is just
.map(function(result){
if(result[1]) return [result[0].dataValues.label, "created"];
return models.Portfolio.update({label: result[0].dataValues.label},
{where: {label: result[0].dataValues.label}}).
return([result[0].dataValues.label, "updated"]);
});
However, since you want it to work regardless of it being resolved, you'd have to do:
.then(function(results){
return results.map(function(result){
if(result[1]) return [result[0].dataValues.label, "created"];
return models.Portfolio.update({label: result[0].dataValues.label},
{where: {label: result[0].dataValues.label}}).
return([result[0].dataValues.label, "updated"]);
});
});
Which means it'll resolve regardless, then you'd call .settle():
.settle().then(function(results){
// your settle logic here
});
Note that the last:
}).then(function () {
return callback(null, resultObj);
}, function (e) {
return callback(e, resultObj);
});
Is simply:
.nodeify(callback);
However, I recommend sticking to promises.
I use Promise.settle for sequelize.update, and can get affect rows number by _settledValueField .
promise.push(...update...)
db.sequelize.Promise.settle(promise).then(function (allresult) {
var affectcnt = 0
allresult.forEach(function (singlecnt) {
if (undefined !== singlecnt._settledValueField[1]) {
affectcnt += parseInt(singlecnt._settledValueField[1])
}
})
unfortunately, it's only work for update.
You can insert array in database using sequelize. You want to change in model like below. I am trying to add multiple languages in database through array.
language: { type: DataTypes.STRING,
allowNull: false,
get()
{
return this.getDataValue('language').split(';')
},
set(val)
{
this.setDataValue('language',Array.isArray(val) ? val.join(','):val);
}
}

how to solve 'this' problems with node libraries like async and request

I've written a node script that gets some data by requesting REST API data (using the library request). It consists of a couple of functions like so:
var data = { /* object to store all data */ },
function getKloutData() {
request(url, function() { /* store data */}
}
// and a function for twitter data
Because I want to do some stuff after fetching all the I used the library async to run all the fetch functions like so:
async.parallel([ getTwitterData, getKloutData ], function() {
console.log('done');
});
This all works fine, however I wanted to put everything inside a object pattern so I could fetch multiple accounts at the same time:
function Fetcher(name) {
this.userID = ''
this.user = { /* data */ }
this.init();
}
Fetcher.prototype.init = function() {
async.parallel([ this.getTwitterData, this.getKloutData ], function() {
console.log('done');
});
}
Fetcher.prototype.getKloutData = function(callback) {
request(url, function () { /* store data */ });
};
This doesn't work because async and request change the this context. The only way I could get around it is by binding everything I pass through async and request:
Fetcher.prototype.init = function() {
async.parallel([ this.getTwitterData.bind(this), this.getKloutData.bind(this) ], function() {
console.log('done');
});
}
Fetcher.prototype.getKloutData = function(callback) {
function saveData() {
/* store data */
}
request(url, saveData.bind(this);
};
Am I doing something basic wrong or something? I think reverting to the script and forking it to child_processes creates to much overhead.
You're doing it exactly right.
The alternative is to keep a reference to the object always in context instead of using bind, but that requires some gymnastics:
Fetcher.prototype.init = function() {
var self = this;
async.parallel([
function(){ return self.getTwitterData() },
function(){ return self.getKloutData() }
], function() {
console.log('done');
});
}
Fetcher.prototype.getKloutData = function(callback) {
var self = this;
function saveData() {
// store data
self.blah();
}
request(url, saveData);
};
You can also do the binding beforehand:
Fetcher.prototype.bindAll = function(){
this.getKloutData = this.prototype.getKloutData.bind(this);
this.getTwitterData = this.prototype.getTwitterData.bind(this);
};
Fetcher.prototype.init = function(){
this.bindAll();
async.parallel([ this.getTwitterData, this.getKloutData ], function() {
console.log('done');
});
};
You can save this into another variable:
var me = this;
Then me is your this.
Instantiate object with this function:
function newClass(klass) {
var obj = new klass;
$.map(obj, function(value, key) {
if (typeof value == "function") {
obj[key] = value.bind(obj);
}
});
return obj;
}
This will do automatic binding of all function, so you will get object in habitual OOP style,
when methods inside objects has context of its object.
So you instantiate you objects not through the:
var obj = new Fetcher();
But:
var obj = newClass(Fetcher);

how to make single function here used two time

In this code :
if (!parms.script) { // no script... load filename
execscript(parms, function (data){
var text={'result':'success', 'response':data };
if(typeof(data)!='object') {
try {
text.response=JSON.parse(text.response);
} catch(e) {
text={'result':'success','response':data};
}
}
responsehttp.end(JSON.stringify(text));
});
} else {
//parameterised input will replace in script
if(query.paraminput!=undefined) {
var paraminput=qs.parse(query.paraminput);
parms=merge_options(parms, paraminput);
}
execscript(parms, function (data){
var text={'result':'success', 'response':data };
if(typeof(data)!='object') {
try {
text.response=JSON.parse(text.response);
} catch(e) {
text={'result':'success','response':data};
}
}
responsehttp.end(JSON.stringify(text));
});
}
in execscript callback it is called two times , i want to make a single function for executing both call back in if and else .
how can i achieve this .
i tried making seperate function but responsehttp undefinded error camed.
The problem is (I suspect) is that you had your common function declared outside the context of your http response handler and, therefore, responsehttp wasn't defined. Instead create it as a closure function inside your outer function's scope:
function someCallbackYouDontShowInYourQuestion(req, responsehttp) {
// Declare your callback as a closure inside this function, so it
// captures responsehttp state
function callback(data) {
var text={'result':'success', 'response':data };
if(typeof(data)!='object') {
try {
text.response=JSON.parse(text.response);
} catch(e) {
text={'result':'success','response':data};
}
}
responsehttp.end(JSON.stringify(text));
}
if (!parms.script) { // no script... load filename
execscript(parms, callback);
} else {
//parameterised input will replace in script
if(query.paraminput!=undefined) {
var paraminput=qs.parse(query.paraminput);
parms=merge_options(parms, paraminput);
}
execscript(parms, callback);
}
}
callback = function (data){
var text={'result':'success', 'response':data };
if(typeof(data)!='object') {
try {
text.response=JSON.parse(text.response);
} catch(e) {
text={'result':'success','response':data};
}
}
responsehttp.end(JSON.stringify(text));
}
execscript(parms, callback);

Resources