As a simple way to test if javascript is executing correctly from CasperJS, I'm trying to have an alert box in javascript pop up on the page. My end goal is running more complex javascript functions, but for right now I just wanted to start with something easy (i.e. if there is a native CasperJS alert box function, I don't want to use it because I want to get javascript working).
var casper = require("casper").create();
casper.start("http://www.google.com", function() {
});
casper.thenEvaluate(function() {
alert('hi');
});
casper.then(function(){
this.wait(500, function() {
this.echo("I've waited for 500 milliseconds");
});
this.capture('google.png', {
top: 0,
left: 0,
width: 1500,
height: 1000
});
});
casper.run(function() {
this.echo(this.getTitle()); // Google
this.exit();
});
When I run this script, I do visit http://www.google.com (as evidence from the screenshot) but no alert box shows up.
Does anyone know how to run javascript from CasperJS?
Thanks!
As to why alert('hi') won't be seen, this link gives a good explanation. Basically, casperjs/phantomjs is a headless browser and hence can't have a window or dialogs.
But inject your scripts into a remote page and execute them you can: here's how in Casperjs docs.
Here's your script slightly modified (note that jquery.js here is supposed to be in the local filesystem, in the same folder from which you issue your command to launch CasperJS in the console):
var casper = require("casper").create({
clientScripts: ["jquery.js"]
});
casper.start("http://www.google.com/ncr");
casper.then(function(){
this.evaluate(function() {
$("input[name='q']").val("CasperJS execute javascript on remote page");
});
});
casper.then(function(){
this.capture('google.png', {
top: 0,
left: 0,
width: 1500,
height: 1000
});
});
casper.run(function() {
this.echo(this.getTitle()); // Google
this.exit();
});
Related
I have tried various methods in casperJS to fill in and submit a form. The code is shown below. Ultimately I am building a robot to automatically check the status of a cargo airwaybills on the IAG Cargo web portal.
Sendkeys will complete the form but I cannot manage to click the SEARCH button.
Using casperJS Form filling methods does not work at all.
Is this an unusual website or am I doing something wrong?
In the code below the program appears to fail on line
this.clickLabel('SEARCH', 'button');
and the subsequent code does not run.
(I have used an dummy airwaybill number in this example so the final page will show 'Airwaybill not found')
var casper = require('casper').create();
var x = require('casper').selectXPath;
phantom.cookiesEnabled = true;
casper.userAgent('Mozilla/4.0 (compatable; MSIE 6.0; Windows NT 5.1)');
casper.start('https://www.iagcargo.com/iagcargo/portlet/en/html/601/main/search');
casper.waitForSelector("#awb_cia", function() {
this.echo('Selector found');
casper.capture('iag_start.png');
this.sendKeys('#awb_cia','125');
this.sendKeys('#awb_cod','12345675');
});
casper.then(function step2() {
this.clickLabel('SEARCH', 'button');
this.echo('this is step 2');
casper.capture('iag_end.png');
});
require('utils').dump(casper.steps.map(function(step) {
return step.toString();
}));
casper.run();
Not being able to click is a common problem that could have by many reasons. clickLabel() won't work here, since it's not a button tag, but an input tag. Here is what I saw on the page:
You can try this,
casper.click('input[value="Search"]');
In general, here are things you could try when clicking an element.
Try changing the viewportSize, e.g.
viewportSize: { width: 1024, height: 768 }
This is because, casperjs won't click anything that is not visible on the page.
If using xpath selector, try CSS instead. XPath selectors are brittle, and do not work the same across all browsers.
Sometimes jquery click works, e.g.
casper.evaluate(function(){
var element = document.querySelector( 'span.control.critical.closer' );
$(element).click();
});
If there's a function inside the button tag, you can call that function directly. E.g.
SEARCH
You can call that function directly,
casper.someFunc();
var casper = require('casper').create({
verbose: true,
logLevel: "debug",
waitTimeout: 60000,
resourceTimeout: 10000,
viewportSize: {
width: 1024,
height: 768
},
pageSettings: {
javascriptEnabled: true,
loadImages: true,
loadPlugins: true
}
});
var x = require('casper').selectXPath;
phantom.cookiesEnabled = true;
casper.userAgent('Mozilla/4.0 (compatable; MSIE 6.0; Windows NT 5.1)');
casper.start('https://www.iagcargo.com/iagcargo/portlet/en/html/601/main/search');
casper.waitForSelector("#awb_cia", function() {
this.echo('Selector found');
casper.capture('iag_start.png');
this.sendKeys(x('//*[#id="awb_cia"]'),'125');
this.sendKeys('#awb_cod','12345675');
this.capture('iag_middle.png');
});
casper.then(function step2() {
if(this.exists('body > div.cuerpo > div.cuerpo > div.contenido > div > form > table > tbody > tr > td:nth-child(3) > input')){
this. click('body > div.cuerpo > div.cuerpo > div.contenido > div > form > table > tbody > tr > td:nth-child(3) > input');
}
});
casper.then(function step3() {
this.echo('this is step 2');
casper.capture('iag_end.png');
});
//require('utils').dump(casper.steps.map(function(step) {
// return step.toString();
//}));
casper.run();
The following is the html I wanna tackle with.
I wanna post a query and see the weather reports for that city. I tried my codes:
var casper = require('casper').create();
var utils = require('utils');
casper.start('http://www.weather.com.cn/weather1d/101210101.shtml');
casper.waitForSelector('input', function()
{
this.fillXPath('div.search clearfix',{'//input[#id="txtZip"]':'shijiazhuang'},true);
});
casper.then(function()
{
utils.dump(this.getTitle());
});
casper.run();
It did not print the web paeg title on the console. I also tried this:
casper.waitForSelector('input', function()
{
this.fillSelectors('div.search clearfix',{'input[id="txtZip"]':'shijiazhuang'},true);
});
}
);
I did not get any web page title also. I got quite confused and did not what I had done wrong. Besides, it seems that this.fill method only tackles with name attributes to post information on CasperJS's official website. I need your help.
CasperJS script:
var casper = require('casper').create(), utils = require('utils');
casper
.start('http://www.weather.com.cn/weather1d/101210101.shtml',function(){
this
.wait(3000,function(){
this.capture('search.png');
utils.dump(this.getTitle());
})
.evaluate(function(){
document.getElementById('txtZip').value='shijiazhuang';
document.querySelector('input[type="button"]').click();
})
})
.run();
Result:
"【石家庄天气】石家庄今天天气预报,今天,今天天气,7天,15天天气预报,天气预报一周,天气预报15天查询"
search.png
You are doing it correct, you only have to modify your script a little bit.
Just modify the selector of the input field the actual don't seems to work, then you should get the correct result.
"this.fillXPath" only fills up the form and don't post it.
...
// fill the form
casper.waitForSelector('input', function() {
this.fillXPath('#txtZip', {
'//input[#id="txtZip"]': 'shijiazhuang'
}, true);
});
// trigger - post the form
casper.then(function() {
this.click('#btnZip');
});
// i can't speak chinese - wait for some specific change on this page
casper.wait(5000);
// take a screenshot of it
casper.then(function() {
this.capture("shijiazhuang_weather.png");
});
...
Wtih casperjs I fill a textarea and trigger an event with:
casper.thenClick( "#project-bar-yes-no-modal.in button.modal-no", function() {
casper.evaluate(function(){
$("#project-button-textarea-for-testing").val( "// This is a test program\nellipse(100, 100, 100, 102);\n\nrect(50, 50, 50, 50);" ).trigger("set-live-editor");
});
this.wait(200);
} );
which works fine. When I try to do the same using a function then casper.evaluate() is not called.
casper.setLiveEditorCode = function( code ) {
utils.dump("1");
casper.evaluate(function(){
utils.dump("2");
$("#project-button-textarea-for-testing").val( code ).trigger("set-live-editor");
});
};
and
casper.thenClick( "#project-bar-yes-no-modal.in button.modal-no", function() {
casper.setLiveEditorCode( "ellipse(100, 100, 100, 101);\n\n" );
this.wait(200);
} );
"1" is displays in the output, "2" is not. Why?
In short, the code inside evaluate is executed by browser, and utils object is not defined in js environment of browser...
casper.setLiveEditorCode = function( code ) {
utils.dump("1");//here is casperjs js environment, and utils is imported by casperjs bootstrap.js
casper.evaluate(function(){
utils.dump("2"); //here browser js environment, and utils is not defined in that scope...
});
};
Read the official docs about evaluate for further information.
Following is a minimal casper script that does a Google query. I've added casper.on('click' ...) prior to running the script, but it doesn't appear to get triggered.
What am I missing?
// File: google_click_test.js
"use strict";
var casper = require('casper').create();
casper.on('click', function(css) {
casper.echo('casper.on received click event ' + css);
});
// ================================================================
// agenda starts here
casper.start('https://google.com', function g01() {
casper.echo('seeking main page');
});
casper.then(function a02() {
casper.waitForSelector(
'form[action="/search"]',
function() {
casper.echo("found search form");
},
function() {
casper.echo("failed to find search form");
casper.exit();
});
});
casper.then(function a03() {
casper.fillSelectors('form[action="/search"]', {
'input[title="Google Search"]' : 'casperjs'
}, false);
});
casper.then(function a04() {
casper.click('form[action="/search"] input[name="btnG"]')
casper.echo('clicked search button');
});
casper.run();
Output:
Here's the output. I would expect to see casper.on received click event somewhere, but it seems that it didn't get triggered:
$ casperjs --ignore-ssl-errors=true --web-security=no google_click_test.js
seeking main page
found search form
clicked search button
$
Although your example runs fine for me using casperjs 1.1.0-beta3 and phantomjs 1.9.8, I've been having similar issues in the last few months with casperjs. Sadly it seems that the author has stopped maintaining the project. More information here:
https://github.com/n1k0/casperjs/issues/1299
I would suggest moving to a different testing framework. In my case I chose a combination of mocha + chai + nightmarejs. This gist is a good starting point:
https://gist.github.com/MikaelSoderstrom/4842a97ec399aae1e024
I use the Mozilla's Add-on Builder. I am looking for a way to remove an event listener in a contentScript. I use the port way to communicate between add-on script code and the content script code.
The problem is the callback on event "response" is called more than once. I want it to be called once and declared in the callback of the event show.
Can someone help me with that?
main.js code:
var Panel = require("panel").Panel;
var popup_panel = Panel({
width: 286,
height: 340,
contentURL: require("self").data.url("popup.html"),
allow: { script: true },
contentScriptWhen: "end",
contentScriptFile : [
require("self").data.url("test.js")
],
onShow: function(){
this.port.emit("show");
var pan = this;
this.port.on("hide", function(){pan.hide();});
}
});
var Widget = require("widget").Widget;
var widget = Widget({
id: "mozilla-icon",
label: "My Mozilla Widget",
contentURL: "http://www.mozilla.org/favicon.ico",
panel: popup_panel
});
popup_panel.port.on("get", function(){
popup_panel.port.emit("response");
});
Content script (test.js):
self.port.on("show", function(){
console.log("show");
function response(){
console.log("reponse called");
}
self.port.emit("get");
self.port.once("response", response);
self.port.removeListener("response", response);
});
full source code
Finally I found the problem. It is a bug in the add-on kit. In the file api-utils/lib/content/content-worker.js in the function removeListener the index is always -1.
The parameter given in the indexOf is the name of the event and it search a function. It is incorrect.
So to solve the problem I replace the line let index = listeners[name].indexOf(name); by let index = listeners[name].indexOf(callback);.
EDIT
The bug has been fixed. It will publish in the version 1.10 see here