James van Dyke James van Dyke - 1 month ago 16
Javascript Question

How do I capture JavaScript errors generated in a page fetched by PhantomJS?

I have a PhantomJS script that loads a local HTML file, injects some javascript files, then executes some javascript in the context of the page. The javascript that runs generates an exception, but I only get output from the console, which doesn't seem to distinguish between an error and a normal log and doesn't have file, line numbers or a stacktrace.

What I need is a way to capture or otherwise distinguish these errors. I have already tried:


  • Wrapping my PhantomJS script in a try-catch

    • Result: nothing is thrown far enough to be caught by this


  • Define a
    window.onerror
    function

    • Result: nothing happens. WebKit does not implement an onerror event on the window




I would prefer to be able to retrieve the error object itself so that I can retrieve the stacktrace.

Answer

I think there were issues with window.onerror not properly working in WebKit (https://bugs.webkit.org/show_bug.cgi?id=8519). Don't know if this has been fixed at all, and if so, if the QT WebKit version is already up-to-date.

However, you should be able to catch the exceptions thrown in your code. If you are using something like webPage.evaluate(...)to run your code, you cannot wrap the complete call in a try/catch block, since the script is evaluated in a different context and the errors will not appear in the main execution context. Insteadyou will need to catch the errors in page execution context. Unfortunately, there is no way of accessing any functions defined in the main context, we therefore have to explicitly write the wrapping code around your code to be executed.

The following is a modified example of the phantomwebintro.js file as included in the PhantomJS source. It loads an HTML page, inserts a script and then runs some code in the page context (here with a line throwing a type error). This code is wrapped with a try/catch block and will return the wrapped result or error object to the main context.

...

// Load an HTML page:
page.open("http://www.phantomjs.org", function(status) {
    if (status == "success") {

        // Inject some scripts:
        page.includeJs("http://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js", function() {

            // Run your own code in the loaded page context:
            var resultWrapper = page.evaluate(function() {
                var wrapper = {};
                try {
                    // Your code goes here
                    // ...

                    var x = undefined.x; // force an error

                    // store your return values in the wrapper
                    wrapper.result = 42;
                } catch(error) {
                    wrapper.error = error;
                }
                return wrapper;
            });

            // Handle the result and possible errors:
            if (resultWrapper.error) {
                var error = resultWrapper.error;
                console.log("An error occurred: " + error.message);
                // continue handling the error
                // ...
            } else {
                var result = resultWrapper.result;
                // continue using the returned result
                // ...
            }

            ...

        });
    }
});

...
Comments