Lets say I have an array of urls. I dont want to use thenOpen function . Since it waits for every previous url to be loaded and it decreases load time .
casper.each(hrefs,function(self,href){
self.thenOpen(href,function(){ });
self.then(function(){
// Selectors
});
});
What methods would u use to spend much less compared to above method ? Would it be efficient to create multiple instances store in the db and then fetch ... but this is alot of headache . And also would like u also to answer in general would I have problems when I run multiple instances of the same js file simultaneously ?
If you don't care about synchronizing behavior between all the URLs that you are opening, then you should start multiple instances of casper for each URL. Here is an example:
var casperActions = {
href1: function (casper) {
casper.start(address, function() {...});
// tests and what not for href1
casper.run(function() {...});
},
href2: function (casper) {
casper.start(address, function() {...});
// tests and what not for href2
casper.run(function() {...});
},
...
};
['href1', 'href2', ...].each(function(href) {
var casper1 = require('casper').create();
casperActions[href](casper);
});
Each instance would run independently of each other, but it would allow you to hit many URLs simultaneously.
If you want to wait for each operation being finished to sequence an array of steps, look at this sample shipping with casper: https://github.com/n1k0/casperjs/blob/1.0/samples/multirun.js
Related
I'm working on some Jasmine end-to-end testing, using Protractor test runner. The application I am testing is a simple webpage. I already have a test scenario that works fine.
Now I'd like to improve my code so that I can use the same script to run the testing scenario twice.
The first time: the test would be performed on the English version of the page
The second time: on a translated version of the same page.
Here is my code:
var RandomSentenceInThePage = ["Sentence in English", "Phrase en Francais"];
var i;
var signInButton;
var TranslationButton;
var RandomSentenceInThePageBis;
i = 0;
//Runs the testing scenario twice
while (i < 2) {
describe('TC1 - The registration Page', function() {
//the translation is done on the second iteration
if (i != 0) {
beforeEach(function() {
browser.ignoreSynchronization = true;
browser.get('https://Mywebsite.url.us/');
//we get the translation button then click on it
TranslationButton = element(by.css('.TranslationButtonClass'));
TranslationButton.click();
});
}
//On the first iteration, we run the test on the not translated pageā¦
Else {
beforeEach(function() {
browser.ignoreSynchronization = true; //Necessary for the browser.get() method to work inside the it statements.
browser.get('https://Mywebsite.url.us/');
});
}
it('should display the log in page', function() {
//Accessing the browser is done in the before each section
signInButton = element(by.css('.SignInButtonClass'));
signInButton.click();
RandomSentenceInThePageBis = element(by.css('.mt-4.text-center.signin-header')).getText();
/*******************[HERE IS WHERE THE PROBLEM IS]*******************/
expect(RandomSentenceInThePageBis.getText()).toEqual(RandomSentenceInThePage[i]);
});
/*******************************************************************/
});
}
I have highlighted the problematic section. The code keeps running even before the comparison between RandomSentenceInThePage[i] and RandomSentenceInThePageBis are compared. And when they are finally compared, the loop is already done.
According to what I have seen on the other related topics, because of the use of expect statements and getText() methods, I am dealing with promises and I have to wait for them to be resolved. After trying for the whole day, I think I could use a hint on how to deal with this promise resolution. Let me know if you need more information.
Change while loop to for loop and declare the variable: i by let, rather than var
let can declare variable at code block scope like for, if block etc. But var can't.
Because protractor api execute async, thus when the expect()... execute for the second time. the value of i has become 2, not 1
for(let i=0;i<2;i++) {
describe('TC1 - The registration Page', function() {
....
})
}
Let's assume I have a service function that returns me the current location. And the function has callbacks to return the location. We can easily mock the function like as follows. But I wanted to introduce some delay (let's say 1 sec) before the callFake() invokes the successHandler(location).
Is there a way to achieve that?
xxxSpec.js
spyOn(LocationService, 'getLocation').and.callFake(function(successHandler, errorHandler) {
//TODO: introduce some delay here
const location = {...};
successHandler(location);
}
LocationService.js
function getLocation(successCallback, errorCallback) {
let location = {...};
successCallback(location);
}
Introducing delay in Javascript is easily done with the setTimeout API, details here. You haven't specified if you are using a framework such as Angular, so your code may differ slightly from what I have below.
It does not appear that you are using Observables or Promises for easier handling of asynchronous code. Jasmine 2 does have the 'done' callback that can be useful for this. Something like this could work:
it( "my test", function(done) {
let successHandler = jasmine.createSpy();
spyOn(LocationService, 'getLocation').and.callFake(function(successHandler, errorHandler) {
setTimeout(function() {
const location = {...};
successHandler(location);
}, 1000); // wait for 1 second
})
// Now invoke the function under test
functionUnderTest(/* location data */);
// To test we have to wait until it's completed before expecting...
setTimeout(function(){
// check what you want to check in the test ...
expect(successHandler).toHaveBeenCalled();
// Let Jasmine know the test is done.
done();
}, 1500); // wait for longer than one second to test results
});
However, it is not clear to me why adding the timeouts would be valuable to your testing. :)
I hope this helps.
I want to make a stack of Ajax calls in this way: call(n) starts after call(n-1) finished...
I cannot use async:false for many reasons:
some requests maybe jsonp (the most relevant)
I have other ajax requests that may work meanwhile..
The browser got blocked
I cannot chain my requests this way:
$.post('server.php', {param:'param1'}, function(data){
//process data
$.post('server.php', {param:'param2'}, function(data){
//process data
});
});
Because the number and params of the requests are dynamically created from user input.
A small example that illustrates my problem.
You will see that the server response order is random, what I want to achieve is to have it in order
Response to arg1
Response to arg2
Response to arg3
Response to arg4
Response to arg5
Response to arg6
Any help would be very appreciated, thanks.
Ok, jQuery Ajax returns a Deferred Object, this can help you achieve this.
Here is how to do it:
var args = ['arg1','arg2','arg3','arg4','arg5','arg6'];
deferredPost(0, 5);
function deferredPost(index, max){
var delay = Math.random()*3;
if (index<max){
return $.post('/echo/html/', {html:('Response to '+args[index]), delay:delay},
function(data){
$('#response').append(data+'<br>');
}).then(function(){
deferredPost(index+1, max);
});
} else {
return $.post('/echo/html/', {html:('Response to '+args[index]), delay:delay},
function(data){
$('#response').append(data+'<br>');
});
}
}
DEMO
Here I used then function.
I also recommend to read a little bit more about deferred objects, they can solve a couple of common problems.
This is a job for a queue.
var queue = ['arg1','arg2','arg3','arg4','arg5','arg6'];
function runQueueInOrder() {
if (queue.length === 0) { return; }
var arg = queue.pop();
var delay = Math.random()*3;
$.post('/echo/html/', {html:('Response to '+ arg), delay:delay},
function(data){
$('#response').append(data+'<br>');
}).then(function() {
runQueueInOrder();
});
}
runQueueInOrder();
You don't need to use jQuery's then for this to work if you've encapsulated the processing of the queue in a function. It's handy though. The code is destructive as it removes elements from the original array (but as they are processed, it's usually OK).
The method runQueueInOrder is called to initiate processing.
When there is no more work to be done, the function simply exits. (I've written a version that polls on a timer before, but that's not needed here).
The function grabs the next work arg, calls your post call syntax, and when done uses jQuery's deferred then callback to call the function again (to process the queue further if needed).
(I looked at the other answer and found it confusing to follow, so I took a simpler approach. Using my simple version, you can add new items as new work is discovered--or remove them.).
I need to search the CouchDB based on several criteria entered in a form. Name, an array of Tags and so on. I would then need various views to index on these fields. Ultimately, all the results will be collated in data.js and provided to mustache.html. Say there are 3 views - docsByName, docsByTags, docsById.
What I don't know is, how to query all these views in query.js. Can this be done and how ?
Or should the approach be of that to write one view that makes multiple emits for each search somehow ?
Thank you.
From what you say I assume you are using Evently, so I will quote from Evently primer:
The async function is the main star, which in this case makes an Ajax request (but it can do anything it wants). Another important thing to note is that the first argument to the async function is a callback which you use to tell Evently when you are done with your asynchronous action. [...] Whatever you pass to the callback function then becomes the first item passed to the data function.
In short: put your Ajax requests in async.js.
As a side note: Evently is only one of the possible choices to write a couchapp and it is not clear if it is maintained. However it works and it is easy to rearrange the code to not use it.
EDIT: here is a sample async function (cut&paste from an old program):
function(cb, e) {
var app = $$(this).app
;
app.db.openDoc('SOMEDOCID', {
error: function(code, error, reason) {
alert("Error("+code+" "+error+"): "+reason);
}
, success: function(doc) {
app.view('SOMEVIEWNAME', {
include_docs: true
, error: function(code, error, reason) {
alert("Error("+code+" "+error+"): "+reason);
}
, success: function(resp) {
resp.doc = doc;
cb(resp);
}
});
}
});
}
I've build a livesearch with the jQuery.ajax() method. On every keyup events it receives new result data from the server.
The problem is, when I'm typing very fast, e.g. "foobar" and the GET request of "fooba" requires more time than the "foobar" request, the results of "fooba" are shown.
To handle this with the timeout parameter is impossible, I think.
Has anyone an idea how to solve this?
You can store and .abort() the last request when starting a new one, like this:
var curSearch;
$("#myInput").keyup(function() {
if(curSearch) curSearch.abort(); //cancel previous search
curSearch = $.ajax({ ...ajax options... }); //start a new one, save a reference
});
The $.ajax() method returns the XmlHttpRequest object, so just hang onto it, and when you start the next search, abort the previous one.
Assign a unique, incrementing ID to each request, and only show them in incrementing order. Something like this:
var counter = 0, lastCounter = 0;
function doAjax() {
++counter;
jQuery.ajax(url, function (result) {
if (counter < lastCounter)
return;
lastCounter = counter;
processResult(result);
});
}
You should only start the search when the user hasn't typed anything for a while (500ms or so). This would prevent the problem you're having.
An excellent jQuery plugin which does just that is delayedObserver:
http://code.google.com/p/jquery-utils/wiki/DelayedObserver
Make it so each cancels the last. That might be too much cancellation, but when typing slows, it will trigger.
That seems like an intense amount of traffic to send an ajax request for every KeyUp event. You should wait for the user to stop typing - presumably that they are done, for at least a few 100 milliseconds.
What I would do is this:
var ajaxTimeout;
function doAjax() {
//Your actual ajax request code
}
function keyUpHandler() {
if (ajaxTimeout !== undefined)
clearTimeout(ajaxTimeout);
ajaxTimeout = setTimeout(doAjax, 200);
}
You may have to play with the actual timeout time, but this way works very well and does not require any other plugins.
Edit:
If you need to pass in parameters, create an inline function (closure).
...
var fun = function() { doAjax(params...) };
ajaxTimeout = setTimeout(fun, 200);
You will want some kind of an ajax queue such as:
http://plugins.jquery.com/project/ajaxqueue
or http://www.protofunc.com/scripts/jquery/ajaxManager/
EDIT:Another option, study the Autocomplete plug-in code and emulate that.(there are several Autocomplete as well as the one in jquery UI
OR just implement the Autocomplete if that serves your needs