简体   繁体   中英

RequireJS module shim not working when testing via Jasmine

I have a JavaEE project that uses RequireJS to load a few third party frameworks. One of those frameworks is OpenLayers3. Openlayers3 natively creates a global "ol" variable. However, OpenLayers3 is written to be AMD compatible and works as a module through RequireJS. I also am using an OpenLayers3 plugin called "olLayerSwitcher" which is not optimized for AMD. Instead, it depends on the "ol" variable being global.

My require config looks like the following:

paths: {
    "sinon": ['/webjars/sinonjs/1.7.3/sinon'],
    "jquery": ["/webjars/jquery/2.1.4/jquery"],
    "backbone": ['/webjars/backbonejs/1.2.1/backbone'],
    "underscore": ['/webjars/underscorejs/1.8.3/underscore'],
    "text": ['/webjars/requirejs-text/2.0.14/text'],
    "log4js": ['/webjars/log4javascript/1.4.13/log4javascript'],
    "ol": ['/webjars/openlayers/3.5.0/ol'],
    "olLayerSwitcher": ['/js/vendor/ol3-layerswitcher/1.0.1/ol3-layerswitcher']
},
shim: {
    "olLayerSwitcher":  {
        deps: ["ol"],
        exports: "olLayerSwitcher"
    },
    'sinon' : {
        'exports' : 'sinon'
    }
}

The project is uses Backbone and includes a Router module (/src/main/webapp/js/controller/AppRouter.js):

/*jslint browser : true*/
/*global Backbone*/
define([
    'backbone',
    'utils/logger',
    'views/MapView'
], function (Backbone, logger, MapView) {
    "use strict";
    var applicationRouter = Backbone.Router.extend({
        routes: {
            '': 'mapView'
        },
        initialize: function () {
            this.LOG = logger.init();
            this.on("route:mapView", function () {
                this.LOG.trace("Routing to map view");

                new MapView({
                    mapDivId: 'map-container'
                });
            });
        }
    });

    return applicationRouter;
});

The Router module depends on a View module (/src/main/webapp/js/views/MapView.js):

/*jslint browser: true */
define([
    'backbone',
    'utils/logger',
    'ol',
    'utils/mapUtils',
    'olLayerSwitcher'
], function (Backbone, logger, ol, mapUtils, olLayerSwitcher) {
    "use strict";

    [...]

    initialize: function (options) {
        this.LOG = logger.init();
        this.mapDivId = options.mapDivId;
        this.map = new ol.Map({

            [...]

                controls: ol.control.defaults().extend([
                    new ol.control.ScaleLine(),

                    new ol.control.LayerSwitcher({
                        tipLabel: 'Switch base layers'
                    })
                ])
            });

            Backbone.View.prototype.initialize.apply(this, arguments);
            this.render();
            this.LOG.debug("Map View rendered");
        }
    });

    return view;
});

The View module attempts to pull in both OpenLayers3 as well as the third-party OpenLayers plugin.

When the project is built and deployed, it works fine in-browser. When the View module is loaded, OpenLayers and the third-party plugin are pulled in just fine and everything renders properly.

However, when I attempt to test this in Jasmine is where all of this falls apart.

For Jasmine, I am using the Jasmine-Maven plugin. It pulls in JasmineJS, PhantomJS and RequireJS along with my libraries and runs my specs. The issue is that when run via Jasmine, the MapView module attempts to load both the OpenLayers3 library as well as the third party plugin (olLayerSwitcher) but fails because the third party plugin can't find "ol".

The test:

define([
    "backbone",
    "sinon",
    'controller/AppRouter'
], function (Backbone, sinon, Router) {
    describe("Router", function () {
        beforeEach(function () {
            this.router = new Router();
            this.routeSpy = sinon.spy();
            this.router.bind("route:mapView", this.routeSpy);

            try {
                Backbone.history.start({silent: true});
            } catch (e) {
            }
            this.router.navigate("elsewhere");
        });

        it("does not fire for unknown paths", function () {
            this.router.navigate("unknown", true);
            expect(this.routeSpy.notCalled).toBeTruthy();
        });

        it("fires the default root with a blank hash", function () {
            this.router.navigate("", true);
            expect(this.routeSpy.calledOnce).toBeTruthy();
            expect(this.routeSpy.calledWith(null)).toBeTruthy();
        });   
    });
});

