Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ES2016 Async/Await example? #18

Open
Mr0grog opened this issue Mar 9, 2016 · 7 comments
Open

ES2016 Async/Await example? #18

Mr0grog opened this issue Mar 9, 2016 · 7 comments

Comments

@Mr0grog
Copy link
Contributor

Mr0grog commented Mar 9, 2016

Maaaaaybe worth having a page on usage with async functions. While these are still just a proposal, they are being actively worked on for both Chakra Core and V8.

Starting point:

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

async function run () {
  var result = await nightmare
    //load a url
    .goto('http://yahoo.com')
    //simulate typing into an element identified by a CSS selector
    //here, Nightmare is typing into the search bar
    .type('input[title="Search"]', 'github nightmare')
    //click an element identified by a CSS selector
    //in this case, click the search button
    .click('#uh-search-button')
    //wait for an element identified by a CSS selector
    //in this case, the body of the results
    .wait('#main')
    //execute javascript on the page
    //here, the function is getting the HREF of the first search result
    .evaluate(function() {
      return document.querySelector('#main .searchCenterMiddle li a')
        .href;
    });


  //queue and end the Nightmare instance along with the Electron instance it wraps
  await nightmare.end();

  console.log(result);
};

run();

Though it would probably be a good idea to cover how to use it today with Babel, too.

@kristianmandrup
Copy link

async/await are supported natively in NodeJS since 7.6

https://www.infoq.com/news/2017/02/node-76-async-await

Should be included in examples!!!

@kwokster10
Copy link

Hi @Mr0grog, I am trying your example above for my specs. Finding that it handles requests better but at the end, I'm getting Error: Evaluation timed out after 30000msec. Are you calling done() or resolving your promises? I can see that all of my steps have been executed but the nightmare instance never ends. Am I missing something? Any help is appreciated.

@Mr0grog
Copy link
Contributor Author

Mr0grog commented Apr 12, 2018

In an async function, a promise rejection becomes a thrown exception. If the evaluate() call, which gets awaited before calling end(), throws an error (the error message you’re seeing is from evaluate), then end() will never get called. You probably need a try/catch somewhere if you want to make sure end() gets called.

@kwokster10
Copy link

Thanks for the response!

I actually have a catch:

.catch(function(error) {
      console.error('an error has occurred: ' + error);
      return error;
    });

I see that console log along with the other error complaint.

It appears to be getting stuck during the .wait and never getting to the evaluate. However, the .wait seems to work fine when using

    .then(() => {
        return nightmare.exists('div.app')
      })
      .then((exists) => {
        expect(exists).to.equal(true);
      })

Is there some trick to using .evaluate that I'm missing?

@Mr0grog
Copy link
Contributor Author

Mr0grog commented Apr 13, 2018

Is your code exactly like the example? What selector are you actually wait()ing for? Think of wait(selector) as something that calls exists(selector) over and over again until it returns true.

If you had:

await nightmare
  .something()
  .then(() => nightmare.exists('div.app'))
  .then(exists => expect(exists).to.equal(true));

Then this should by definition work with wait:

await nightmare
  .something()
  .wait('div.app');

Side note: you can use .catch() in an async function, but generally the idea is that you should use try { /* some stuff */ } catch (error) { /* handle error */ } blocks:

async function run() {
  try {
    await nightmare
      .something()
      .something()
      .something();
  }
  catch (error) {
    // handle the error however you like
  }
  finally {
    // cleanup that runs regardless of success or error
    await nightmare.end()
  }
}

@kwokster10
Copy link

kwokster10 commented Apr 13, 2018

Yep, that first example does work with wait, but wait with evaluate wouldn't. I was testing this on an app, that goes from div.login to div.dashboard.

// Does work
await nightmare
    .something()
    .wait('.dashboard')
    .then(() => nightmare.exists('div.dashboard'))
    .then(exists => expect(exists).to.equal(true));

// Doesn't work
await nightmare
    .something()
    .wait('.dashboard')
    .evaluate(() => document.querySelector('.dashboard'))
    .then(element => expect(element.length).to.equal(1));

It could be related to issue segment-boneyard/nightmare#1423.

Thanks for the side note. Totally new to using async/await.

@Mr0grog
Copy link
Contributor Author

Mr0grog commented Apr 13, 2018

I was testing this on an app, that goes from div.login to div.dashboard.

Can you try that without attempting to return an element? e.g. here:

.evaluate(() => document.querySelector('.dashboard'))

You can’t pass elements between the Electron and Node.js processes (only simple values like booleans, strings, numbers, and arrays or objects containing them). Instead, you’d want to do something like:

await nightmare
    .something()
    .wait('.dashboard')
    // Note also `querySelector()` returns a single element, not an array
    .evaluate(() => !!document.querySelector('.dashboard'))
    .then(exists => expect(exists).to.equal(true));

That said, if your problem is actually some unbelievably terrible bug like segment-boneyard/nightmare#1423 appears to be, that won’t help you :P

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants