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

Cannot get DOM elements from evaluate()? #567

Closed
waxlamp opened this issue Apr 13, 2016 · 2 comments
Closed

Cannot get DOM elements from evaluate()? #567

waxlamp opened this issue Apr 13, 2016 · 2 comments

Comments

@waxlamp
Copy link

waxlamp commented Apr 13, 2016

I love using Nightmare so far, thanks for creating it 🎉

Here's a short script that illustrates my questions:

var Nightmare = require('nightmare');
var n = Nightmare();
var logo, height;

Promise.resolve()
.then(function () { 
  return n.goto('http:https://google.com')
    .wait('#hplogo')
    .evaluate(function () {
      return document.getElementById('hplogo');
    });
})
.then(function (_logo) {
  logo = _logo;

  return n.evaluate(function () {
    return document.getElementById('hplogo').height;
  });
})  
.then(function (_height) {
  height = _height

  n.end();
})
.then(function () {
  console.log(logo);    // <-- prints out "undefined" (expected to see a DOM element)
  console.log(height);  // <-- prints out "92" (as expected)

  console.log(logo);    // <-- prints out "{ __jsaction: {} }" (???)

  process.exit();
});
  1. From this it looks like I can't just return a DOM element from the page context? If that's the case, can you explain to my why? Does it have to do with the magic of distinguishing the script's runtime from that of the page?
  2. What is that weird object with the __jsaction property?
  3. (Somewhat unrelated question; if I don't call process.exit() in the final callback, the script just hangs. Can you explain why?)

Thanks!

@rosshinkley
Copy link
Contributor

From this it looks like I can't just return a DOM element from the page context? If that's the case, can you explain to my why? Does it have to do with the magic of distinguishing the script's runtime from that of the page?

.evaluate() executes in the page context, and I believe the return value is stripped down to primitives for transport over an inter-process channel. If you need properties from the element, you'd be better off returning the property or returning a projection. For example (snipped for brevity):

    .evaluate(function () {
      var element =  document.getElementById('hplogo');
      return {
        src: element.src,
        height: element.height
      }
    });

It really depends on what you're trying to accomplish, though. Why do you need the DOM element in the calling process?

What is that weird object with the __jsaction property?

That's a good question. Judging from the minified JS on google, it looks like it might be a container for attaching custom actions to the image (like a Doodle, for example) directly added to the DOM element. That's a wild guess, though.

Somewhat unrelated question; if I don't call process.exit() in the final callback, the script just hangs. Can you explain why?

The .end() call is queued but not run. Try changing:

.then(function (_height) {
  height = _height

  n.end();
})

to:

.then(function (_height) {
  height = _height

  return n.end();
})

... and I think you'll have better luck. Returning the Nightmare thenable ensures the chain is executed. It also might interest you to go read #546's thread on .end().

@waxlamp
Copy link
Author

waxlamp commented Apr 13, 2016

Thank you for getting back to me so quickly!

On Wed, Apr 13, 2016 at 12:33 PM Ross Hinkley [email protected]
wrote:

From this it looks like I can't just return a DOM element from the page
context? If that's the case, can you explain to my why? Does it have to do
with the magic of distinguishing the script's runtime from that of the page?

.evaluate() executes in the page context, and I believe the return value
is stripped down to primitives for transport over an inter-process channel.
If you need properties from the element, you'd be better off returning the
property or returning a projection. For example (snipped for brevity):

.evaluate(function () {
  var element =  document.getElementById('hplogo');
  return {
    src: element.src,
    height: element.height
  }
});

This makes sense, and confirms my vague intuition of what was happening,
thanks.

It really depends on what you're trying to accomplish, though. Why do you
need the DOM element in the calling process?

I don't really, I was just poking around to see what is possible. I just
expected the DOM element to come back out with no problem, and wondered why
it wouldn't (or whether it was supposed to, and I had done something wrong,
etc.).

Computing a projection stored and returned in a plain JavaScript object
will be my new SOP.

What is that weird object with the __jsaction property?

That's a good question. Judging from the minified JS on google, it looks
like it might be a container for attaching custom actions to the image
(like a Doodle, for example) directly added to the DOM element. That's a
wild guess, though.

I think you're right. Googling for __jsaction links to some sort of event
handling magic library and I assume that's what this is. I had really just
been curious if it was coming from Nightmare somehow (good to know it's
not).

Somewhat unrelated question; if I don't call process.exit() in the final
callback, the script just hangs. Can you explain why?

The .end() call is queued but not run. Try changing:

.then(function (_height) {
height = _height

n.end();
})

to:

.then(function (_height) {
height = _height

return n.end();
})

... and I think you'll have better luck. Returning the Nightmare thenable
ensures the chain is executed.

I had to change them to return n.end().then() but that did the trick.
It feels weird to call then() without a callback argument but... seems
to work.

Any reason I should avoid doing it that way?

It also might interest you to go read #546
#546 thread on .end().

Ah, thanks.

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

No branches or pull requests

2 participants