Evaluating Remote Javascript with CasperJs

I needed to retrieve evaluated Javascript object from a remote page. The code on the page looked like this:

<script language="Javascript" type="text/javascript">

        var XXXGen = function(options){
                !options && (options = {});

                this.url = '';
                this.options = options;
                ....
        };

        ...

        var gen = new XXXGen({
                trackuri: 'some.uri',
                campaignId: 000000,
                programs: [{"key":"123","value":"345"}, {.....}]
        });

I was trying to scrap this webpage and retrieve 'gen' object as it was after the Javascript gets executed, with a subsequent task to enumerate the list of all 'programs' in the object.

Using CasperJs, it should have been as simple as:

var casper = require('casper').create();

casper.start('https://some.website.com/login');

casper.thenEvaluate(function() {
        .. sign in code here ..
});

casper.thenOpen('https://some.website.com/target-page', function() {
                var x = this.getGlobal('gen.options.programs');
                this.echo(x);
});

casper.run();

However, it failed with a type error:

TypeError: JSON.stringify cannot serialize cyclic structures.

From this post on StackOverflow.com, I learned that: "In PhantomJS (and thus also CasperJS), evaluate runs in a jailed environment. Only primitive objects, something you can serialize via JSON.stringify and JSON.parse is accepted."

I struggled to find a work-around until I thought about using underlying PhantomJs API which Casperjs exposes via .page class.

Bingo! From within casper.thenOpen call, using this.page.evaluate I was able to access 'gen' object as a property of 'window' object and return it back to my casperjs code:

                var programs = this.page.evaluate(function() {
                        return window.gen.options.programs;
                });

                for(var i = 0; i < programs.length; i++) {
                        console.log(programs[i].key, programs[i].value);
                }

Neat :)