rosshinkley / nightmare-examples

Examples and supplementary documentation for Nightmare
251 stars 46 forks source link

common pitfall: variable lifting with `.evaluate()` #14

Closed rosshinkley closed 8 years ago

rosshinkley commented 8 years ago

In working through adding comments for #6, I realized that the reason why variable lifting with .evaluate() isn't explicitly stated in the Nightmare documentation. Consider this, lifted directly from the co parameters example:

 var run = function * (selector) {
  var result = yield nightmare
    .goto('http://yahoo.com')
    .type('input[title="Search"]', 'github nightmare')
    .click('#uh-search-button')
    .wait('#main')
    .evaluate(function(selector) {
      return document.querySelector(selector)
        .href;
    }, selector);

  yield nightmare.end();

  return result;
};

It's not immediately clear why you can't simply have selector lifted, as in:

var run = function * (selector) {
  var result = yield nightmare
    .goto('http://yahoo.com')
    .type('input[title="Search"]', 'github nightmare')
    .click('#uh-search-button')
    .wait('#main')
    //this looks legitimate, but will cause problems
    .evaluate(function(selector) {
      return document.querySelector(selector)
        .href;
    });

  yield nightmare.end();

  return result;
};
i12n commented 8 years ago

There is another thing about .evaluate() when using strict mode:

"use strict"
let run = function *() {
    let result = yield nightmare
        .on('page', function (type, message) {
            console.log(message);
        })
        .goto('https://github.com/')
        .wait('.header-search-input')
        .type('.header-search-input', 'nightmare\r\n')
        .wait('.codesearch-results')
        .evaluate(function () {
            // without using strict mode cause a syntax error 
            let ndName = document.getElementsByClassName('repo-list-name')[0];
            return ndName.getElementsByTagName('a')[0].href;
        });
    yield nightmare.end();
    return result;
}

I think the reason may be that the contexts of .evaluate(fn) and fn is different. So the function fn should also invoke strict mode:

"use strict"
let run = function *() {
    let result = yield nightmare
        .on('page', function (type, message) {
            console.log(message);
        })
        .goto('https://github.com/')
        .wait('.header-search-input')
        .type('.header-search-input', 'nightmare\r\n')
        .wait('.codesearch-results')
        .evaluate(function () {
            "use strict"
            let ndName = document.getElementsByClassName('repo-list-name')[0];
            return ndName.getElementsByTagName('a')[0].href;
        });
    yield nightmare.end();
    return result;
}
rosshinkley commented 8 years ago

@unknownGe You're right. I'll make sure that's included.

rosshinkley commented 8 years ago

I'm going to break the stricture issue out into its own area.