NightmareJS multiple evaluations
Asked Answered
T

1

6

NightmareJS works great when I am running one evaluation, but as I interact with the page I need to do more evaluations as things pass. However using the docs I tried a simple sample of chaining evaluations and I get an error:

describe('test google search results', function() {
  this.timeout(15000);
  it('should find the nightmare github link first', function(done) {
    var nightmare = Nightmare({show: true})
    nightmare
      .goto('http://google.com')
      .wait(1000)
      .type('form[action*="/search"] [name=q]', 'github nightmare')
      .click('form[action*="/search"] [type=submit]')
      .wait(1000)//.wait('#rcnt')
      .evaluate(function () {
        return document.querySelector('div.rc h3.r a').href
      })
      .then(function(link) {
        console.log("TESTING 1");
        expect(link).to.equal('https://github.com/segmentio/nightmare');
      })
      .wait()
      .evaluate(function () {
        return document.querySelector('div.rc h3.r a').href
      })
      .end()
      .then(function(link) {
        console.log("TESTING 2");
        expect(link).to.equal('https://github.com/segmentio/nightmare');
        done();
      })
  });
});

Error:

TypeError: nightmare.goto(...).wait(...).type(...).click(...).wait(...).evaluate(...).then(...).wait is not a function

In this case I added a wait before the next evaluation in case I needed to let the system wait for a complete but still it is not working.

Trypanosome answered 27/10, 2016 at 18:53 Comment(0)
B
8

The thing is that evaluate() returns a Promise, which is a Javascript thing and not a Nightmare thing.

So a Promise has a then and catch, among others, methods, but clearly does not have a wait method.

I thing this answer and this resource can help you understand the concept a little better.

Apply the concept to your scenario, the code would look like this

describe('test google search results', function() {
  this.timeout(15000);
  it('should find the nightmare github link first', function(done) {
    var nightmare = Nightmare({show: true})

    nightmare
      .goto('http://google.com')
      .wait(1000)
      .type('form[action*="/search"] [name=q]', 'github nightmare')
      .click('form[action*="/search"] [type=submit]')
      .wait(1000)//.wait('#rcnt')
      .evaluate(function () {
        return document.querySelector('div.rc h3.r a').href
      })
      .then(function(link) {
        console.log("TESTING 1");
        expect(link).to.equal('https://github.com/segmentio/nightmare');

        nightmare.evaluate(function () {
          return document.querySelector('div.rc h3.r a').href
        })
        .end()
        .then(function(link) {
          console.log("TESTING 2");
          expect(link).to.equal('https://github.com/segmentio/nightmare');
          done();
        })

      }).catch(function(error) {
        done(new Error(error))
      })
  });
});

Notice how the second call to evaluate is inside the first then callback.

Burrows answered 27/10, 2016 at 23:16 Comment(5)
Thank you so much for your help, after testing some more I was still getting some errors until I discovered that I was loading should instead of expect from chai.Trypanosome
After looking at this in more detail it seems like it will be a mess to manage when I have to write 100 nested tests, is there a more elegant to write nested evals? I was thinking of feeding a promise but may not work if the promise has to be nested.Trypanosome
After some more testing I have come up with the following solution: #40297878 It allows me to keep the separation that I need for now.Trypanosome
Nice @HelmutGranda, I am using the exact same approach to perform several sequential tests using NightmareBurrows
Unless nightmare has changed since this was posted, I do not believe that .evaluate returns a promise. .evaluate is, like all actions, are wrapped queue methods that return the nightmarejs instance. It is in fact the .then method that returns the promise (nightmare's .then method is a wrapper that returns a promise chain). I wonder if it is possible to chain .evaluate by: .evaluate(...) .evaluate(...) .then(...)Inextirpable

© 2022 - 2024 — McMap. All rights reserved.