How to automate desktop application developed using electron framework? - javascript

Our application is developed using electron framework. it is a standalone application. I have seen that spectron is the framework which is used to automate electron application. but i am not sure whether it is applicable for desktop application. Please confirm the same.
I have installed nodejs and spectron.
I have written a code launch application as mention in the following site
https://electron.atom.io/spectron/
File Name : First.js
var Application = require('spectron').Application
var assert = require('assert')
var app = new Application({
path: 'C:\Users\ramass\AppData\Local\Programs\ngsolutions\ngsolutions.exe'
})
app.start().then(function () {
// Check if the window is visible
return app.browserWindow.isVisible()
}).then(function (isVisible) {
// Verify the window is visible
assert.equal(isVisible, true)
}).then(function () {
// Get the window's title
return app.client.getTitle()
}).then(function (title) {
// Verify the window's title
assert.equal(title, 'My App')
}).then(function () {
// Stop the application
return app.stop()
}).catch(function (error) {
// Log any failures
console.error('Test failed', error.message)
})
i have tried to run the script using command
node First.js
But i am getting error saying that
C:\spectronprgs>node First.js
Error: Cannot find module 'spectron'
Please let me know whether I am going towards right path
how to launch .exe file using spectron framework
how to run the script

run the following from the command line.
npm install --save-dev spectron
Then see if you can find the module. You never mentioned in your post how you installed spectron.

Related

can't load chrome driver with selenium, in the firebase cloud functions