The error from Jasmine:

[ERROR - 2015-08-08T21:27:30.693Z] Session [4610ead0-3e14-11e5-bb2b-dd2c4b5c2c7b] - page.onError - msg: ReferenceError: Can't find variable: ol

:262 in error
[ERROR - 2015-08-08T21:27:30.694Z] Session [4610ead0-3e14-11e5-bb2b-dd2c4b5c2c7b] - page.onError - stack:
global code (http://localhost:58309/js/vendor/ol3-    layerswitcher/1.0.1/ol3-layerswitcher.js:9)

:262 in error
JavaScript Console Errors:

* ReferenceError: Can't find variable: ol

The relevant section from the ol3-layerswitcher plugin on line 9 is:

[...]
ol.control.LayerSwitcher = function(opt_options) {
[...]

So it does depend on "ol" being a thing at this point.

The Jasmine-Maven plugin creates its own spec runner HTML and the relevant portion looks like this:

<script type="text/javascript">
if(window.location.href.indexOf("ManualSpecRunner.html") !== -1) {
  document.body.appendChild(document.createTextNode("Warning: Opening this HTML file directly from the file system is deprecated. You should instead try running `mvn jasmine:bdd` from the command line, and then visit `http://localhost:8234` in your browser. "))
}

var specs = ['spec/controller/AppRouterSpec.js'];

var configuration = {
  paths: {
    "sinon": ['/webjars/sinonjs/1.7.3/sinon'],
    "jquery": ["/webjars/jquery/2.1.4/jquery"],
    "backbone": ['/webjars/backbonejs/1.2.1/backbone'],
    "underscore": ['/webjars/underscorejs/1.8.3/underscore'],
    "text": ['/webjars/requirejs-text/2.0.14/text'],
    "log4js": ['/webjars/log4javascript/1.4.13/log4javascript'],
    "ol": ['/webjars/openlayers/3.5.0/ol'],
    "olLayerSwitcher": ['/js/vendor/ol3-layerswitcher/1.0.1/ol3-layerswitcher']
  },
  shim: {
    "olLayerSwitcher":  {
        deps: ["ol"],
        exports: "olLayerSwitcher"
    },
    'sinon' : {
        'exports' : 'sinon'
    }
  }
};

if (!configuration.baseUrl) {
    configuration.baseUrl = 'js';
}

if (!configuration.paths) {
    configuration.paths = {};
}

if (!configuration.paths.specs) {
    var specDir = 'spec';
    if (!specDir.match(/^file/)) {
        specDir = '/'+specDir;
    }
    configuration.paths.specs = specDir;
}

require.config(configuration);

require(specs, function() {
  jasmine.boot();
});

I am able to create a customer HTML runner but am not sure what the problem is so I wouldn't know what needs changing.

This doesn't seem to be a PhantomJS issue as I can load the tests in-browser and am experiencing the same issue.

I'd appreciate if anyone has any thoughts on what could be happening here. I really do not want to hack up the third-party module to transform it into a RequireJS module as the Jasmine testing is the last-leg of implementing this completely and I'm completely stuck here.

I am using Jasmine 2.3.0 and RequireJS 2.1.18

I apologize for not linking out more but this is a new account and I don't have enough rep for it.

It will be tough to figure out the problem without a running version of your setup. However, if you're able to customize the SpecRunner.html for jasmine generated by the maven plugin, simply include the jasmine(/ any other library causing an issue) in the SpecRunner html - <script src="/<path_to_lib>"> .

In my experience, its usually not worth the effort , to make libraries used in source amd compliant and play nicely with every other library for testing setup.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM