Using MozMill for testing standalone XUL applications - javascript

As a follow-up of this question, I am trying MozMill for testing standalone XUL applications (not a firefox extension). However, I did not "get it" yet - more specifically, how to test a XULRunner-based application.
Consider this app, for example. For now, I can run it from command line, more or less this way:
$ /path/to/xulrunner /full/path/to/mozmillexample/application.ini
I would like to write Mozmill scripts to test it. For example, I would like to write a test such as this one, which has as "taste" of unit testing:
Components.utils.import("chrome://mozmillexample/content/example.js", example);
var setupModule = function(module) {
module.controller = mozmill.getBrowserController(); // Or what?
}
var testEquals = function() {
jumlib.assertEqual(example.exHello(), "Hello, World!", "Should be equal");
}
I would like to write some functional tests, too:
Components.utils.import("chrome://mozmillexample/content/example.js", example);
var setupModule = function(module) {
module.controller = mozmill.getBrowserController(); // Or what?
}
var testAlerts = function() {
var button = findElement.Elem(document.getElementById('button'));
button.click();
controller.window.assertAlert(); // I bet it does not exist but it gives the idea...
}
Unfortunately, however, I did not find any documentation about testing standalone apps, at least none explaining the basic steps. So I ask: is it possible to write tests like these ones? How could I do it, if it is possible?

I got it to work with the MozMill extension; unpack the extension and edit the following files:
add this to install.rdf at the right place:
<em:targetApplication>
<Description>
<em:id>mozmill#example.com</em:id>
<em:minVersion>0.9</em:minVersion>
<em:maxVersion>1.1</em:maxVersion>
</Description>
</em:targetApplication>`
create a folder "extensions" in the application's root (where application.ini and the "chrome" and the "defaults" folder are); paste the unpacked mozmill extension there.
Enable the extension manager as described in MDC
embed the MozMill Extension code in your XULRunner app: <script src="chrome://mozmill/content/overlay.js"/>
Enable the extension by adding or modifying %appdata%\Adam Brandizzi\MozMill Example\Profiles\123455.default\extensions.ini:
[ExtensionDirs]
Extension0=C:\Users\John\Desktop\myXULApp\extensions\mozmill
Use the following JS code to open MozMill: MozMill.onMenuItemCommand(event);

Related

Is there a way to replace some javascript variables (at build time?) with some DEV or RELEASE config data?

I have a really simple website (ASP.NET core) that is a single .html static page and 6 .js files.
In one of the js files are some data that is based on my configuration:
localhost
dev
production
right now, it's hardcoded for my localhost.
Is there way that I can build/package the simple app so that if i say dev or prod in some command line arg, it replaces those values with something from somewhere else?
eg.
in main.js:
var environment = "localhost";
var rooturl = "https://localhost:43210";
and lets imagine i wish to build to my dev server...
var environment = "dev";
var rooturl = "https://pewpew.azurewebsites.com";
Is this possible? To keep things simple, assume I know nothing of JS tools and processes. (it's actually the truth, but lets not tell anyone that).
Update (further clarifications):
with 1x static html file and 6x static JS files, I have a static website. So i'm hoping to generate the js files as static files (still) but with the environment data already compiled in it.
you can use some build tools like grunt. where you can define build task which takes the environment parameter and change the variables to the desired values.
another (more simple) way is to dynamicaly create main.js (with dependency on the environment) file with your backend and the frontend will load it when it starts. src of the script tag can be the asp script, where the output is javascript
This is a snippet from a project in which I do just that. I replace various place holders with values stored in the environment variables.
This example is based on a linux environment, so I used sed to modify the file in-place, however you could just as easily read the file into memory, do the replace and write it back to disk.
grunt.task.registerTask('secretkeys', 'Replace various keys', function() {
var oauth;
try{
oauth = JSON.parse(process.env.oauthKeys).oauth;
}
catch(e){
oauth = {google:{}};
}
var replaces = {
'==GOOGLECLIENTID==':oauth.google.client_id || '{**GOOGLECLIENTID**}',
'==GOOGLESECRETKEY==':oauth.google.client_secret || '{**GOOGLESECRETKEY**}',
'==SECRETKEY==':oauth.secret || '{**SECRETKEY**}',
'==LOCALAUTH==':oauth.login,
};
const child = require('child_process');
grunt.file.expand('bin/**/*.json').forEach(function(file) {
grunt.log.write(`${file} \n`);
for(var key in replaces){
var cmd = 'sed -i s~{{orig}}~{{new}}~g {{file}}'
.replace(/{{file}}/g,file)
.replace(/{{orig}}/g,key.replace(/~/g,'\\~'))
.replace(/{{new}}/g,replaces[key].replace(/~/g,'\\~'))
;
grunt.log.write(` - ${key} \n`);
//grunt.log.write(` ${cmd} \n`);
child.execSync(cmd);
}
});
});
Hopefully you can modify to your purposes.
EDIT : I am reconsidering my answer, you are modifying javascript on a windows environment. You are likely better using PowerShell
(gc script.js) `
.replace("==GOOGLECLIENTID==",$Env:GoogleClientId) `
.replace("==SECRETKEY==",$Env:SecretKey) `
> script-build.js
So after re-reading your question, I realize there is a better solution that I have used in the past. My other answer is still relevant, so I'll leave it.
It may be simplest to just create a config file in the same folder.
<html>
<head>
<script type="text/javascript" src="config.js" ></script>
<script type="text/javascript" src="myscript.js" ></script>
</head>
<body>
ask me your questions, bridgekeeper
</body>
</html>
config.js
var config = {
'colour': 'yellow'
};
myscript.js
var user = prompt("What is your favourite colour?", "");
if(user !== config.colour){
alert("No BLUE! Ahhh....");
}
else{
alert("You may pass");
}
This is the technique I use when developing simple HTA apps for use around the office.
Check out envify. You can run it from the command line. https://github.com/hughsk/envify
sudo npm install -g envify
Say you have
var myVar = process.env.MYVAR;
Run from the command line
MYVAR=somevalue envify input.js > output.js
and the output js file should have
var myVar = 'somevalue';

