CasperJS bind issue
Asked Answered
S

1

11

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();
});
Simp answered 18/8, 2014 at 8:37 Comment(0)
M
20

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

Mckee answered 18/8, 2014 at 9:9 Comment(8)
Thank you so much for this answer which also works well for facebook .Mishap
You might want to update PhantomJS to version 2 and use CasperJS from the master branch on GitHub.Mckee
Oh thanks for that, will this make this solution unnecessary?Mishap
Yes, it will make it unnecessary, but as I said currently there are some hurdles, because there is currently no CasperJS release that supports PhantomJS 2.Mckee
Just want to add a few tags for google to pickup incase anyone else is searching the wrong thing (as I was) casperjs casper not rendering svg png transparent png not capturing no captureJupiter
@Jupiter That shouldn't be necessary, because over time this question was asked in different ways and they were marked as duplicate of this question.Mckee
Well I wasn't able to find any that took me to here. My issue was SVGs not rendering and transparent PNG's as background-image showing up all white. Hopefully this helps someoneJupiter
Unfortunately this will not polyfill iframe environments... just the parent windowModestine

© 2022 - 2024 — McMap. All rights reserved.