How do I set a variable from casper.evaluate()?

2019-09-17 14:39发布

问题:

I'm trying to set a value from within casper.evaluate() that I will check later to run a test on, but it doesn't seem to be working.

isArticleOrReview = false;
casper.waitFor(function check() { //here I'm just waiting for jQuery to load
    return this.evaluate(function() {
        return jQuery.fn.jquery == '1.2.6';
    });
}, function then() { //once jQuery has been loaded, do this stuff
    this.evaluate(function() {
        isArticleOrReview =  (jQuery('body').hasClass('node-type-review') || jQuery('body').hasClass('node-type-article'));
        __utils__.echo('isArticleOrReview ' + isArticleOrReview);
    });
});
casper.then(function(){
    casper.test.info('isArticleOrReview ' + isArticleOrReview);
});

For output I get:

isArticleOrReview true
isArticleOrReview false

I want this to read:

isArticleOrReview true
isArticleOrReview true

回答1:

evaluate is sandboxed. The evaluated function has no access to the surrounding code, nor does surrounding code have access to the evaluated function. Here is a simpler example from PhantomJS (Casper's evaluate uses that underneath):

var page = require('webpage').create();
page.open('http://google.com/', function(status) {
  var titleVar = "NOT SET";

  var titleReturn = page.evaluate(function() {
    // This would result in an error:
    // console.log('Variable in evaluate:', titleVar);
    // ReferenceError: Can't find variable: titleVar

    titleVar = document.title;
    return document.title;
  });

  console.log('Return value from evaluate:', titleReturn);
  console.log('Variable post evaluate:', titleVar);
  phantom.exit();
});

As you found out, this will print

Return value from evaluate: Google
Variable post evaluate: NOT SET

and if you uncomment the console.log line inside evaluate, you will see evaluate crash and burn, since the variable does not exist.

Thus, you can only pass values through evaluate parameters and return values (and only those that are JSON-serialisable):

isArticleOrReview = this.evaluate(function() {
  return (jQuery('body').hasClass('node-type-review') || jQuery('body').hasClass('node-type-article'));
});