I have a long-running script that loops across several different links to perform its work. I encountered a scenario where PhantomJS ran out of resources due to the page objects not being garbage collected since I'm reusing it. I have a simple example below. I close() the page object and create a new one at the end of each loop cycle, but after I do that Casper just hangs. What is the proper way to do this?
var links = ['http://www.google.com', 'http://www.yahoo.com'];
var casper = require('casper').create({
logging: 'error',
pageSettings: {
webSecurityEnabled: false
}
});
casper.start('http://www.amazon.com', function () {
this.echo(this.getTitle());
});
casper.eachThen(links, function(item) {
var url = item.data;
this.open(url).then(function (){
this.echo(this.getTitle());
}).then(function (){
casper.page.close();
casper.page = require('webpage').create();
});
});
casper.run(function (){
this.echo('Done');
});
This will output
Amazon.com: Online Shopping for Electronics, Apparel, Computers, Books, DVDs & more
Google
and then just hang. What am I missing?
var casper = require('casper').create();
var urls = ['http://google.com/', 'http://yahoo.com/'];
casper.start().eachThen(urls, function(response) {
this.thenOpen(response.data, function(response) {
this.echo('\n'+this.getTitle());
});
});
casper.run(function(){
this.die('\n'+'Done');
});
this worked for me. its from the documentation... I'm not sure casperjs requires you to close the page.
Related
I'm using cypress to test my VueJS application. The one thing I'm having trouble with is mocking an image to be displayed on the page. For my use case, I'm simply loading a user profile with the following code:
describe('Test Login', () => {
it('Can Login', () => {
cy.server();
cy.route({
method: 'GET',
url: '/api/account/',
response: 'fx:profile.json',
});
cy.route('**/media/demo1.png', 'fx:demo1.png');
});
});
fixtures/profile.json
{
"avatar": "http://localhost:8080/media/demo1.png",
"username": "cypress",
"email": "email#cypress.io",
"pk": 1,
"is_staff": true,
"is_superuser": true,
"is_active": true
}
The profile fixture data is loading correctly in the test. In my fixtures folder, I also have a demo1.png file. I am expecting this image to be loaded and displayed on the page during my test, but it is being displayed as a broken image.
In the network tab, it shows demo1.png as a broken image with a 200 response code and type of text/html.
The cypress documentation mostly discusses images in the context of uploading images, but I haven't been able to find an example of how I can mock an image that is loaded through a <img> tag. Is there an easier way of doing this?
I am not sure if this answer can help you. But at least it is a workaround for this problem ;-)
Say we have a HTML like this:
<html>
<body>
<button id="button">load</button>
<div id="profile">
</div>
<script>
function httpGetAsync(theUrl, callback)
{
var xmlHttp = new XMLHttpRequest();
xmlHttp.onreadystatechange = function() {
if (xmlHttp.readyState == 4 && xmlHttp.status == 200)
callback(JSON.parse(xmlHttp.responseText));
}
xmlHttp.open("GET", theUrl, true); // true for asynchronous
xmlHttp.send(null);
}
document.getElementById("button").addEventListener("click", () => {
httpGetAsync("/api/account/", (result) => {
var div = document.querySelector("#profile");
var img = document.createElement("img");
img.src = result.avatar;
div.appendChild(img)
})
})
</script>
</body>
</html>
source: HTTP GET request in JavaScript?
And you want to load the profile after the click was done. Then you can use MutationObserver to replace the img.src.
First, write the MutationObserver:
var observeDOM = (function(){
var MutationObserver = window.MutationObserver || window.WebKitMutationObserver;
return function( obj, callback ){
if( !obj || !obj.nodeType === 1 ) return; // validation
if( MutationObserver ){
// define a new observer
var obs = new MutationObserver(function(mutations, observer){
callback(mutations);
})
// have the observer observe foo for changes in children
obs.observe( obj, { childList:true, subtree:true });
}
else if( window.addEventListener ){
obj.addEventListener('DOMNodeInserted', callback, false);
obj.addEventListener('DOMNodeRemoved', callback, false);
}
}
})();
(heavily copy & pasted from Detect changes in the DOM)
Now you are able to do this:
describe('Test Login', () => {
it('Can Login', () => {
var win = null;
cy.server();
cy.route({
method: 'GET',
url: '/api/account/',
response: 'fx:profile.json'
});
cy.visit("index.html").then(w => {
cy.get("#profile").then(pro => {
var e = pro[0];
observeDOM(e, (m) => {
// add a red dot image
m[0].addedNodes[0].src = "data:image/png;base64,"+
"iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAABGdBTUEAALGP"+
"C/xhBQAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9YGARc5KB0XV+IA"+
"AAAddEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIFRoZSBHSU1Q72QlbgAAAF1J"+
"REFUGNO9zL0NglAAxPEfdLTs4BZM4DIO4C7OwQg2JoQ9LE1exdlYvBBeZ7jq"+
"ch9//q1uH4TLzw4d6+ErXMMcXuHWxId3KOETnnXXV6MJpcq2MLaI97CER3N0"+
"vr4MkhoXe0rZigAAAABJRU5ErkJggg=="
})
})
cy.get("button").click()
})
});
});
(yeah at least some lines of code are written on my own ;-P)
You can read the image from the img.src attribute from the fixtures folder. For the sake of simplicity I have used a static base64 string here.
And the result:
We are not using this kind of stuff in our aurelia app but I tried similar things in a private project some time ago.
consider the following snippet.how can i access the value of the page url outside the page context?globally accessing the value was not working either.callbacks wasn't clear to me in approach.
page.onUrlChanged = function(targetUrl) {
console.log('New URL: ' + targetUrl);
};
page.onConsoleMessage = function (msg) {
console.log(msg);
};
var abc=page.open(url,function(status){
page.evaluate(function(){
//some code;
})
return page.url;
});
console.log(abc);
the code always gives undefined page url.
PhantomJS documents are very much recommended: http://phantomjs.org/api/webpage/method/evaluate.html
page.open(url,function(status){
var current_url = page.evaluate(function(){
return document.location.href;
})
console.log(current_url);
});
I am new using CasperJS. I am trying to call an external command using Casper but nothing appers in the console. I am using Windows 7. Do you have any idea? This is the code:
var casper = require('casper').create();
casper.then(function() {
var process = require("child_process")
var spawn = process.spawn
var execFile = process.execFile
var child = spawn("cmd.exe", ["/k","dir"])
child.stdout.on("data", function (data) {
console.log("spawnSTDOUT:", JSON.stringify(data))
})
child.stderr.on("data", function (data) {
console.log("spawnSTDERR:", JSON.stringify(data))
})
child.on("exit", function (code) {
console.log("spawnEXIT:", code)
})
});
casper.run();
Thanks
That happens because CasperJS exits earlier than spawned process manages to return data.
The detailed explanation: https://stackoverflow.com/a/29255476/2715393
My code is:
var url = 'https://search.yahoo.com/',
page = new WebPage(),
fs = require('fs');
page.settings.userAgent = 'Mozilla/5.0 (platform; rv:geckoversion) Gecko/geckotrail appname/appversion';
page.onConsoleMessage = function (msg) {
console.log(msg);
};
page.open(url, function(status) {
if (status !== 'success')
{
console.log('Unable to access network');
phantom.exit();
return;
}
else
{
page.includeJs("https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js", function()
{
page.evaluate(function()
{
$('#yschsp').val("ask question");
$(".sbb").click();
});
page.onLoadFinished = function(status) {
var content = page.content;
fs.write('1.html', content, 'w');
console.log($('#link-1').val());
phantom.exit();
};
});
}
});
JQuery works perfect in page.evaluate but does not work in page.onLoadFinished. I get an error
Can't get variable: $
That means that in function page.onLoadFinished jquery is not working. But I can not understand why?
Since jQuery is loaded into the page context, you can only use there. The only function that interfaces with the page context is evaluate (and the other evaluate functions).
So this line
console.log($('#link-1').val());
must be inside of an evaluate callback. Since you have a page.onConsoleMessage event handler you will receive the console message from the page context.
The other thing is that adding an page.onLoadFinished event handler after the page has loaded isn't doing anything useful. You can remove the handler surrounding your code since the page load is finished when the page.open callback is called.
If #link-1 is not yet loaded, you should either log the value after a static timeout (setTimeout) or use waitFor.
While searching in stack overflow .I find an old issue that i am facing too.But no one answered it.
So just wants to know anyone have any idea about it
How to get jquery Tooltipster Plugin to work for newly created DOM elements?
Following is my code
$(document).ready(function() {
$('.test_link').tooltipster({
interactive:true,
content: 'Loading...',
functionBefore: function(origin, continueTooltip) {
continueTooltip();
// next, we want to check if our data has already been cached
//if (origin.data('ajax') !== 'cached') {
$.ajax({
type: 'POST',
url: 'example.php',
success: function(data) {
// update our tooltip content with our returned data and cache it
origin.tooltipster('content', $(data)).data('ajax', 'cached');
}
});
// }
}
});
});
My problem solved.
Just add the instantiation script in the ajax content too.
also set the option multiple:true
ie
$(document).ready(function() {
$('.test_link').tooltipster({
interactive:true,
multiple:true,
content: 'Loading...',
functionBefore: function(origin, continueTooltip) {
continueTooltip();
// next, we want to check if our data has already been cached
//if (origin.data('ajax') !== 'cached') {
$.ajax({
type: 'POST',
url: 'example.php',
success: function(data) {
// update our tooltip content with our returned data and cache it
origin.tooltipster('content', $(data)).data('ajax', 'cached');
}
});
// }
}
});
});
It worked for me in Firefox.But didn't tested in other browser
I know this is an old post, and the problem was solved, but i recently needed something similar.
Adding the initialization on every ajax function was not a solution since we had several content dynamically loaded on the page, so the simplest solution found was:
$(document).on('mouseenter', '[data-toggle="tooltip"]', function(){
if ($(this).is('.tooltipstered')) {
// Do nothing
} else {
$(this).tooltipster({
delay: 50,
// Your other Tooltipster options
});
$(this).mouseover();
}
});
$('[data-toggle="tooltip"]') being the OP's $('.test_link').
The if deter the repeated initialization of document mouseenter.