how to have a variable value for casper.repeat - casperjs

I want to repeat steps with CasperJS depending on a variable value coming from the page where I run CasperJS.
To get this value, I do something like:
casper.waitForSelector(".xxxx", function () {
myvalue = this.evaluate(function() {
value = Math.ceil(document.querySelector('#yyy').getAttribute('data-all')/10)-1;
return value;
});
});
Then I try to do something like:
casper.repeat(myvalue, function() {
but it doesn't work because repeat can't find myvalue variable. Any idea how to achieve something like that?
EDIT
now I try this :
var myvalue = "";
casper.waitForSelector(".xxxx", function () {
myvalue = this.evaluate(function() {
value = Math.ceil(document.querySelector('#connections').getAttribute('data-num-all')/10)-1;
return value;
});
});
casper.repeat(myvalue, function() {
Now I didn't get any synthax error but the repeat isn't executed at all (myvalue=49)

I think casper.repeat and casper.waitForSelector are executed asynchronously, so repeat() is executed before the waitFor().
Try that :
var myvalue = "";
casper.waitForSelector(".xxxx", function () {
myvalue = this.evaluate(function() {
value = Math.ceil(document.querySelector('#connections').getAttribute('data-num-all')/10)-1;
return value;
});
});
casper.then(function(){
casper.repeat(myvalue, function() {
this.echo("Here the code to be executed 'myvalue' times");
});
});
The then() statement wait for the previous waitForSelector() to be executed before executing repeat().

Related

Checkbox with search filter codeigniter

My problem is when I check one of the checkboxs and then I search it, the checkbox will change to uncheck. and I don`t know what's wrong with my livesearch, it is not working.
please check this link to test.
http://jsfiddle.net/v921/KmVHf/4/
is is my javascript
var tr = $(".AvailableGroupLab").clone().html();
function filter(element) {
$('.AvailableGroupLab').html(tr);
var value = $(element).val().toLowerCase();
$(".AvailableGroupLab tr").each(function () {
if ($(this).text().toLowerCase().search(value) == -1){
$(this).remove();
}
});
}
Try
function filter(element) {
var $trs = $('.AvailableGroupLab tr').hide();
var regexp = new RegExp($(element).val(), 'i');
var $valid = $trs.filter(function () {
return regexp.test($(this).children(':nth-child(2)').text())
}).show();
$trs.not($valid).hide()
}
$('input:text').on('keyup change', function () {
filter(this);
})
Demo: Fiddle

Jasmine calling function with ajax returned value

I want to test the "addGroup" function using Jasmine. I get the following error:
Error: Expected spy modifyMyHtml to have been called.at null.
I don't know what is the best way to test the addGroup function. Please HELP.....
var myRecord = {
addGroup: function(groupNumber) {
$.when(myRecord.getHtml())
.done(function(returnedHtml){
myRecord.modifyMyHtml(returnedHtml);
});
},
getHtml: function() {
return $.ajax({url: "myHtmlFile.html", dataType: "html" });
},
// adds options and events to my returned HTML
modifyMyHtml: function(returnedHtml) {
$('#outerDiv').html(returnedHtml);
var myOptions = myRecord.getOptions();
$('#optionsField').append(myOptions);
myRecord.bindEventsToDiv();
},
}
====JASMINE TEST
describe("Configure Record page", function() {
var fixture;
jasmine.getFixtures().fixturesPath = "/test/" ;
jasmine.getFixtures().load("myHtmlFile.html");
fixture = $("#jasmine-fixtures").html();
describe("addGroup", function(){
beforeEach(function() {
var groupNumber = 0;
spyOn(myRecord, "getHtml").andCallFake(function(){
return $.Deferred().promise();
});
spyOn(myRecord, "modifyMyHtml");
myRecord.addGroup(groupNumber);
});
it("Should call getHtml", function() {
expect(myRecord.getHtml).toHaveBeenCalled();
});
it("Should call modifyMyHtml", function() {
expect(myRecord.modifyMyHtml).toHaveBeenCalled(); ==>FAILS
});
});
});
You have to resolve the promise before you return em in your andCallFake.
spyOn(myRecord, "getHtml").andCallFake(function(){
return $.Deferred().resolve ().promise();
});
Btw. you should not test that the function on the object you wanna test are called, but that the html in the DOM are set with the right html
it("Should call modifyMyHtml", function() {
spyOn(myRecord, "getHtml").andCallFake(function(){
return $.Deferred().resolveWith(null, 'returnedHtml').promise();
});
expect($('#outerDiv').html).toEqual('returnedHtml')
});

Pass jQuery event to default on-eventhandler

I've written a function to call the default jQuery.fn.on-handler, after a given number of fired events. Now I stuck, because the original event will not passed to the function, any ideas how to improve this?
;(function ($) {
var oldOn = $.fn.on,
i = 0;
$.fn.on = function () {
var args = arguments,
j = args.length;
for (var last in args);
while (j--) {
if ($.isFunction(args[j]) && !isNaN(args[last])) {
var oldFn = args[j],
after = args[last];
args[j] = function () {
i++;
if (i === after) {
oldFn.call();
i = 0;
}
};
}
}
if (!isNaN(args[last])) delete args[last];
return oldOn.apply(this, arguments);
};
})(jQuery);
// call the plugin and fire the `fn` after each 20 mousemoves
$(document).on('mousemove', function (e) {
console.log(e); // undefined
}, 20);
As you can see, will the following work without problems:
var oldOn = $.fn.on;
$.fn.on = function () {
return oldOn.apply(this, arguments);
};
$(document).on('click', function(e){
console.log(e) // jQuery.Event
});
Where's the mistake, how can i get this to work?
Update
I got it much simpler now: https://github.com/yckart/jquery.unevent.js
You're not passing the arguments from your callback wrapper function to the original callback function.
args[j] = function (*HERE*) {
i++;
if (i === after) {
oldFn.call(*TO HERE*);
i = 0;
}
};
Try replacing oldFn.call(); with oldFn.apply(this, [].slice.call(arguments)); to carry them over (and keeping up jQuery's this).
Edit: http://jsfiddle.net/QFyhX/
I think
for (var last in args);
should be
var last = args[args.length-1];

Conditionally pause Javascript to wait for ajax

The variable ajaxdata is modified within the success function, if that hasn't been done yet, I would like to wait 2 seconds, then continue without it.
The use case is for a jqueryui autocomplete field. The autocomplete source is an ajax request, but if the user types quickly, and exits the field before the list loads, the field remains unset. Using the 'change' event on the autocomplete I check if the user entered a valid option without selecting it, but this doesn't work if the source hasn't loaded when the change event fires. So I would like to put a delay in the change function which waits, if the source (stored in the variable 'ajaxdata') is empty.
code:
input.autocomplete({
source: function (request, response){
$.ajax(
{
type: "GET",
url: "/some/url",
dataType: "json",
success: function(data){
response($.map(data,function(item){
return{
label: item.label,
value: item.value
}
}));
ajaxdata = data;
}
}
);
// ajaxopts = ajaxsource(request,response,ajaxurl,xtraqry)
},
change: function(event, ui) {
if (!ui.item) {
// user didn't select an option, but what they typed may still match
var enteredString = $(this).val();
var stringMatch = false;
if (ajaxdata.length==0){
/// THIS IS WHERE I NEED A 2 SECOND DELAY
}
var opts = ajaxdata;
for (var i=0; i < opts.length; i++){
if(opts[i].label.toLowerCase() == enteredString.toLowerCase()){
$(this).val(opts[i].label);// corrects any incorrect case
stringMatch = true;
break;
}
}
}
},
});
Edit:
To be more specific about the problem: This delay needs to be conditional. Meaning that if the data is already loaded (either because it came from a static source, or from an earlier ajax call) I do not want to have a delay.
If I'm understanding you properly, I think you just want to check and see if ajaxdata has been populated; but if it hasn't, only wait two more seconds and then just proceed without it.
Try this:
change: function(event, ui) {
if (!ui.item) {
// user didn't select an option, but what they typed may still match
if (ajaxdata.length==0){
/// THIS IS WHERE I NEED A 2 SECOND DELAY
//pass in 'this' so that you can use it
setTimeout(function() {correctCase(this);}, 2000);
}
}
}
. . . . .
function correctCase(inThis){
//I'm not sure what this variable does. do you really need it???
var stringMatch = false;
var enteredString = $(inThis).val();
//you still want to be sure that ajaxdata is not empty here
if (ajaxdata.length==0){
var opts = ajaxdata;
for (var i=0; i < opts.length; i++){
if(opts[i].label.toLowerCase() == enteredString.toLowerCase()){
$(inThis).val(opts[i].label); // corrects any incorrect case
stringMatch = true; //this variable doesn't seem to do anything after this???
break;
}
}
}
}
I'm not really sure what it is you're trying to do, but I'm pretty sure something like this would be a better way of doing it :
input.autocomplete({
source: function(request, response) {
return $.ajax({
type: "GET",
url: "/some/url",
dataType: "json"
});
},
change: function(event, ui) {
if (!ui.item) {
// user didn't select an option, but what they typed may still match
var enteredString = this.value;
var stringMatch = false;
//make sure ajax is complete
this.source().done(function(data) {
var opts = $.map(data, function(item) {
return {
label: item.label,
value: item.value
}
});
for (var i = 0; i < opts.length; i++) {
if (opts[i].label.toLowerCase() == enteredString.toLowerCase()) {
$(this).val(opts[i].label); // corrects any incorrect case
stringMatch = true;
}
}
});
}
}
});​
By default, JavaScript is asynchronous whenever it encounters an async function, it queued that function for later.
But if you want a pause js(ajax call or anything) for you can do it use promises
Case 1: output hello(will not wait for setTimeout)
https://jsfiddle.net/shashankgpt270/h0vr53qy/
//async
function myFunction() {
let result1='hello'
//promise =new Promise((resolve,reject)=>{
setTimeout(function(){
resolve("done");
result1="done1";
}, 3000);
//});
//result = await promise
alert(result1);
}
myFunction();
case 2: output done1(will wait for setTimeout)
https://jsfiddle.net/shashankgpt270/1o79fudt/
async function myFunction() {
let result1='hello'
promise =new Promise((resolve,reject)=>{
setTimeout(function(){
resolve("done");
result1="done1";
}, 3000);
});
result = await promise
alert(result1);
}
myFunction();

How do I emit to an eventListener from inside a nested function in Node.js (javascript scoping issue)

I am writing code below that parses a sites API one at a time, than tells an event queue it is ready for the next object to parse. I am having issues since I am still new to javascript scoping, and would like to emit from SiteParser or call the emitForNext function. I cannot seem to bring emitForNext into scope in the error callback.
function SiteParser(){
this.emitForNext = function (message) {
this.emit("next", message);
};
this.pullJSON = function (path, processJSON) { //processJSON is a callback function
var options = {
host: 'www.site.com',
port: 80,
path: path
}
//console.log("... processing "+path);
//pulls the entire json request via chunks
http.get(options, function (res) {
var resJSON = ''; //stores the comment JSON stream given in the res
res.on('data', function (chunk) {
resJSON+=chunk;
});
res.on('end', function () {
var obJSON = (JSON.parse(resJSON));
if (obJSON.hasOwnProperty("error")){
console.log(obJSON);
console.log('... ', path, ' does not exist');
//
//NEED A NEXT EVENT EMMITER HERE NEED TO FIGURE OUT SCOPE
//
//
} else {
processJSON(obJSON); //call the callback function
}
}) ;
}).on('error', function (e) {
emitForNext("got error: " + e.message);
});
};
}
JavaScript has function scoping, if you declare a variable with the var keyword, it will be local to the current function. When you access a variable, it will look to the scope chain which consist of the current function, it's parent function, …. Try:
function one() {
var foo = 'foo';
function two() {
console.log(foo) // undefined. I'll explain this
var foo = 'bar';
console.log(foo) // bar
}
two()
console.log(foo) // foo
}
one()
Most of the time we define variables at the beginning of functions, because a variable defined in function's body get hoisted. Basically, it means that it's available in the whole function, even before it's defined but in this case it's value is undefined.
For example if a variable is not defined we normally get a ReferenceError, but in the snippet below, both console.log() just print undefined.
function foo() {
console.log(bar);
if (0) {
var bar = 'bar';
}
console.log(bar);
}
So, a common practice is that, when you write long functions, you map this to self.
function SiteParser() {
var self = this;
// ...
.error('error', function(err) {
self.emitForNext("got " + err.message);
})
}
You should not write all your methods in the constructor, it's only usefull sometimes when we want privacy, but in this case you'd better use prototypes.
Putting this together, I would write:
var SiteParser = function() {};
SiteParser.prototype.emitForNext = function(message) {
this.emit("next", message);
};
SiteParser.prototype.pullJSON = function(path, processJSON) {
var self = this,
options = {
host: 'www.site.com',
port: 80,
path: path
};
http.get(options, function(res) {
// ...
}).on('error', function (e) {
self.emitForNext("got error: " + e.message);
});
};
To be able to access emitForNext, you need to call self.emitForNext, where self points to your instance of SiteParser.
Like so:
function SiteParser(){
this.emitForNext = function (message) {
this.emit("next", message);
};
this.pullJSON = function (path, processJSON) { //processJSON is a callback function
var options = {
host: 'www.site.com',
port: 80,
path: path
};
var self = this;
//console.log("... processing "+path);
//pulls the entire json request via chunks
http.get(options, function (res) {
var resJSON = ''; //stores the comment JSON stream given in the res
res.on('data', function (chunk) {
resJSON+=chunk;
});
res.on('end', function () {
var obJSON = (JSON.parse(resJSON));
if (obJSON.hasOwnProperty("error")){
console.log(obJSON);
console.log('... ', path, ' does not exist');
self.emitForNext(path + ' does not exist');
} else {
self.emitForNext('Successfully parsed the response');
processJSON(obJSON); //call the callback function
}
}) ;
}).on('error', function (e) {
self.emitForNext("got error: " + e.message);
});
};
}
However, it looks like you'd rather manage what you'll do next (like parsing the next object) in you callback, ie. in the body of processJSON.
You need to store link to 'this'' object in SiteParser local scope.
function SiteParser () {
var that = this; // store link to 'this' in local scope
this.emitForNext = function (message) {
this.emit("next", message);
};
this.pullJSON = function (path, processJSON) { //processJSON is a callback function
var options = {
host: 'www.site.com',
port: 80,
path: path
}
//console.log("... processing "+path);
//pulls the entire json request via chunks
http.get(options, function (res) {
var resJSON = ''; //stores the comment JSON stream given in the res
res.on('data', function (chunk) {
resJSON+=chunk;
});
res.on('end', function () {
var obJSON = (JSON.parse(resJSON));
if (obJSON.hasOwnProperty("error")){
console.log(obJSON);
console.log('... ', path, ' does not exist');
that.emitForNext();
} else {
processJSON(obJSON); //call the callback function
}
}) ;
}).on('error', function (e) {
that.emitForNext("got error: " + e.message);
});
};
}

Resources