2

I'm attempting to interact with a website that is rather badly coded, and horribly slow. I'll illustrate the problem that I'm having with an example:

On this webpage are 2 select boxes, the first one is used to select a country, onchange a AJAX request is made to the webserver, which in turn returns a list of cities. This list if used to populate the second select box. Now the problem is that I can use the evaluate function in phanomtjs' page object to iterate over the first select box and select the correct option. But after that I have to wait for n seconds before the second box is populated. Currently I've 'solved' this by setting a timer to wait for 25 seconds before selecting the city from the second box. This however, is a very bad solution. First of all, 25 seconds is not long enough in all situations, so from time to time it will just timeout and fail. Second problem is that in most cases 25 seconds is way too long.

So I have to find a way to wait for the second box to get populated. At first I though I could just use setInterval inside the evaluate function, to test whether or not the select box is populated. This works, but there is a problem, since setInterval is asynchronous, using this method I lose the ability to find out whether the correct selection could be made. To illustrate what I mean, the code below is how it's working when I don't have to wait:

var retval = page.evaluate(function () {
    return selectOption('select_id',
                        info['country']);
});

That selectOption is a function that iterates over the select element until it finds the right option element, if it fails it returns false, this return value is then returned by the evaluated function so I can check if it worked.

Another option is to just do the waiting with setInterval inside the context of the webpage, and then raise and exception if it fails. I tried doing this, but I can't seem to catch the exception outside of the website scope. PhantomJS dumps the exception in the terminal, but I can't intercept it.

Is there any way around this? Or should I just use the fixed waiting time option?

Edit: I tried to use page.onError, but it doesn't seem to get used.

Blubber
  • 2,214
  • 1
  • 17
  • 26

1 Answers1

0

I also needed to find out if an exception was thrown in the evaluated function. I managed to do this by adding another layer that just wrapped the function with a try-catch:

// Wrap a function (func) inside a try-catch block and return
// the exception if any. Otherwise return null. The ctx is a
// a bucket for all the variables to be passed to func.
var tryCatchWrapper = function(func, ctx) {        
    try {
        funct(ctx);
    }
    catch(e) {
        return e;
    }

    return null;
}

Then to evaluate somefunction I use it like that:

var error = page.evaluate(tryCatchWrapper, somefunction);
if (error) {
    handle error...
}

If I wish to pass arguments to func then I use the context object. For a different approach on how to pass variable arguments to the function have a look at question: "JavaScript variable number of arguments to function".

Community
  • 1
  • 1
Panos Rontogiannis
  • 4,154
  • 1
  • 24
  • 29