Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

CasperJS bind issue

I'm trying to reach an instagram page, but with no luck. I keep getting the error and a blank screenshot.

Error text:

TypeError: 'undefined' is not a function (evaluating 'a.createDescriptor.bind(null,t)')

Casperjs --version is 1.1.0-beta3.

Basically I use the following code:

var casper = require('casper').create({
    verbose: true,
    logLevel: 'debug',
    pageSettings: {
         userAgent: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_5) AppleWebKit/537.4 (KHTML, like Gecko) Chrome/22.0.1229.94 Safari/537.4'
    },
    loadPlugins: true
});

casper.on( 'page.error', function (msg, trace) {
    this.echo( 'Error: ' + msg, 'ERROR' );
});

casper.start('http://instagram.com/hello', function() {
    casper.wait(3000, function()  {
        this.capture('screen.png');
    });
});

casper.run(function() {
    this.exit();
});
like image 490
buzdykg Avatar asked Aug 18 '14 08:08

buzdykg


Video Answer


1 Answers

The shim below isn't needed anymore if PhantomJS 2 is used. Sadly CasperJS 1.1-beta3 doesn't support it yet, so you might want to use the master branch from GitHub.


The problem is that PhantomJS v1.x does not support the Function.prototype.bind. You need to add a shim for that. In CasperJS it goes into the page.initialized event handler. This shim works well for me on instragram:

casper.on( 'page.initialized', function(){
    this.evaluate(function(){
        var isFunction = function(o) {
          return typeof o == 'function';
        };

        var bind,
          slice = [].slice,
          proto = Function.prototype,
          featureMap;

        featureMap = {
          'function-bind': 'bind'
        };

        function has(feature) {
          var prop = featureMap[feature];
          return isFunction(proto[prop]);
        }

        // check for missing features
        if (!has('function-bind')) {
          // adapted from Mozilla Developer Network example at
          // https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/bind
          bind = function bind(obj) {
            var args = slice.call(arguments, 1),
              self = this,
              nop = function() {
              },
              bound = function() {
                return self.apply(this instanceof nop ? this : (obj || {}), args.concat(slice.call(arguments)));
              };
            nop.prototype = this.prototype || {}; // Firefox cries sometimes if prototype is undefined
            bound.prototype = new nop();
            return bound;
          };
          proto.bind = bind;
        }
    });
});

It doesn't work if the shim is exported into its own file and included through the clientScripts option, because those are appended after the instagram javascript which is too late.

What might also work is registering to page.resource.received event.

There is also the pure PhantomJS question: bind polyfill for PhantomJS

like image 187
Artjom B. Avatar answered Oct 20 '22 05:10

Artjom B.