Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

assertEval throws "TypeError: 'null' is not an object" #133

Closed
benbuckman opened this Issue · 12 comments

2 participants

Ben Buckman Nicolas Perriault
Ben Buckman

I'm running a test with many assert and evaluate calls that run correctly, but at some point it breaks:

casper.then(function(){
  this.test.assertEval(function(){
    return true;
  }, 'testing assertEval');

  this.test.assert(function(){
    return this.evaluate(function(){ return true; });
  }, 'testing assert with evaluate');
});

These both throw an error:

FAIL TypeError: 'null' is not an object
type: uncaughtError
error: "TypeError: 'null' is not an object"
TypeError: 'null' is not an object

... :678 in injectClientUtils
... :444 in evaluate
... :180 in assertEval

Looking in Casper.prototype.injectClientUtils in casper.js, it's running this.page.evaluate, but in the assertion where it fails, this.page is null.

Have you seen this one before?

Ben Buckman

Adding in some logging -

    this.assertEval = this.assertEvaluate = function assertEval(fn, message, params) {
        console.log('in assertEval, page is', typeof this.page, typeof casper.page, typeof this.evaluate, typeof casper.evaluate);
        ...

It then outputs (before crashing),

in assertEval, page is undefined object undefined function

An evaluate right before the exception-causing assertion works fine. Very strange.

Nicolas Perriault
Owner

Hmm. This is the correct way of testing:

// file: test.js
casper.start();

casper.then(function(){
    this.test.assertEval(function(){
        return true;
    }, 'testing assertEval');

    this.test.assert(this.evaluate(function() {
        return true;
    }), 'testing assert with evaluate');
});

casper.run(function() {
    this.test.done();
});

Running:

$ casperjs test test.js 
Test file: test.js                                                                 
PASS testing assertEval
PASS testing assert with evaluate
PASS 2 tests executed, 2 passed, 0 failed.                                      

It's working side by my side using latest master. Can you confirm it was a mistake by your side? And if so, please close the issue :)

Nicolas Perriault
Owner

As a side note, please make sure the start() method is called before calling assertion methods.

Ben Buckman

Thanks. I'm running an "extended" casper object as instructed here: http://casperjs.org/#extending

I was redefining casper as casper again; in this example I've reduced it to the simplest case where it breaks. I'm now extending casper to ghost (running out of ghost names here :)) --

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

// now extend casper to ghost
// FROM HERE ON USE ghost INSTEAD OF casper
var ghost = Object.create(casper);

ghost.start();  

ghost.then(function(){
  this.test.assertEval(function(){
    return true;
  }, 'testing assertEval');

  this.test.assert(this.evaluate(function() {
    return true;
  }), 'testing assert with evaluate');
});

ghost.run(function() {
  this.test.done();
});

And it fails (first 3 lines I added to debug):

in assertEval, page is undefined object undefined function
in evaluate, page is null! [object Object]
in injectClientUtils, page is null! [object Object]
FAIL TypeError: 'null' is not an object
type: uncaughtError
error: "TypeError: 'null' is not an object"
TypeError: 'null' is not an object

...:454 in evaluate
...:181 in assertEval

Any ideas? I'd like to be able to add custom methods to the casper object, is there a better way to do it?

Ben Buckman

It looks like if I simply comment out the line,

casper = Object.create(casper);
(or)
ghost = Object.create(casper);

and stick with the casper object, i can add methods as before and it works fine.

So the bug has something to do with the Extending mechanism described in the documentation.

Nicolas Perriault n1k0 was assigned
Nicolas Perriault
Owner

I confirm the issue. I have to idea why the prototype is not ported to the new instance… I'll be investigating.

Nicolas Perriault
Owner

For some reason — and I'm suspecting it's related to the way native PhantomJS' WebPage prototype behaves — this is the way to do:

var casper = require('casper').create();
casper.start(); // note we're starting the `casper` instance, not the `ghost` one

var ghost = Object.create(casper);

ghost.thenOpen('http://google.fr/', function onStart() {
    this.test.assertEval(function() {
        return true;
    }, 'testing assertEval');

    this.test.assert(this.evaluate(function() {
        return true;
    }), 'testing assert with evaluate');
});

ghost.run();

I've no really idea how to fix this, I don't even know if this should be considered as a casperjs bug…

Ben Buckman

Thanks for looking into it.
Is it actually necessary to have the Object.create(casper) extension syntax? Adding methods directly to casper seems to work just as well.

Nicolas Perriault
Owner

It's just matter of having a clone instance rather than a reference to the original object… you're most likely not needing it 90% of time I guess.

Adding methods to an original casper instance works indeed perfectly.

Nicolas Perriault
Owner

As a side note, since I wrote this part of the documentation, I've ported the inherits() method of nodejs into the utils module, so you could also use it to create new Casper derived classes:

var Casper = require('casper').Casper;
var utils = require('utils');

function Ghost(options) {
    Casper.call(this, options);
}
utils.inherits(Ghost, Casper);

var ghost = new Ghost({
    verbose: true,
    logLevel: "debug"
});

ghost.start();

ghost.then(function() {
    this.test.assert(true, 'testing assert');
});

ghost.run(function() {
    this.test.renderResults(true);
});

I'll update the documentation in order to promote this approach — and the monkey-patching one.

Nicolas Perriault n1k0 closed this in bebe38d
Nicolas Perriault
Owner

The extending section is now up to date : http://casperjs.org/extending.html (force refresh the page as github applies client-side caching)

Ben Buckman

Nice! Thanks for maintaining this so actively.

Hubert Pan hubpan referenced this issue from a commit in hubpan/casperjs
Ivan De Marino detro Adding "window.phantomCallback()" within the page context.
The callback is harmless: if the user registers a "page.onCallback = [Function]",
that will receive any JS type passed via "phantomCallback()".
Also, if the handler for ".onCallback" returns a value, that is passed back as a
return value of "phantomCallback()".

Also, added "page.onConfirm" and "page.onPrompt".
This solves [Issue #133](http://code.google.com/p/phantomjs/issues/detail?id=133).
caf1365
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.