Search code examples
angularjsscalasbtrhino

How to configure rhino to run jasmine tests for angularjs controllers


I am having trouble getting unit tests working for an Angular JS app using Jasmine sbt plugin.

when I add angular.js ( ver 1.3.1) to test.dependecies.js

EnvJasmine.loadGlobal(EnvJasmine.libDir + "/angular.js");
EnvJasmine.loadGlobal(EnvJasmine.libDir + "/ui-bootstrap-0.11.2.js");
EnvJasmine.loadGlobal(EnvJasmine.testDir + "/lib/angular-mocks.js");

I got the following error

[ Envjs/1.6 (Rhino; U; Linux amd64 3.13.0-32-generic; en-US; rv:1.7.0.rc2) Resig/20070309 PilotFish/1.2.13 ] Could not read file: /opt/scala/myproject/src/main/webapp/static/js/lib/angular.js error was: TypeError: Cannot find function querySelector in object [object HTMLDocument].

I cant figure if there is a compatibility issue with angular and rhino or in jasmine config


Solution

  • Use a maintained project such as Domino:

    Domino is based on work by Mozilla's Andreas Gal and appears to be currently maintained. While it didn't work out of the box, it was easy to patch. The modifications which I made were as follows:

        Change files to use AMD style loading instead of CommonJS (so I can load them in Rhino and the browser using RequireJS)
        Add xmlns attribute to SVG element when serializing
        Modified the CSS parser to workaround a issue in Rhino with case insensitive regular expressions
        Added a SVG element type which has a style property like the HTML elements
        Added SVG specific CSS properties to the CSS parser
        Several bug fixes
    
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.FileNotFoundException;
    import java.io.IOException;
    import java.io.InputStreamReader;
    import java.io.Reader;
    
    import org.apache.commons.logging.Log;
    import org.apache.commons.logging.LogFactory;
    import org.mozilla.javascript.Context;
    import org.mozilla.javascript.Scriptable;
    import org.mozilla.javascript.ScriptableObject;
    import org.mozilla.javascript.tools.shell.Global;
    
    import com.google.common.base.Charsets;
    
    public abstract class RunJS {
        static final Log LOG = LogFactory.getLog(RunJS.class);
    
        static final int JS_VERSION = Context.VERSION_1_8;
        static final int OPTIMIZATION_LEVEL = 9;
    
        private static ScriptableObject ENVIRONMENT = null;
    
        static {
            ENVIRONMENT = createNewEnvironment();
        }
    
        /**
         * Creates a top level scope with the shell globals and requirejs then loads
         * bootstrap.js
         * 
         * The bootstrap script can then load other modules to be included in the top level
         * scope using requirejs
         */
        public static ScriptableObject createNewEnvironment() {
            Global global = null;
    
            Context cx = Context.enter();
            try {
                cx.setOptimizationLevel(OPTIMIZATION_LEVEL);
                cx.setLanguageVersion(JS_VERSION);
    
                global = new Global();
                global.setSealedStdLib(true);
                global.init(cx);
    
                Scriptable argsObj = cx.newArray(global, new Object[] {});
                global.defineProperty("arguments", argsObj, ScriptableObject.DONTENUM);
    
                // Enable RequireJS
                loadJS(cx, global, "/path/to/r.js");
    
                // Load the bootstrap file
                loadJS(cx, global, "/path/to/bootstrap.js");
    
                global.sealObject();
            } catch (Exception e) {
                LOG.error("Error setting up Javascript environment", e);
            }
            finally {
                Context.exit();
            }
            return global;
        }
    
        public static void loadJS(Context cx, Scriptable scr, String fileName) throws Exception {
            Reader reader;
            try {
                reader = new InputStreamReader(new FileInputStream(new File(fileName)), Charsets.UTF_8);
            } catch (FileNotFoundException e) {
                throw new Exception("Could not find file", e);
            };
    
            try {
                cx.evaluateReader(scr, reader, fileName, 0, null);
            } catch (IOException e) {
                throw new Exception("IO error reading file", e);
            }
            finally {
                try { reader.close(); } catch (IOException e) {
                    throw new Exception("IO error closing file", e);
                }
            }
        }
    
        protected static Scriptable getScope(Context cx) {
            Scriptable scope = cx.newObject(RunJS.ENVIRONMENT);
            scope.setPrototype(RunJS.ENVIRONMENT);
            scope.setParentScope(null);
            return scope;
        }
    }
    
    boostrap.js
    
    require.config({
        baseUrl: '/base/path/to/packages'
    });
    
    var window, document, d3;
    
    require(['domino/index'], function(domino) {
        window = domino.createWindow('');
        document = window.document;
    
        require(['d3/d3'], function(_d3) {
            d3 = _d3;
        });
    });
    
    // preload your modules
    require(["mypackage/mymodule1", "mypackage/mymodule2"]);
    
    Subclass RunJS and load your JavaScript file like this:
    
    Context cx = Context.enter();
    try {
        cx.setOptimizationLevel(OPTIMIZATION_LEVEL);
        cx.setLanguageVersion(JS_VERSION);
    
        Scriptable scope = getScope(cx);
        scope.put("myvar", scope, myvar);
        loadJS(cx, scope, "/path/to/yourcode.js");
    }
    catch (Exception e) {
        LOG.error(e);
    }
    finally {
        Context.exit();
    }
    

    References