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.
Related
I'm trying to run an empty simple code snippet to test SaxonJS 1.1.0 on NodeJs v8.11.1 on Windows 10.
require('./Saxon-JS-1.1.0/SaxonJS.js');
But I got this error :
PS C:\XXX\sandbox\xsl-transformation> node main.js
C:\XXX\xsl-transformation\Saxon-JS-1.1.0\SaxonJS.js:17136
setPlatform(JSTestDriver.platform);
^
ReferenceError: JSTestDriver is not defined
at initialize (C:\XXX\sandbox\xsl-transformation\Saxon-JS-1.1.0\SaxonJS.js:17136:25)
Looking at the source code, I can see :
function initialize() {
"use strict";
if (inBrowser) {
setPlatform(BrowserPlatform.platform);
saxonPrint("Saxon-JS " + getProcessorInfo().productVersion + " in browser", 0);
} else {
// Currently only Nashorn. (Later need to distinguish from Node case)
// Nashorn JSTestDriver
setPlatform(JSTestDriver.platform);
saxonPrint("Saxon-JS " + getProcessorInfo().productVersion + " in
Nashorn");
// node NodePlatform
}
if (typeof platform.initialize === "function") {
platform.initialize();
}
}
It seems Node Platform is not implemented.
However, in the documentation, it is written :
We're talking here primarily about running Saxon-JS in the browser.
However, it's also capable of running in server-side JavaScript
environments such as Node.js (not yet fully supported in this
release).
I deeply search a code snippet of SaxonJS/NodeJS but I did not find one.
Has anyone a snippet code of SaxonJS working on NodeJS ?
I'm afraid the documentation was somewhat jumping the gun. We do have users who have reported getting the code to run under Node.js, and we have done it ourselves "in the lab", but it requires source code tweaks to the issued product. As released, the code runs under two platforms, the browser platform and Nashorn (and under Nashorn, it assumes our test harness which is not released).
We're working on a version for Node.js. Doing this properly as a product needs a lot of functionality that isn't in the browser version, for example in XML parsing and serialization, debugging support, command line interfaces and APIs, etc.
Node.js Saxon-Js Instructions
This S/O question is the first listed on Google for "node.js saxon-js". So I'm answering this 4 years late because of the visibility.
[Terminal] npm install saxon-js
[IDE][xslt.js]
const saxonJs = require('saxon-js');
const fs = require('fs');
function transformDocument(source, destination, transformation, parameters) {
var xml = fs.readFileSync(source).toString()
var stylesheetParams = Object.getOwnPropertyNames(parameters)
.map(o => `QName('', '${o}') : '${parameters[o]}'`).join(",")
const html = saxonJs.XPath.evaluate(
`transform(
map {
'source-node' : parse-xml($xml),
'stylesheet-location' : $xslt,
'stylesheet-params': map {${stylesheetParams}},
'delivery-format' : 'serialized'
}
)?output`,
null,
{
params : {
'xml' : xml,
'xslt' : 'file:' + transformation
}
}
);
fs.writeFileSync(destination, html)
}
Parameters
source: xml file name
destination: output file name
transformation: xsl file name
parameters: regular json object containing any params for xslt
Characteristics
(-) extremely slow
(+) doesn't require running something on the command line every time the xslt file changes
(+) easy to use function signature based on xslt usage over the last 22 years
(+) doesn't crash
Notes
I didn't find any "Getting Started" for this. Not from Google, at least. I pieced together a working solution from multiple S/O answers.
This took me 3 hours. I hope this saves multiple developers 3 hours each.
I tried getting 'source-location' to work with a file: url, but no beans
sync I/O of course isn't necessary, it should work fine with async and nested callback functions. However, this isn't why its' slow. The xpath transform() function is quite slow, for some reason.
For some reason, this solution is stable and doesn't crash. Using Saxon-C over in Python keeps crashing, but this does not.
I'm trying to create selenium tests that run each step synchronously, without using .then(), or async/await. The reason for this is that I want to create a set of functions that allow pretty much anyone on our test team, almost regardless of tech skills to write easy to read automated tests. It looks to me like webdriver-sync should give me exactly what I want. However, the following dummy code is producing problems:
var wd = require('webdriver-sync');
var By = wd.By;
var Chromedriver = wd.Chromedriver;
var driver = new Chromedriver;
driver.get('https://my.test.url');
var myButton = driver.findElement(By.cssSelector('[id*=CLICK_ME]'));
myButton.click();
It tries to run - browser is launched, and page starts to load... but the steps are not executed synchronously - it goes on and tries to find and click "myButton" before the page has finished loading, throwing a "no such element" error... which to me kinda defeats the point of webdriver-sync?! Can someone tell me where I am going wrong?
FWIW, I have webdriver-sync 1.0.0, node v7.10.0, java 1.8.0_74, all running on CentOS 7.
Thanks in advance!
You need to put double-quotes around "CLICK_ME" as it's a string value.
Generally, though, it's a good idea to Wait for specific elements because dynamic pages are often "ready" before all their elements have been created.
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
});
One of the pleasures of frameworks like Rails is being able to interact with models on the command line. Being very new to node.js, I often find myself pasting chunks of app code into the REPL to play with objects. It's dirty.
Is there a magic bullet that more experienced node developers use to get access to their app specific stuff from within the node prompt? Would a solution be to package up the whole app, or parts of the app, into modules to be require()d? I'm still living in one-big-ol'-file land, so pulling everything out is, while inevitable, a little daunting.
Thanks in advance for any helpful hints you can offer!
One-big-ol'-file land is actually a good place to be in for what you want to do. Nodejs can also require it's REPL in the code itself, which will save you copy and pasting.
Here is a simple example from one of my projects. Near the top of your file do something similar to this:
function _cb() {
console.log(arguments)
}
var repl = require("repl");
var context = repl.start("$ ").context;
context.cb = _cb;
Now just add to the context throughout your code. The _cb is a dummy callback to play with function calls that require one (and see what they'll return).
Seems like the REPL API has changed quite a bit, this code works for me:
var replServer = repl.start({
prompt: "node > ",
input: process.stdin,
output: process.stdout,
useGlobal: true
});
replServer.on('exit', function() {
console.log("REPL DONE");
});
You can also take a look at this answer https://stackoverflow.com/a/27536499/1936097. This code will automatically load a REPL if the file is run directly from node AND add all your declared methods and variables to the context automatically.
Did anyone set up something like this for himself using the existing
node.js REPL? I didn't think of a quick way to do it.
The way I do it today is using emacs and this:
https://github.com/ivan4th/swank-js
This module is composed of:
A SLIME-js addon to emacs which, in combination with js2-mode, lets
you simply issue a C-M-x somewhere in the body of a function def - and
off goes the function's string to the ..
Swank-js server (yes, you could eval from your local-machine
directly to a remote process) written in Node.js - It receives the
string of the function you eval'ed and actually evals it
A whole part that lets you connect to another port on that server
with your BROWSER and then lets you manipulate the DOM on that browser
(which is pretty amazing but not relevant)
My solution uses SLIME-js on the emacs side AND I require('swank-
js') on my app.js file
Now.. I have several issues and questions regarding my solution or
other possible ones:
Q1: Is this overdoing it? Does someone have a secret way to eval stuff
from nano into his live process?
Q2: I had to change the way swank-js is EVALing.. it used some
kind of black magic like this:
var Script = process.binding('evals').Script;
var evalcx = Script.runInContext;
....
this.context = Script.createContext();
for (var i in global) this.context[i] = global[i];
this.context.module = module;
this.context.require = require;
...
r = evalcx("CODECODE", this.context, "repl");
which, as far I understand, just copies the global variables to the
new context, and upon eval, doesn't change the original function
definitions - SOOO.. I am just using plain "eval" and IT
WORKS.
Do you have any comments regarding this?
Q3: In order to re-eval a function, it needs to be a GLOBAL function -
Is it bad practice to have all function definitions as global (clojure-like) ? Do you think there is another way to do this?
Actually, swank.js is getting much better, and it is now much easier to set up swank js with your project using NPM. I'm in the process of writing the documentation right now, but the functionality is there!
Check this out http://nodejs.org/api/vm.html
var util = require('util'),
vm = require('vm'),
sandbox = {
animal: 'cat',
count: 2
};
vm.runInNewContext('count += 1; name = "kitty"', sandbox, 'myfile.vm');
console.log(util.inspect(sandbox));
// { animal: 'cat', count: 3, name: 'kitty' }
Should help you a lot, all of the sandbox things for node uses it :) but you can use it directly :)
You might take a look at jsapp.us, which runs JS in a sandbox, and then exposes that to the world as a quick little test server. Here's the jsapp.us github repo.
Also, stop into #node.js and ask questions for a quicker response :)