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();
});
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