5

From post: How to ng-click an A directive in a PhantomJS test I understand I need to create my own function to click an element, but how do I use it?

The following code gives me error TypeError: 'undefined' is not a function (evaluating 'click(obj)')

var page = require('webpage').create();
var url = 'http://somesite.com/document.html';

page.open(url, function(status) {
    page.evaluate(function() {
        var obj = document.querySelectorAll('button')[0];
        click(obj);
    });
    console.log(page.content);
    phantom.exit();
});


function click(el){
    var ev = document.createEvent('MouseEvent');
    ev.initMouseEvent(
        'click',
        true /* bubble */, true /* cancelable */,
        window, null,
        0, 0, 0, 0, /* coordinates */
        false, false, false, false, /* modifier keys */
        0 /*left*/, null
    );
    el.dispatchEvent(ev);
}
Community
  • 1
  • 1
zoltar
  • 706
  • 2
  • 7
  • 20

3 Answers3

5

PhantomJS has two context. Only the page context, accessed through page.evaluate(), has access to the DOM and can trigger synthetic events. Since your click() function uses document, it needs to be run in the page context.

page.evaluate() is sandboxed, which is why you can't simply use variables that are defined outside. You either need to define them in the page context or you need to pass them in in a complicated manner (because only primitive objects can be pass into and out of the page context and functions are not primitive objects).

page.open(url, function(status) {
    page.evaluate(function() {
        if (typeof window.click !== "function") {
            window.click = function(el){
                var ev = document.createEvent('MouseEvent');
                ev.initMouseEvent(
                    'click',
                    true /* bubble */, true /* cancelable */,
                    window, null,
                    0, 0, 0, 0, /* coordinates */
                    false, false, false, false, /* modifier keys */
                    0 /*left*/, null
                );
                el.dispatchEvent(ev);
            }
        }
        var obj = document.querySelectorAll('button')[0];
        click(obj);
    });
    console.log(page.content);
    phantom.exit();
});

References:

Community
  • 1
  • 1
Artjom B.
  • 61,146
  • 24
  • 125
  • 222
  • This is useful, and I no longer get the TypeError message, however it does not solve the issue, i.e. it does not result in a clicking of the button. I'm wondering if there is some sort of javascript click prevention going on with the page I'm trying to click, is that a thing? – zoltar Oct 22 '15 at 21:18
  • 1
    @zoltar Clicking is always tricky in PhantomJS. Have you gone through the solutions in the question I linked? Particularly, [this answer](http://stackoverflow.com/a/24026636/1816580) works almost always. – Artjom B. Oct 22 '15 at 22:01
  • Thanks Artjom, that is the solution that works for me. – zoltar Oct 28 '15 at 14:36
1

I figured out the problem. The click was being circumvented by the site's javascript. Luckily PhantomJS has a sendEvent function that sends the event the same as a real user would:

var rect = page.evaluate(function() {
    return $('a.whatever')[0].getBoundingClientRect();
});
page.sendEvent('click', rect.left + rect.width / 2, rect.top + rect.height / 2);

Found above solution via PhantomJS; click an element

Community
  • 1
  • 1
zoltar
  • 706
  • 2
  • 7
  • 20
  • It's better not to duplicate content. If the solution worked for you, then it's best to confirm the duplicate. – Artjom B. Oct 28 '15 at 14:44
0
    page.evaluate(function () {
        document.getElementById("login").click();
    });

does work... Not what you mean?

user1515791
  • 675
  • 4
  • 20