Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PhantomJS cannot click on existing elements

I use PhantomJS 1.9.7 on windows 8.1 and I am going to click on Login button after typing username and password. I can write username and password but, when I want PhantomJS to click on the button, It can find the element but is not able of clicking on that. I found in previous posts that I need to create event and use "dispatchEvent". I did that but I got an error as follows:

TypeError: 'undefined' is not a function (evaluating 'elm.dispatchEvent(event)')

I also tried to get help from EventListener but I got the same error for that.

How can I click on an element?

var page = require('webpage').create();

page.open('URL', function() {
    var submitButton = enterUserAndPassAndLogin();      
    click(submitButton);
    phantom.exit();
});

function enterUserAndPassAndLogin() {
    var element = page.evaluate(function()  {
        document.querySelector('input[name="username"]').value = "*******";
        document.querySelector('input[name="password"]').value = "*******";
        return document.getElementsByTagName("Button");
    });
    return element;
}

function click(elm) {
    var event = document.createEvent("MouseEvent");
    event.initMouseEvent("click", true, true, window,
        0, 0, 0, 0, 0, false, false, false, false, 0, null);
    elm.dispatchEvent(event);
}
like image 779
user3321210 Avatar asked Nov 23 '22 18:11

user3321210


1 Answers

There are two problems with the code. First DOM elements cannot be passed from the page context (page.evaluate) outside. Corresponding line from the docs:

Note: The arguments and the return value to the evaluate function must be a simple primitive object. The rule of thumb: if it can be serialized via JSON, then it is fine.

Closures, functions, DOM nodes, etc. will not work!

So the submitButton is [null]. Because an array is returned, the error message doesn't show the actual problem. Since the DOM element cannot be passed outside, the click must happen inside of page.evaluate.

Since page.evaluate is sandboxed the click function must be defined inside of the page context. Variables and functions from outside cannot be directly accessed.

A possible script is this:

var page = require('webpage').create();

page.open('URL', function() {
    enterUserAndPassAndLogin();
    setTimeout(function(){
        // wait a little to maybe see the click result
        phantom.exit();
    }, 1000);
});

function enterUserAndPassAndLogin() {
    page.evaluate(function()  {
        function click(elm) {
            var event = document.createEvent("MouseEvent");
            event.initMouseEvent("click", true, true, window,
                0, 0, 0, 0, 0, false, false, false, false, 0, null);
            elm.dispatchEvent(event);
        }
        document.querySelector('input[name="username"]').value = "*******";
        document.querySelector('input[name="password"]').value = "*******";
        click(document.getElementsByTagName("Button")[0]);
    });
}
like image 68
Artjom B. Avatar answered Dec 05 '22 16:12

Artjom B.