Using third-party JS libraries in Mozilla Add-On SDK - javascript

I'm starting a new project (Firefox add-on) and I'd like to try using behavior-driven development. I particularly like the Jasmine BDD library. However, I can't find a good way how to use a framework such as Jasmine in the Add-On SDK.
One problem is that Jasmine needs setTimeout (and similar) functions to be specified on the global object, whereas Add-On SDK exports those using "timers" module. But let's say I tweak Jasmine to get those object from "timers" (or add the the methods exported by timers to the global object).
The bigger problem is that I don't know how to actually run the tests. There is a test directory generated by the SDK, however, there's no window or document object there to allow me to see the output (and I'd really like to see the fancy HTML output). I guess I could create a content script that would modify the page, but then I can't access (test) the background script.
Have you ever faced this before? Is there any recommended way how to deal with that?
Thanks!
Tomas

You can use the Add-on SDK windows API to open a new window to run your tests in. You should be able to load the Jasmine script(s) with the subscript loader and set window and document to whatever you want in the scope of that subscript:
var windows = require("windows").browserWindows;
windows.open({
url: "about:blank",
onOpen: function(window) {
var script;
var scriptLoader = Cc["#mozilla.org/moz/jssubscript-loader;1"].
getService(Ci.mozIJSSubScriptLoader);
scriptLoader.loadSubScript(subscriptSpec, script);
script["window"] = window;
script["document"] = window.document;
// ... run your tests here by calling script.someFunc() ...
}
});
Update: Further research shows that the browserWindows are actually special wrappers that don't give you access to the content window. You might try getting a window/document from a hidden frame. That's the only way I can see to get access to an HTML document from privileged code.

Related

Debugging JavaScript code that uses ES6 Modules

TL;DR: How can I access variables/functions/names that are defined in ES Modules from the debugger?
More context: I'm a relatively experienced JavaScript programmer, but new to Modules. I've followed the tutorial at MDN here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules. They have a good set of examples here: https://github.com/mdn/js-examples/tree/master/modules
In that collection, say in the "basic-modules" example, (live code here: https://mdn.github.io/js-examples/modules/basic-modules/) there is, for example, a function called random in the file modules/square.js. Suppose I want to execute that function in the debugger, just to try it out, or because it's my code and I want to test/debug it, or I want to demonstrate to another coder what the function does. All the stuff you expect to do in a REPL or debugger. Is there a way to do that? I've tried both the Firefox debugger and the Chrome debugger, with no luck.
Back in the pre-Modules era, that code would be put into the global namespace (making access easy) or it would be locked up in an IIFE (making access impossible) or maybe in some home-made module system (access depends). I am hoping that the new Modules system still allows the debugger access to the names inside modules.
Thanks.
It says in the docs:
Last but not least, let's make this clear — module features are imported into the scope of a single script — they aren't available in the global scope. Therefore, you will only be able to access imported features in the script they are imported into, and you won't be able to access them from the JavaScript console, for example. You'll still get syntax errors shown in the DevTools, but you'll not be able to use some of the debugging techniques you might have expected to use.
To take your example from before, you'll need to invoke that function from a scope where it is visible, i.e where it's been imported:
import { random } from 'path/to/square.js'
debugger; // you should be able to invoke random() from here

Access Chrome Options in JavaScript (optional: from Galen test)

I am using Galen (a JS tool for testing layout of a HTML page). It is configured from a .js file which can't use ES6 JS :-(
I need to load/amend ChromeOptions from the Chrome driver but I can't figure out how to access it. I see lots of examples of how to set options but when I do so using:
var options = new chrome.Options();
I get an error saying: ReferenceError: "chrome" is not defined
I have tried using require() and load() functions but with the require I get similar not defined errors (ES6 issue I think) and with load I can't seem to point it at a script the works, I've tried:
load("../../npm_modules/selenium-webdriver")
load("../../npm_modules/selenium-webdriver/chrome")
load("chrome")
etc.
It seems that is not the webdriver that Galen is using, but how do I find the one that it IS using?
and is load() what to use to load it?
Galen uses the Rhino JS Engine. Which means that you can directly call Java classes from within the .js file that configures it, thus allowing for an answer like this:
importClass(org.openqa.selenium.chrome.ChromeOptions);
importClass(org.openqa.selenium.chrome.ChromeDriver);
var options = new ChromeOptions();
options.addArguments("--headless");
var driver = new ChromeDriver(options);
Trick is to know how to import the class you need from the Selenium Chrome driver!
Found this on Galen's Google Groups site.
Used the Selenium HQ API, documented on GitHub, for further expansion of what I was doing. HTH.

JavaScript for automation in OSX Yosemite

Can we send a click event to a button inside a webview in Cocoa app using JavaScript?
I am trying to use the script editor under utilities (Yosemite) to record but unfortunately not able to record any events inside the webview.
I tried using the sample code under UI automation section provided in the Apple documentation with the testapp (cocoa app with webview) at https://developer.apple.com/library/mac/releasenotes/InterapplicationCommunication/RN-JavaScriptForAutomation/index.html.
TestApp = Application('TestApp')
TestApp.activate()
delay(1)
SystemEvents = Application('System Events')
TestApp = SystemEvents.processes['TestApp']
TestApp.document.getElementById('testid').click(); // stuck at this last line not sure if I can
//even call the document object in this way. Getting error undefined variable document.
You're trying to use browser/DOM Javascript to access native app UI elements. Although this environment uses Javascript like a browser does, the underlying object model is not the DOM you're used to seeing on a web page. That's why you're seeing that document is undefined.
As implied by the little snippet in the "UI Automation" section of the docs, you need to access the window and button objects. The exact path you'll use depends on your TestApp, of course, but it might look something like:
TestApp.windows[0].buttons[0].click()
(It is probably also possible to scrobble through these arrays by control ID using whose, or the like, but don't have experience with that.)

Exposing almond module to window object fails due to asynchronicity

I am working on a JavaScript project where we use requirejs to manage our code. The product we create is to be used on 3rd party web sites, and therefore we cannot assume that an AMD compatible library is present. To solve this, we include almond in our target file and expose our main module on window. The file created by our build looks like this:
(function() {
//Almond lib
//Our code
define('window-exposer', ['main-module'], function(mainModule) {
window.mainModule = mainModule;
});
require('window-exposer');
}());
When building a site that want to use mainModule an error is thrown because when the site specific code tries to access window.mainModule it has not been set yet. There are also cases where the module has indeed been initialized and the code works.
Is there any way to guarantee that the window-exposer is run before other JavascriptCode is?
I solved it by using the solution provided here https://github.com/jrburke/almond#exporting-a-public-api

using requirejs within a firefox xul extension

I would like to use requirejs to manage my code within a firefox xul plugin, and I can't get it to find my modules.
I know that xul doesn't play nice with the data-main attribute, so I have my main.js script as a second script:
<script src="chrome://myPackage/content/require.js" type="application/x-javascript"></script>
<script src="chrome://myPackage/content/main.js" type="application/x-javascript"></script>
This successfully calls the script, and the require function is available within main.js, but when I run
require(['lib1'], function(lib1){
alert(lib1.val1);
})
the alert never gets popped (lib1 is in the same directory as main.js).
I have tried this within and without setting the baseUrl as
require.config({
baseUrl: "chrome://myPackage/content/"
})
and it does not work either way.
Does anyone know how I can get require.js to look in the right place for my modules?
Addendum **
I added an error handling function and the error code returned is
http://requirejs.org/docs/errors.html#timeout
I have loaded the test module into a normal web page successfully. This seems to confirm that the issue is path configuration (it also takes the 15 second timeout before failing)
Firebug seems to have a working requirejs version. But more importantly, they have a far better mini-require.js that will not pollute the shared global scope when used in overlays (if used correctly :p)
https://github.com/firebug/firebug/blob/master/extension/modules/require.js
https://github.com/firebug/firebug/blob/master/extension/modules/mini-require.js
I suggest you have a look at these implementations and also the code using it.
Proactive warning:
Please note, that if your add-on uses code that defines lots of new properties on the scope in overlays (window) either by defining global functions or variables or implicitly declaring variables within functions, then this may interfere with other code running in the same scope (the browser code itself and other add-ons). Besides, should you want to submit your add-on to addons.mozilla.org, then a reviewer might not give it public status if your add-on "pollutes" the global scope/namespace in the main overlay.

Categories

Resources