Issue with npm require

110 Views Asked by At

I'm running a Nightmare.js script, and within it I'm trying to require lodash (installed locally with npm, in node_modules, registered in package.json).

index.js :

var Nightmare = require('nightmare');
var _ = require('lodash');

function getRandomInt(min, max) {
  min = Math.ceil(min);
  max = Math.floor(max);
  return Math.floor(Math.random() * (max - min)) + min;
}

function getElms(elm) {
    var elsm =  document.querySelectorAll(elm);
    return _.map(elsm, function(elem){ return elem.innerHTML; });
} 

var someWebsite = new Nightmare({ show: false })
  .goto( ***some url*** )
  .wait(getRandomInt(2500, 5000))
  .evaluate(function () {

      var elsm =  document.querySelectorAll(***some selector***);
      return _.map(elsm, function(elem){ return elem.innerHTML; });

      // return getElms(***some selector***);


  }).then(function(linkstexts) {
    console.log(linkstexts)
  });
  • but I'm getting this:

    UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): _ is not defined

    • similar issue if I uncomment and use return getElms(***some selector***);

This is package.json

{
  "name": "nightxp",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "dependencies": {
    "lodash": "^4.17.4",
    "nightmare": "^2.10.0"
  },
  "devDependencies": {},
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC"
}

enter image description here

What am I missing?

UPDATE

I tried passing the lodash to the browser scope, and completing with catch(), but somehow the lodash variable still isnt being passed to the scope (example with hackernews):

var Nightmare = require('nightmare');
var lodash = require('lodash');

function getRandomInt(min, max) {
  min = Math.ceil(min);
  max = Math.floor(max);
  return Math.floor(Math.random() * (max - min)) + min; 
}

var facebook = new Nightmare({ show: false })
  .goto('https://news.ycombinator.com')
  .wait(getRandomInt(5500, 6000))
  .evaluate(  (lodash) => {
      var elsm =  document.querySelectorAll('tr td.title a.storylink');
      return lodash.map(elsm, function(elem){ return elem.innerHTML; });
   }, lodash).then(function(titles) {
    console.log(titles)
  }).catch(function (error) {
      console.error('Error:', error);
  });

and this is what I get:

C:\Projects\nightmare>set DEBUG=nightmare & node index.js
  nightmare queuing process start +0ms
  nightmare queueing action "goto" for https://news.ycombinator.com +4ms
  nightmare queueing action "wait" +2ms
  nightmare queueing action "evaluate" +0ms
  nightmare running +1ms
Error: Cannot read property 'map' of undefined
1

There are 1 best solutions below

3
On BEST ANSWER

When you run

var someWebsite = new Nightmare({ show: false })
.evaluate(function () {
/* ... */
}

You are now in browser scope — you can think of Nightmare.evaluate as running the contained code in the context of an independent browser, which means your global scope, including _ is not available.

See here for a bit more info and some tips on passing data into the scope:

https://github.com/segmentio/nightmare/issues/89

https://github.com/segmentio/nightmare/issues/333

Edit:

While you can pass simple values into evaluate from the node context, you can't pass complex values with functions and methods. This is because the arguments are serialize in transit and this is difficult with functions. Here's an issue that explains it a bit:

https://github.com/segmentio/nightmare/issues/349

In this particular case it seems like the easiest thing to do is to work without lodash, which these days isn't hard. For example:

var facebook = new Nightmare({ show: false })
.goto('https://news.ycombinator.com')
.wait(getRandomInt(5500, 6000))
.evaluate(  () => {
    var elsm =  document.querySelectorAll('tr td.title a.storylink');
    return Array.prototype.map.call(elsm, elem => elem.innerHTML)
})
.then(function(titles) {
    console.log("title", titles)
})
.catch(function (error) {
    console.error('Error:', error);
});