I've just picked up node.js and selenium the other day so I apologize for this introductory question but I haven't been able to find an answer on this. I've written a .js script that uses webdriverio. To use this I open 2 cmd windows (I'm running off windows 7) one where I type selenium-standalone start to get selenium to open. Then I run in the other one node ..../script.js . This gets me a beautiful browser that does what it's suppose to 1/10. The other 9/10 times I get a Session deleted due to client timeout. Since this is to be quick and easy I don't really care if it times out I just want it to restart this process. Any suggestions how to do this?
From the sounds of it, your node.js program may be trying to connect to the Selenium server, but without allowing for enough time for it to be able to establish the browser reliably too. Perhaps a case for using .pause(10000) as in:
var Selenium = function () {
this.client = webdriverio.remote(options);
};
Selenium.prototype.refreshURL = function (url, cb) {
var self = this;
this.client
.init()
.url(url)
.pause(10000)
// etc.
}
A good workaround for setting a pause is to use waitFor* - there are multiple options like
http://webdriver.io/api/utility/waitForVisible.html
or
http://webdriver.io/api/utility/waitForExist.html
.waitForVisible('body', 20000000).then(function(isVisible){
//.. you can add also small timeout here to dodge low hardware lags
});
Related
This is an update to a question I had asked previously but wasn't thinking straight when I asked the question (I was taking a very backwards approach to my solution). I'm currently working with Puppeteer and I'm trying to create an association between a particular task and a puppeteer browser instance. Right now I am currently getting the browser's context id using:
const {browserContextId} = await browser._connection.send('Target.createBrowserContext');
and I am storing it in a file along with other details related to the task. My goal is to somehow be able to close that browser instance using the stored context id. I've given this issue a read on the Puppeteer's GitHub hoping that it would help in some way but it seems that it's not super helpful to me as its not really related to what I'm doing.
The real issue is that I am going to be spawning browser instances in one file and attempting to close them in another, otherwise this wouldn't be an issue at all. Right now the only thing I've been able to do is just spawn another browser instance using the context id (pretty much useless for my task) and have had no luck in closing it or disposing it.
Any help would be greatly appreciated, thanks!
P.S. If there is a better approach to solving this association issue I'm all ears!
Turns out I was thinking about it way too much and trying to make it too complex. For anyone trying to do something similar I'll leave my solution here for you.
Instead of using the browser's context id I found it much easier to just grab the browser's process id (pid). From there I could kill the process using different strategies based on where I was running the close command.
For Node.js:
// Lets say for example we're instantiating our browser like this
const browser = await puppeteer.launch({ headless: false });
// You can simply run this to get the browser's pid
const browserPID = browser.process().pid
// Then you can either store it for use later
fs.writeFile(file, JSON.stringify(jsondata, null, 4), (err) => {
if (err) console.log(err);
})
// Or just kill the process
process.kill(browserPID);
Keep in mind that if you are storing the PID you need to read the file and parse the data to pass into the process.kill command.
For React via Electron
// Require process from the electron file
const process = window.require('process');
// Then same process as before
process.kill(yourbrowserPID);
Hopefully my stupidity can help someone in the future if they are trying to do something similar. It was way easier than I was making it out to be.
EDIT
I have noticed the removal of the .end() function appears to solve the issue, but after reading the Nightmare docs on the use of .end() it says: Completes any queue operations, disconnect and close the electron process.
Now while this does solve the problem, am I now just opening more and more electron processes each time the route is called, which will eventually cause the server to run out of memory, or is this a safe way to fix the issue?
ORIGINAL TEXT
Please consider the following problem:
I am developing a Node based service that will allow the user to request screenshot of a particular URL.
For this I am using Nightmare to visit the URL, wait 2 seconds, take a screenshot, which is saved to the disk, convert it to base64, delete the image and then return the base64 string.
console.log('Nightmare starts');
nightmare
.goto(url)
.wait(2000)
.screenshot(filename)
.end()
.then(function (result)
{
fs.exists(filename, function(exists)
{
if (exists)
{
data = fs.readFileSync(filename);
var base64 = data.toString('base64')
fs.unlink(filename);
var output = {'message':'success','map_image':base64};
res.send(output);
}
});
})
.catch(function (error)
{
console.error('Search failed:', error);
});
console.log("Nightmare Finished");
The above code works just fine, the first time it runs. However any subsequent calls to this just consoles "Nightmare starts" and "Nightmare Finished" instantly with the actual code in-between not running. I don't appear to have any errors display, nothing is caught if I wrap it in a try/catch. The node requires a reboot to allow it to happen again.
Something worth noting is that I am running on a headless ubuntu machine, as electron (one of the nightmare dependencies) appears to need a GUI, I am using xvfb to launch the node using the following command:
xvfb-run --auto-servernum --server-num=1 node server.js
I'm assuming this may be an issue with some resource not being released correctly on the first run, but any assistance would be appreciated.
Also open to any constructive criticism of my code, very new to Node and i'm sure i'm not writing in the most optimal way (sync file loading etc)
It appears that you are simply misplacing where you are creating the nightmare instances. Cannot help much without some more code snippet and information.
Way 1
Create nightmare instance every time and close them after you are done with your task. It will require some time to boot up the instance, but it will also lessen the memory load. Not to mention you can have multiple nightmare instances for different users.
Way 2
Don't end and re-use same nightmare instance. Have multiple nightmare instances and queue the call for screenshot. The websites will load fast and it won't take time to boot up an instance, but you will have longer wait time for longer queue.
im very new to nodejs but was wondering if the following was easily possible to achieve.
I use Gulp along with browser-sync plugin. I was wondering if there was a way to log every time the browser gets re-injected with the domain and time over a port range. The reason for this being I want to be able to plot productivity over projects without having to manually record this and this seems to be the most logical solution.
Is there anything out there like this or could this easily be added into a Gulp file?
Many thanks, Luke
There are some options and you can use the emitter to react to events like stream:changed, browser:reload, client:connected, connection,...
example:
var bs = require("browser-sync").create();
bs.init({}); //http://www.browsersync.io/docs/options/
....
bs.emitter.on("file:reload", function(){
console.log("File reload - Details:"+arguments)
});
I'm about to start coding a chat bot. However, I plan on running more than one, using a wrapper to communicate and restart them. I have done this in the past with child_process.fork(), but it was incredibly inefficient. I've looked into spawn and cluster as well, but they all seem to focus on running the same thing, not unique bots. As for plugins, I've looked into fleet, forkfriend, and workerfarm, but none seem to fit my needs.
Is there any plugin or way I'm not seeing to help me do this? Or am I just going to have o wing it again?
You can have as many chat bots as you wish in a single process. The rule of thumb in Node.js is using one process per processor core since Node has slightly different multithreading model you might got used to.
Assuming you still need some multithreading on top of this, here is a couple of node modules you might find fitting your needs:
node-webworker-threads, dnode.
UPDATE:
Now I see what you need. There is a nice example in Node.js docs, which I saw recently. I just copy & paste it here:
var normal = require('child_process').fork('child.js', ['normal']);
var special = require('child_process').fork('child.js', ['special']);
// Open up the server and send sockets to child
var server = require('net').createServer();
server.on('connection', function (socket) {
// if this is a VIP
if (socket.remoteAddress === '74.125.127.100') {
special.send('socket', socket);
return;
}
// just the usual dudes
normal.send('socket', socket);
});
server.listen(1337);
child.js looks like this:
process.on('message', function(m, socket) {
if (m === 'socket') {
socket.end('You were handled as a ' + process.argv[2] + ' person');
}
});
I believe it's pretty much what you need. Launch several processes with different configs (if number of configs is relatively low) and pass socket to a particular one from master process.
As QA I use WSH scripts to do auto upload, deployment and some time Web testing in IE. WSH(wscript) with JavaScript can open IE window, activate it and access DOM model to do some actions or verify some expected results. It is kind of Selenium 1.0 approach but does not require JAVA and any envrionment configuration so can be executed on any developers/qa windows machine immidiately.
Recently I found NodeJS and all its abilities, except manipulating with Windows IE DOM. Cannot find the way on how to run my old WSH scripts to test IE DOM and at the same time use some NodeJS modules to parse XMLs or run test report server.
So question: is it possible to run WSH JavaScripts and Node.js and use all goodies from both worlds?
I am afraid, it is not, but hope somebody has workaround...
As workaround, maybe somebody found the way in NodeJS to start IE window access its DOM (...add own js script or run SendKeys to it)!?
I understand that NodeJS is not designed to do windows administrative tasks.
While not actually marrying as the question requires, #o_nix in the comments made the suggestion for https://github.com/idobatter/node-win32ole.
I'd suggest that this module satisfies many issues for people arriving here from Google (as I did).
It is also available from npm here: https://www.npmjs.com/package/win32ole
The module also has quite a few examples, such as:
https://github.com/idobatter/node-win32ole/blob/dev0.1.3/examples/activex_filesystemobject_sample.js
var win32ole = require('win32ole');
. . .
var withReadFile = function(filename, callback){
var fso = new ActiveXObject('Scripting.FileSystemObject');
var fullpath = fso.GetAbsolutePathName(filename);
var file = fso.OpenTextFile(fullpath, 1, false); // open to read
try{
callback(file);
}finally{
file.Close();
}
};
var withEachLine = function(filename, callback){
withReadFile(filename, function(file){
// while(file.AtEndOfStream != true) // It works. (without unary operator !)
// while(!file.AtEndOfStream) // It does not work.
while(!file.AtEndOfStream._) // *** It works. oops!
callback(file.ReadLine());
});
};
withEachLine(testfile, function(line){
console.log(line);
});
So, to me, this is as good as marrying old WSH scripts as anything. Tweaks will be involved of course, but then it's goodbye WSH.
More specifically, to the question at hand, this is a snippet of a demo IE script:
https://github.com/idobatter/node-win32ole/blob/master/examples/ie_sample.js
var win32ole = require('win32ole');
. . .
var ie = new ActiveXObject('InternetExplorer.Application');
ie.Visible = true;
for(var i = 0; i < uris.length; ++i){
console.log(uris[i]);
ie.Navigate(uris[i]);
win32ole.sleep(15000, true, true);
}
ie.Quit();
WSH is a different runtime and set of libraries from nodejs. The only simple solution I can think of for your use case is to use child_process to run your WSH scripts and capture the output and parse it.
The other options are:
Look at other browser automation modules - selenium is not your only option, there are also headless browsers, which may appease the situation: zombiejs, phantomjs etc
Write native bindings to the APIs used by WSH for nodejs
Merge the event loops of WSH and nodejs, and expose WSH's API to nodejs: not a good idea for such a narrow use case.
The benefit of firing a child process is that WSH is able to issue HTTP requests. And Node, obviously, can serve HTTP.
One can imagine a Node.js library that would completely proxy ActiveXObject that way and give Node.js all the same powers as WSH.