How to probe if a file was download using Selenium/WebdriverIO

I want to know how I can verify if a file was downloaded using Selenium Webdriver after I click the download button.
Your question doesn't say whether you want to confirm it locally or remotely(like browserstack) . If it is remotely then my answer will be "NO" as you can see that the file is getting downloaded but you can not access the folder. So you wont be able to assert that the file has been downloaded.
If you want to achieve this locally(in Chrome) then the answer is "YES", you can do it something like this:
In wdio.conf.js(To know where it is getting downloaded)
var path = require('path');
const pathToDownload = path.resolve('chromeDownloads');
// chromeDownloads above is the name of the folder in the root directory
exports.config = {
capabilities: [{
maxInstances: 1,
browserName: 'chrome',
os: 'Windows',
chromeOptions: {
args: [
'user-data-dir=./chrome/user-data',
],
prefs: {
"download.default_directory": pathToDownload,
}
}
}],
And your spec file(To check if the file is downloaded or not ?)
const fsExtra = require('fs-extra');
const pathToChromeDownloads = './chromeDownloads';
describe('User can download and verify a file', () =>{
before(() => {
// Clean up the chromeDownloads folder and create a fresh one
fsExtra.removeSync(pathToChromeDownloads);
fsExtra.mkdirsSync(pathToChromeDownloads);
});
it('Download the file', () =>{
// Code to download
});
it('Verify the file is downloaded', () =>{
// Code to verify
// Get the name of file and assert it with the expected name
});
});
more about fs-extra : https://www.npmjs.com/package/fs-extra
Hope this helps.
TL;DR: Unless your web-app has some kind of visual/GUI trigger once the download finishes (some text, an image/icon-font, push-notification, etc.), then the answer is a resounding NO.
Webdriver can't go outside the scope of your browser, but your underlying framework can. Especially if you're using NodeJS. :)
Off the top of my head I can think of a few ways I've been able to do this in the past. Choose as applicable:
1. Verify if the file has been downloaded using Node's File System (aka fs)
Since you're running WebdriverIO, under a NodeJS environment, then you can make use its powerful lib tool-suite. I would use fs.exists, or fs.existsSync to verify if the file is in the expected folder.
If you want to be diligent, then also use fs.statSync in conjunction with fs.exists & poll the file until it has the expected size (e.g.: > 2560 bytes)
There are multiple examples online that can help you put together such a script. Use the fs documentation, but other resources as well. Lastly, you can add said script inside your it/describe statement (I remember your were using Mocha).
2. Use child_process's exec command to launch third-party scripts
Though this method requires more work to setup, I find it more relevant on the long run.
!!! Caution: Apart from launching the script, you need to write a script in a third-party framework.
Using an AutoIT script;
Using a Sikuli script;
Using a TestComplete (not linking it, I don't like it that much), or [insert GUI verification script here] script;
Note: All the above frameworks can generate an .exe file that you can trigger from your WebdriverIO test-cases in order to check if your file has been downloaded, or not.
Steps to take:
create one of the stand-alone scripts like mentioned above;
place the script's .exe file inside your project in a known folder;
use child_process.exec to launch the script and assert its result after it finishes its execution;
Example:
exec = require('child_process').exec;
// Make sure you also remove the .exe from scriptName
var yourScript = pathToScript + scriptName;
var child = exec(yourScript);
child.on('close', function (code, signal) {
if (code!==0) {
callback.fail(online.online[module][code]);
} else {
callback();
}
});
Finally: I'm sure there are other ways to do it. But, your main take-away from such a vague question should be: YES, you can verify if the file has been downloaded if you absolutely must, expecially if this test-case is CRITICAL to your regression-run.

Webdriver.io crashes with NoSessionIdError

I'm trying to get webdriver.io and Jasmine working.
Following their example, my script is at test/specs/first/test2.js (in accordance with the configuration) and contains:
var webdriverio = require('webdriverio');
describe('my webdriverio tests', function() {
var client = {};
jasmine.DEFAULT_TIMEOUT_INTERVAL = 9999999;
beforeEach(function() {
client = webdriverio.remote({ desiredCapabilities: {browserName: 'firefox'} });
client.init();
});
it('test it', function(done) {
client
.url("http://localhost:3000/")
.waitForVisible("h2.btn.btn-primary")
.click("h2.btn.btn-primary")
.waitForVisible("h2.btn.btn-primary")
.call(done);
});
afterEach(function(done) {
client.end(done);
});
});
I'm using wdio as the test runner, and set it up using the interactive setup. That config is automatically-generated and all pretty straightforward, so I don't see a need to post it.
In another terminal window, I am running selenium-server-andalone-2.47.1.jar with Java 7. I do have Firefox installed on my computer (it blankly starts when the test is run), and my computer is running OS 10.10.5.
This is what happens when I start the test runner:
$ wdio wdio.conf.js
=======================================================================================
Selenium 2.0/webdriver protocol bindings implementation with helper commands in nodejs.
For a complete list of commands, visit http://webdriver.io/docs.html.
=======================================================================================
[18:17:22]: SET SESSION ID 46731149-79aa-412e-b9b5-3d32e75dbc8d
[18:17:22]: RESULT {"platform":"MAC","javascriptEnabled":true,"acceptSslCerts":true,"browserName":"firefox","rotatable":false,"locationContextEnabled":true,"webdriver.remote.sessionid":"46731149-79aa-412e-b9b5-3d32e75dbc8d","version":"40.0.3","databaseEnabled":true,"cssSelectorsEnabled":true,"handlesAlerts":true,"webStorageEnabled":true,"nativeEvents":false,"applicationCacheEnabled":true,"takesScreenshot":true}
NoSessionIdError: A session id is required for this command but wasn't found in the response payload
at waitForVisible("h2.btn.btn-primary") - test2.js:21:14
/usr/local/lib/node_modules/webdriverio/node_modules/q/q.js:141
throw e;
^
NoSessionIdError: A session id is required for this command but wasn't found in the response payload
0 passing (3.90s)
$
I find this very strange and inexplicable, especially considering that it even prints the session ID.
Any ideas?
Please check out the docs on the wdio test runner. You don't need to create an instance using init on your own. The wdio test runner takes care on creating and ending the session for you.
Your example covers the standalone WebdriverIO usage (without testrunner). You can find examples which use wdio here.
To clarify that: there are two ways of using WebdriverIO. You can embed it in your test system by yourself (using it as standalone / or as a scraper ). Then you need to take care of things like create and end an instance or run those in parallel. The other way to use WebdriverIO is using its test runner called wdio. The testrunner takes a config file with a bunch of information on your test setup and spawns instances updates job information on Sauce Labs and so on.
Every Webdriver command gets executed asynchronously.
You properly called the done callback in afterEach and in your test it test, but forgot to do it in beforeEach:
beforeEach(function(done) {
client = webdriverio.remote({ desiredCapabilities: {browserName: 'firefox'} });
client.init(done);
});

Pull an HTML file into a TinyTest

TinyTest seems to be concerned only with unit testing; however, may Meteor packages have UI elements, and it would be helpful to pull in a pre-crafted HTML file that exercises a widget. For instance, we might want to transform a <table> into a grid with DataTables.net, then test if the instantiation was correct.
How can external HTML files be used in a TinyTest?
package.js:
Package.onTest(function (api) {
api.use(packageName, where);
api.use(['tinytest', 'http'], where);
// TODO we should just bring in src/test.html - but how to do that with TinyTest?
api.addFiles('src/test.html', where); // this won't magically display the HTML anywhere
api.addFiles('meteor/test.js', where);
});
test.js:
Tinytest.addAsync('Visual check', function (test, done) {
var iconsDropZone = document.createElement('div');
document.body.appendChild(iconsDropZone);
// TODO ideally we'd get src/test.html straight from this repo, but no idea how to do this from TinyTest
HTTP.get('https://rawgit.com/FortAwesome/Font-Awesome/master/src/test.html', function callback(error, result) {
if (error) {
test.fail('Error getting the icons. Do we have an Internet connection to rawgit.com?');
} else {
iconsDropZone.innerHTML = result.content;
test.ok({message: 'Test passed if the icons look OK.'});
}
done();
});
});
I personally think TinyTest is not the right tool for the job! You may get away with finding out how to include the Asset package or writing your own file loader, but you'll soon face the problem of needing to query the DOM in your tests.
Here are some options I can think of:
Option 1:
You can get access to a fully rendered page by using xolvio:webdriver. If you include this package in your onTest block, then you should have access to wdio in your TinyTest tests. I say should as I don't use TinyTest at all but I designed the webdriver package to be usable by any framework. Follow the instructions on the package readme and then do something like this:
browser.
init().
url('https://rawgit.com/FortAwesome/Font-Awesome/master/src/test.html').
getSource(function(err, source) {
// you have a fully rendered source here and can compare to what you like
}).
end();
It's a heavyweight option but might be suitable for you.
Option 2:
If you're willing to move away from TinyTest, another option is to use Jasmine. It supports client unit testing so you can load up the unit that does the visuals and isolate it with a unit test.
Option 3:
You can create a test app around your package. So you would have:
/package
/package/src
/package/example
/package/example/main.html
/package/example/tests
/package/example/tests/driver.js
And now the example directory is a Meteor app. In main.html you would use your package and under tests directory you can use the framework of your choice (jasmine/mocha/cucumber) in combination with webdriver. I like this pattern for package development as you can test the package as it is intended to be used by apps.

JavaScript Build system using Node.js error in Sublime Text 2

I'm using Node.js to make a build system in Sublime Text 2 to build JavaScript code. I know how to setup basic build systems in Sublime, but this one is really giving me problems.
JavaScript example code:
var end = 10;
for (var i = 0; i < end; i++) {
console.log("hello world!");
};
1st try:
{
"cmd": ["node", "$file"]
}
returned this in the console: [Finished in 0.1s]
2nd try:
{
"cmd": ["node", "$file", "$file_base_name"],
"working_dir": "${project_path:${folder}}",
"selector": "#.js"
}
returns the same thing.
Any help would be much appreciated (I've spend over 2 hours searching google).
EDIT: Fixed For to for : Same result.
Here's a Javascript build system I use on my Mac with Sublime Text. It uses the Webkit engine (SquirrelFish) which comes with OS X, and therefore doesn't require anything special be installed (not even Node.js):
{
"cmd": ["/System/Library/Frameworks/JavaScriptCore.framework/Versions/Current/Resources/jsc", "$file"],
"selector": "source.js"
}
Tips:
Use "print(foo)" from within your script to return results to the Sublime console
Save your .js file to disk at least once
If ".js" files are not automatically selected, ensure you have no other build systems for ".js" in "~/Library/Application Support/Sublime Text 2/Packages/". Alternately you can manually select the appropriate system from "Tools > Build System"
Hope this helps.
In Sublime Text 2 you must save your .js file before you build, or the result above will happen.
Simple fix is to save the file (obviously)!

Categories