Phantomjs; Click an Element

PhantomJS; click an element

.click() is not standard. You need to create an event and dispatch it:

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);
}

PhantomJS - click element

if you want to access the dom/window of the page loaded by phantomjs, you will need to wrap your click code within a page.evaluate function. It will be executed sync

So your code would look like this

console.log("click");
page.render('1.png');
page.evaluate(function(selector){
return document.getElementById(selector).click();
}, 'build');
page.render('2.png');

Cannot click element with Phantomjs

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

How to call a button's onClick() method in PhantomJS?

PhantomJS exits before the work is done.

We need to wait, after the steps is complete.

//
// Run this script like so:
//
// phantomjs --cookies-file=cookys.txt example_amazon_login.js 'myemailaddress@gmail.com' 'mypasswordshhhh'
//
// You may need to execute the script twice so that the cookys.txt file gets data written to it.
// See http://stackoverflow.com/questions/41391254/not-able-to-get-phantomjs-example-to-work
//

var steps=[];
var testindex = 0;
var loadInProgress = false;//This is set to true when a page is still loading

/*********SETTINGS*********************/
var username = 'unknown';
var password = 'unknown';
var apptitle = 'unknown';
var category = 'Music & Audio';

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

/*
page.onResourceRequested = function(request) {
console.log('Request ' + JSON.stringify(request, undefined, 4));
};
page.onResourceReceived = function(response) {
console.log('Receive ' + JSON.stringify(response, undefined, 4));
};
*/

page.onError = function(msg, trace) {

var msgStack = ['ERROR: ' + msg];

if (trace && trace.length) {
msgStack.push('TRACE:');
trace.forEach(function(t) {
msgStack.push(' -> ' + t.file + ': ' + t.line + (t.function ? ' (in function "' + t.function +'")' : ''));
});
}

console.error(msgStack.join('\n'));

};

page.settings.userAgent = 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.157 Safari/537.36';
page.settings.javascriptEnabled = true;
page.settings.loadImages = false;//Script is much faster with this field set to false
phantom.cookiesEnabled = true;
phantom.javascriptEnabled = true;
/*********SETTINGS END*****************/

/* Get command line args user password*/
var system = require('system');
var args = system.args;
var initial_url = 'https://developer.amazon.com/login.html';

if (args.length === 1) {
console.log('Try to pass some arguments when invoking this script!');
} else {
args.forEach(function(arg, i) {
console.log(i + ': ' + arg);
if ( i === 1 ) { username = arg; }
if ( i === 2 ) { password = arg; }
if ( i === 3 ) { apptitle = arg; }
});
}

if ( username == 'unknown' ) {
console.log('Please specify username and password');
phantom.exit();
}
if ( password == 'unknown' ) {
console.log('Please specify username and password');
phantom.exit();
}
if ( apptitle == 'unknown' ) {
console.log('Please specify apptitle');
phantom.exit();
}

console.log('All settings loaded, start with execution');
page.onConsoleMessage = function(msg) {
console.log(msg);
};
/**********DEFINE STEPS THAT FANTOM SHOULD DO***********************/
steps = [

/*
* Step 1 - Open Amazon home page
*/
function(){
console.log('Step 1 - Open Amazon home page ' + initial_url);
// page.open("https://developer.amazon.com/home.html", function(status) {
page.open( initial_url, function(status) {
console.log('status is '+ status );
});
},

/*
* Step 2 - Populate and submit the login form
*/
function(username,password){
console.log('Step 2 - Populate and submit the login form');
// var appActionToken = page.evaluate(function() { return $('input[name="appActionToken"]').attr('value'); });
// console.log( 'appActionToken is ' + appActionToken );
console.log( 'username is ' + username );
console.log( 'password is ' + password );
page.evaluate(function(username,password){
console.log( ' username is ' + username );
console.log( ' password is ' + password );
document.getElementById("ap_email").value=username;
document.getElementById("ap_password").value=password;
document.getElementById("ap_signin_form").submit();
},username, password);
},
/*
* Step 3 Click the add_new_app button
*/
function(){
console.log('Step 3 - Click on the add_new_app button');
page.evaluate(function(){
var evnt = document.createEvent("MouseEvents");
evnt.initEvent("click",true,true);
document.getElementById("add_new_app_link").dispatchEvent(evnt);

});
//page.render('step3.png');
},

/*
* Step 4 - Populate and submit the First App submission vorm
*
* <input id="submit_button" type="submit" class="button large primary one-click-submit" name="save" value="Save" onclick="sanitizeManifestURL()">
*
* try looking here:
* http://stackoverflow.com/questions/32771609/how-to-click-on-selectbox-options-using-phantomjs
*
*/
function(apptitle,category){
console.log('Step 4 - save app ' + apptitle);
page.evaluate(function(apptitle,category){
document.getElementById('title').value=apptitle;
// this works
document.querySelector('select').selectedIndex = 16;
$('select[lvl="1"]').change();
//document.querySelector('select[lvl="2"]').selectedIndex = 1;
//$('select[lvl="2"]').change();

//The form will be submitted, by click on the button:
$('#submit_button').click();
},apptitle,category);

page.render('step4.png');
// console.log(page.content);
},
];

