Search code examples
javascriptjqueryphantomjsbrowser-automationnightmare

Nightmarejs .click() on each element with delay between


I am trying to make simple follow script with Nightmarejs. It should work in next way:

  1. Go to some user profile
  2. Click on button to open list of followers of that user
  3. Click all follow buttons with delay between each click
  4. Click load more
  5. Repeat step 3. and 4. few times

What I have so far is this, and it works with no errors, but it clicks only on first follow button and that is end:

var Nightmare = require('nightmare');
var nightmare = Nightmare({ show: true })

nightmare
.goto('http://example.com/')
.click('.buttonOpenModal')
.wait(4000)
.click('.buttonFollow')
  .end()
  .then(function (result) {
    console.log(result)
  })
  .catch(function (error) {
    console.error('Search failed:', error);
  });

I tried to loop clicking on follow buttons like this but it gives me error $ is not defined

var Nightmare = require('nightmare');
var nightmare = Nightmare({ show: true })

nightmare
.goto('http://example.com/')
.click('.buttonOpenModal')
.wait(4000)
.evaluate(function(){
    $('.buttonFollow').each(function() {
      $(this).click();
    });
  })
  .end()
  .then(function (result) {
    console.log(result)
  })
  .catch(function (error) {
    console.error('Search failed:', error);
  });

I believe that for someone who is experienced in Nightmarejs this will be simple task, but I just started with it and been struggling with it for 2 days now.

I would really appreciate any help.


Solution

  • You get $ is not defined because this syntax is part of jQuery, when you write NightmareJS script it uses pure javascript.

    You can load jquery library (before evaluateing) thanks to function .inject("js", "https://code.jquery.com/jquery-3.1.0.min.js")

    We need a synchronous sleep, else NightmareJS may end the function ̀evaluate before it finishes. (I found the code for sleep on this thread: https://stackoverflow.com/a/17532524/6479780) If you want to try asynchronous sleep, you have to use setTimeout(callback, millis) Here is what I would do, using pure javascript :

    var Nightmare = require('nightmare');
    var nightmare = Nightmare({ show: true })
    
    nightmare
    .goto('http://example.com/')
    .click('.buttonOpenModal')
    .wait(4000)
    .evaluate(function(){
        function sleep(ms) {
         var start = new Date().getTime(), expire = start + ms;
         while (new Date().getTime() < expire) { }
         return;
        }
    
        var list = document.querySelectorAll('.buttonFollow');
        list.forEach(function(elt){
           elt.click();
           //We need synchronous sleep here
           sleep(2000); //Wait 2 seconds
        });
      })
    .end()
    .then(function (result) {
        console.log(result)
    })
    .catch(function (error) {
        console.error('Search failed:', error);
    });