im trying use the chrome driver, with selenium in the firebase cloud functions.
while deploying the index.js file on to a local host, using the terminal cmd
'firebase serve --only functions' from the functions folder(which has the chromedriver file, every thing work like in supposed to, im getting a response.
But,
when I deploying the index.js file to the firebase real servers using the
'firebase deploy --only functions' ,
and then trigger the function from my app, or from a url,
im getting an error in the firebase cloud functions logs telling me
'Function execution took 1774 ms, finished with status: 'crash' '
so since there were not details about what was causing this 'crash' I uses the consoled.log() function, and printed each line that was executed successfully.
this lead me into the line of
let driver = await new Builder().forBrowser('chrome').setChromeOptions(new chrome.Options().headless().windowSize(screen)).build();
its seems like in the firebase cloud function I can't for some reason create a chrome driver successfully , although in the local host version, it's working as expected.
here the full code of the function:
exports.initializedChromeDriver = functions.https.onRequest((request, response) => {
async function start_chrome_driver() {
functions.logger.info('Hello logs!', {structuredData: true});
console.log("did enter the function")
const dic = {};
const google_site = "https://www.gooogle.com";
const { WebDriver } = require('selenium-webdriver');
const {Builder, By} = require('selenium-webdriver');
console.log("did creat WebDriver,Builder, By, constans")
const chrome = require('selenium-webdriver/chrome');
console.log("chrome constans was created")
const screen = {
width: 1024,
height: 1024
};
let driver = await new Builder().forBrowser('chrome').setChromeOptions(new chrome.Options().headless().windowSize(screen)).build();
console.log("driver was set");
await driver.get(google_site);
console.log("succ loading google");
return "succ loading google"
}
const p = start_chrome_driver().then((value,reject) => {
dic['status'] = 200;
dic['data'] = {"message": value};
response.send(dic);
});
and here are the logs in the firebase cloud console:
UPDATE
well after searching for answers in the web, ,i found that I didn't have a suitable 'driver' for linux systems,
so I replace the chrome driver for mac(which work on my machine, on the local host version),
with a chrome driver, for linux. and try again, well that doesn't work either , but at lest I was getting a new log with an Error, not just a 'crash' , here it his:
so now I know that I need to install the chrome browser binary for linux on the project,
any ideas to how can I do this, Im trying to install the chrome binary driver on to my project in firebase, there a few ways im trying now, like installing the chrome binary using the google shell some how, any help or idea to I do does, even so, I don't sure that after the binary will be install , this will be it, and the driver will work on the firebase servers..

Can't Require Node Modules In WebWorker (NWJS)

I'm trying to do something I thought would be simple. I'm using nwjs (Formerly called Node-Webkit) which if you don't know basically means I'm developing a desktop app using Chromium & Node where the DOM is in the same scope as Node. I want to offload work to a webworker so that the GUI doesn't hang when I send some text off to Ivona Cloud (using ivona-node) which is a text to speech API. The audio comes back in chunks as it's generated and gets written to an MP3. ivona-node uses fs to write the mp3 to the drive. I got it working in the dom but webworkers are needed to not hang the UI. So I have two node modules I need to use in the webworker, ivona-node and fs.
The problem is that in a webworker you can't use require. So I tried packaging ivona-node and fs with browserify (There's a package called browserify-fs for this which I used) and replacing require with importScripts(). Now I'm getting var errors in the node modules.
Note: I don't think the method of native_fs_ will work for writing the mp3 to disk in chunks (The stream) as it should be and I'm getting errors in the Ivona package as well (Actually first and foremost) that I don't know how to fix. I'm including all information to reproduce this.
Here's an error I'm getting in the console: Uncaught SyntaxError: Unexpected token var VM39 ivonabundle.js:23132
Steps to reproduce in NWJS:
npm install ivona-node
npm install browserify-fs
npm install -g browserify
Now I browserified main.js for ivona-node and index.js for browserify-fs:
browserify main.js > ivonabundle.js
browserify index.js > fsbundle.js
package.json...
{
"name": "appname",
"description": "appdescr",
"title": "apptitle",
"main": "index.html",
"window":
{
"toolbar": true,
"resizable": false,
"width": 800,
"height": 500
},
"webkit":
{
"plugin": true
}
}
index.html...
<html>
<head>
<title>apptitle</title>
</head>
<body>
<p><output id="result"></output></p>
<button onclick="startWorker()">Start Worker</button>
<button onclick="stopWorker()">Stop Worker</button>
<br><br>
<script>
var w;
function startWorker() {
if(typeof(Worker) !== "undefined") {
if(typeof(w) == "undefined") {
w = new Worker("TTMP3.worker.js");
w.postMessage(['This is some text to speak.']);
}
w.onmessage = function(event) {
document.getElementById("result").innerHTML = event.data;
};
} else {
document.getElementById("result").innerHTML = "Sorry! No Web Worker support.";
}
}
function stopWorker() {
w.terminate();
w = undefined;
}
</script>
</body>
</html>
TTMP3.worker.js...
importScripts('node_modules/browserify-fs/fsbundle.js','node_modules/ivona-node/src/ivonabundle.js');
onmessage = function T2MP3(Text2Speak)
{
postMessage(Text2Speak.data[0]);
//var fs = require('fs'),
// Ivona = require('ivona-node');
var ivona = new Ivona({
accessKey: 'xxxxxxxxxxx',
secretKey: 'xxxxxxxxxxx'
});
//ivona.listVoices()
//.on('end', function(voices) {
//console.log(voices);
//});
// ivona.createVoice(text, config)
// [string] text - the text to be spoken
// [object] config (optional) - override Ivona request via 'body' value
ivona.createVoice(Text2Speak.data[0], {
body: {
voice: {
name: 'Salli',
language: 'en-US',
gender: 'Female'
}
}
}).pipe(fs.createWriteStream('text.mp3'));
postMessage("Done");
}
There are two things that I wan to point out first:
Including node modules in a web worker
In order to include the module ivona-node I had to change a little its code. When I try to browserify it I get an error: Uncaught Error: Cannot find module '/node_modules/ivona-node/src/proxy'. Checking the bundle.js generated I notice that it doesn't include the code of the module proxy which is in the file proxy.js in the src folder of ivona-node. I can load the proxy module changing this line HttpsPA = require(__dirname + '/proxy'); by this: HttpsPA = require('./proxy');. After that ivona-node can be loaded in the client side through browserify. Then I was facing another error when trying to follow the example. Turn out that this code:
ivona.createVoice(Text2Speak.data[0], {
body: {
voice: {
name: 'Salli',
language: 'en-US',
gender: 'Female'
}
}
}).pipe(fs.createWriteStream('text.mp3'));
is no longer correct, it cause the error: Uncaught Error: Cannot pipe. Not readable. The problem here is in the module http. the module browserify has wrapped many built-in modules of npm, which mean that they are available when you use require() or use their functionality. http is one of them, but as you can reference here: strem-http, It tries to match node's api and behavior as closely as possible, but some features aren't available, since browsers don't give nearly as much control over requests. Very significant is the fact of the class http.ClientRequest, this class in nodejs environment create an OutgoingMessage that produce this statement Stream.call(this) allowing the use of the method pipe in the request, but in the browserify version when you call https.request the result is a Writable Stream, this is the call inside the ClientRequest: stream.Writable.call(self). So we have explicitly a WritableStream even with this method:
Writable.prototype.pipe = function() {
this.emit('error', new Error('Cannot pipe. Not readable.'));
};
The responsible of the above error. Now we have to use a different approach to save the data from ivona-node, which leave me to the second issue.
Create a file from a web worker
Is well know that having access to the FileSystem from a web application have many security issues, so the problem is how we can have access to the FileSystem from the web worker. One first approach is using the HTML5 FileSystem API. This approach has the inconvenient that it operate in a sandbox, so if we have in a desktop app we want to have access to the OS FileSystem. To accomplish this goal we can pass the data from the web worker to the main thread where we can use all the nodejs FileSystem functionalities. Web worker provide a functionality called Transferable Objects, you can get more info here and here that we can use to pass the data received from the module ivona-node in the web worker to the main thread and then use require('fs') in the same way that node-webkit provide us. These are the step you can follow:
install browserify
npm install -g browserify
install ivona-node
npm install ivona-node --save
go to node_modules/ivona-node/src/main.js and change this line:
HttpsPA = require(__dirname + '/proxy');
by this:
HttpsPA = require('./proxy');
create your bundle.js.
Here you have some alternatives, create a bundle.js to allow a require() or put some code in a file with some logic of what you want (you can actually include all the code of the web worker) and then create the bundle.js. In this example I will create the bundle.js only for have access to require() and use importScripts() in the web worker file
browserify -r ivona-node > ibundle.js
Put all together
Modify the code of the web worker and index.html in order to receive the data in the web worker and send it to the main thread (in index.html)
this is the code of web worker (MyWorker.js)
importScripts('ibundle.js');
var Ivona = require('ivona-node');
onmessage = function T2MP3(Text2Speak)
{
var ivona = new Ivona({
accessKey: 'xxxxxxxxxxxx',
secretKey: 'xxxxxxxxxxxx'
});
var req = ivona.createVoice(Text2Speak.data[0], {
body: {
voice: {
name: 'Salli',
language: 'en-US',
gender: 'Female'
}
}
});
req.on('data', function(chunk){
var arr = new Uint8Array(chunk);
postMessage({event: 'data', data: arr}, [arr.buffer]);
});
req.on('end', function(){
postMessage(Text2Speak.data[0]);
});
}
and index.html:
<html>
<head>
<title>apptitle</title>
</head>
<body>
<p><output id="result"></output></p>
<button onclick="startWorker()">Start Worker</button>
<button onclick="stopWorker()">Stop Worker</button>
<br><br>
<script>
var w;
var fs = require('fs');
function startWorker() {
var writer = fs.createWriteStream('text.mp3');
if(typeof(Worker) !== "undefined") {
if(typeof(w) == "undefined") {
w = new Worker("MyWorker.js");
w.postMessage(['This is some text to speak.']);
}
w.onmessage = function(event) {
var data = event.data;
if(data.event !== undefined && data.event == 'data'){
var buffer = new Buffer(data.data);
writer.write(buffer);
}
else{
writer.end();
document.getElementById("result").innerHTML = data;
}
};
} else {
document.getElementById("result").innerHTML = "Sorry! No Web Worker support.";
}
}
function stopWorker() {
w.terminate();
w = undefined;
}
</script>
</body>
</html>

How can I setup a testing environment for testing with selenium and phantomjs?

I am trying to setup environment for headless testing using Selenium and PhantomJS.
Setting UP phantomjs:
I have made a folder c:/phantomjs and put all the phantomjs script files there (after downloading).
Then I created a folder C:\xampp\htdocs\testPhantomJS
Now I installed nodeJS in my system.
Then I traversed to the C:\xampp\htdocs\testPhantomJS in the command prompt and installed phantomJS like this:
C:\xampp\htdocs\testPhantomJS>npm install -g phantomjs
The image states a different location. Thats because it was taken from my colleague's computer. We both are working on same installation, and he sent me the image for reference. That's why its different with my folder location, but the location I stated, it is the one I worked on.
Now on typing phantomjs on command prompt, when we are typing
C:\xampp\htdocs\testPhantomJS>phantomjs
phantom>
Setting Up Selenium-Webdriver
I traversed to C:\xampp\htdocs\testPhantomJS in the command prompt and installed selenium webdriver like this:
C:\xampp\htdocs\testPhantomJS>npm install selenium-webdriver
After installation, the folder structure is like this:
Now I have a test-script test.js which is like this:
describe('Test example.com', function(){
before(function(done) {
client.init().url('http://google.com', done);
});
describe('Check homepage', function(){
it('should see the correct title', function(done) {
client.getTitle(function(err, title){
expect(title).to.have.string('Example Domain');
done();
});
});
it('should see the body', function(done) {
client.getText('p', function(err, p){
expect(p).to.have.string(
'for illustrative examples in documents.'
);
done();
})
});
});
after(function(done) {
client.end();
done();
});
});
The problem is, where should I put the above script, and how shall I run it?
I just don't need to run using the phantomjs only, I need to test with both phantomjs and selenium.
This solution is coming from this pretty neat tutorial on how to setup testing with selenium and phantomjs: http://code.tutsplus.com/tutorials/headless-functional-testing-with-selenium-and-phantomjs--net-30545
Here is some of the tutorial below:
Combining Everything
Now that we have all the pieces, we have to put everything together.
Remember: before running any tests, you have to run Selenium Server:
1
java -jar selenium-server-standalone-2.28.0.jar
Selenium will run PhantomJS internally; you don't have to worry about that.
Now, we need to connect to Selenium from our JavaScript. Here's a sample snippet, which will initiate a connection to Selenium and have a ready object to control our Selenium instance:
// Use webdriverjs to create a Selenium Client
var client = require('webdriverjs').remote({
desiredCapabilities: {
// You may choose other browsers
// http://code.google.com/p/selenium/wiki/DesiredCapabilities
browserName: 'phantomjs'
},
// webdriverjs has a lot of output which is generally useless
// However, if anything goes wrong, remove this to see more details
logLevel: 'silent'
});
client.init();
Now, we can describe our tests and use the client variable to control the browser.
A full reference for the webdriverjs API is available in the documentation, but here's a short example:
client.url('http://example.com/')
client.getTitle(function(title){
console.log('Title is', title);
});
client.setValue('#field', 'value');
client.submitForm();
client.end();
Let's use the Mocha and Chai syntax to describe a test; we'll test some properties of the example.com web page:
describe('Test example.com', function(){
before(function(done) {
client.init().url('http://example.com', done);
});
describe('Check homepage', function(){
it('should see the correct title', function(done) {
client.getTitle(function(title){
expect(title).to.have.string('Example Domain');
done();
});
});
it('should see the body', function(done) {
client.getText('p', function(p){
expect(title).to.have.string(
'for illustrative examples in documents.'
);
done();
})
});
});
after(function(done) {
client.end();
done();
});
});
You might want to share one client initialization over many test files. Create a small Node module to initialize and import it into every test file:
client.js:
exports.client = require('webdriverjs').remote({
// Settings
};
test.js:
var client = require('./client').client;
var expect = require('chai').expect;
// Perform tests
EDIT based on the question in the comments:
Here is how to install the selenium server, and yes you need to do it.
Selenium
Download Selenium Server. It is distributed as a single jar file, which you run simply:
java -jar selenium-server-standalone-2.28.0.jar
As soon as you execute this command, it boots up a server to which your testing code will connect later on. Please note that you will need to run Selenium Server every time that you run your tests.

Grunt - no image library that works. All are silently failing

I'm grunt beginner. But whenever I install any kind of grunt library to handle images it does not work.
grunt-webshot, webshot, getPixels, node-image, node, gm, node-pngjs, imagemagick, node-png, png, get-pixels
grunt.registerTask("getPixels", "your description", function() {
var fs = require('fs') , gm = require('gm');
gm('source/templates/t1/images/menu_item_bg.png').size(function (err, size) {
grunt.log.writeln(size.width > size.height ? 'wider' : 'taller than you');
});
});
Silently fails. No error, no nothing (I get: Done, without errors). Does not enter callback.
Same is with other libraries I used.
Only grunt modules can be used in grunt? Dont Think so, it seems i can use any library by using require() and it should work. It works ok with require('path')
Any way I can debug it? Make it return some kind of error or fix this problem?
Edit
I wrote a makescreenshot.js script which I call with node
var webshot = require('webshot');
// also tried commented varians:
//webshot('google.com', 'google.jpg', function(err) {
//webshot('http://google.com', 'google.jpg', function(err) {
webshot('http://google.com', 'google.jpg', {}, function(err) {
console.log('console.log ERROR: ' + err);
});
It returns the following: console.log ERROR: Error: PhantomJS exited with return value 1
Seems I figured it somehow. The problem seemed to be not properly installed Microsoft Visual Studio I reinstalled MSVS 2013 Express and it started taking screens normally.

Restart a node.js app from code level

I've an app which initially creates static config files (once) and after files were written I need to reinitialize/restart the application.
Is there something to restart a node.js app from itself?
This is required cause I've an application running in two runlevels in node.js.
The initial one starts completly synchronus and after this level has been completed app is in async runlevel in a previously started environment.
I know there are tools like nodemon but that's not what I need in my case.
I tried to kill the app via process.kill() which is working but I can't listen to the kill event:
// Add the listener
process.on('exit', function(code) {
console.log('About to exit with code:', code);
// Start app again but how?
});
// Kill application
process.kill();
Or is there a better, cleaner way to handle this?
Found a working case to get node.js restarted from app itself:
Example:
// Optional part (if there's an running webserver which blocks a port required for next startup
try {
APP.webserver.close(); // Express.js instance
APP.logger("Webserver was halted", 'success');
} catch (e) {
APP.logger("Cant't stop webserver:", 'error'); // No server started
APP.logger(e, 'error');
}
// First I create an exec command which is executed before current process is killed
var cmd = "node " + APP.config.settings.ROOT_DIR + 'app.js';
// Then I look if there's already something ele killing the process
if (APP.killed === undefined) {
APP.killed = true;
// Then I excute the command and kill the app if starting was successful
var exec = require('child_process').exec;
exec(cmd, function () {
APP.logger('APPLICATION RESTARTED', 'success');
process.kill();
});
}
The only con I can see here is to loose outputs on console but if anything is logged into logfiles it's not a problem.

Categories

Resources