/**********END STEPS THAT FANTOM SHOULD DO***********************/

//Execute steps one by one
interval = setInterval(executeRequestsStepByStep,50);

function executeRequestsStepByStep(){
if (loadInProgress == false && typeof steps[testindex] == "function") {
console.log("testindex is " + testindex );
if ( testindex == 1 ) {
console.log( "username is " + username );
steps[testindex](username, password);
} else if ( testindex == 3 ) {
steps[testindex](apptitle, category);
} else {
steps[testindex]();
}
testindex++;
}
if (typeof steps[testindex] != "function") {
//We need to wait, after the steps is complete!
clearInterval(interval);interval=0;
setTimeout(function(){
console.log("test complete!");
page.render('complete.png');
setTimeout(phantom.exit,2000)
},3000);

}
}

/**
* These listeners are very important in order to phantom work properly.
* Using these listeners, we control loadInProgress marker which controls, weather a page is fully loaded.
* Without this, we will get content of the page, even a page is not fully loaded.
*/
page.onLoadStarted = function() {
loadInProgress = true;
console.log('Loading started');
};
page.onLoadFinished = function() {
loadInProgress = false;
console.log('Loading finished');
};
page.onConsoleMessage = function(msg) {
console.log(msg);
};

Triggering click event on li element in phantomjs

In earlier PhantomJS versions (before 2.0.0) the underlying rendering engine does not support click() function on HTMLElement elements, but supports it on HTMLInputElement elements (inputs and buttons). That's why you can click() on input buttons but not on <li>s.

There are two possible solutions for your case:

A) Switch to PhantomJS 2

B) Use a shim to emulate click() function on HTMLElements. Just issue this evaluate at the top of your script and it will work for later evaluates.

page.evaluate(function(){
if (!HTMLElement.prototype.click) {
HTMLElement.prototype.click = function() {
var ev = document.createEvent('MouseEvent');
ev.initMouseEvent(
'click',
/*bubble*/true, /*cancelable*/true,
window, null,
0, 0, 0, 0, /*coordinates*/
false, false, false, false, /*modifier keys*/
0/*button=left*/, null
);
this.dispatchEvent(ev);
};
}
});

Code from this solution

Is it possible to click an element with phantomJS in protractor?

First of all, if you choose PhantomJS as your target browser, I bet you'll come back to SO with a new problem in the nearest future. Even protractor developers recommend against it:

We recommend against using PhantomJS for tests with Protractor. There
are many reported issues with PhantomJS crashing and behaving
differently from real browsers.

Plus, if you are doing this for testing, you should have your test environment be as close to the end user's environment as possible - have you seen the users of your application using PhantomJS? - probably not.

If you are picking up PhantomJS because of it's headless nature and absence of a real display, you might run firefox or chrome in a headless mode too, see:

  • protractor with any headless browser?
  • What is a good headless browser to run with protractor?

Also, read this @Louis's answer - great essay on headless vs headful.

Or, you can use remote selenium servers at BrowserStack or Sauce Labs or similar services.


The latest approach you've taken has a problem - isDisplayed should be called:

var hiddenElement = $('#protractorTest');
browser.executeScript("arguments[0].click()", hiddenElement).then(function() {
expect(successPage.isDisplayed()).toBeTruthy();
// HERE^
});

Or/And, you may scroll into view of an element with scrollIntoView():

var button  = $('#protractorTest');
browser.executeScript("arguments[0].scrollIntoView();", button.getWebElement()).then(function () {
button.click();
});

Adding an explicit wait might also help:

var EC = protractor.ExpectedConditions;
browser.wait(EC.visibilityOf(button), 5000);


Related Topics



Leave a reply



Submit