I'm using Mocha with RequireJS and tests are running fine, however, when I try to add in blanket code coverage I'm getting Uncaught TypeError: Object #<HTMLDivElement> has no method 'reporter',
Here's the code I'm running:
<div id="mocha"></div>
<script src="../src/js/vendor/requirejs/require.js"></script>
<script src="../src/js/vendor/blanket/dist/qunit/blanket.js"
data-cover-adapter="../src/js/vendor/blanket/src/adapters/mocha-blanket.js"></script>
<script src="SpecRunner.js" data-cover></script>
and my specrunner:
require(["../src/js/require-config.js"], function () {
// Set testing config
require.config({
baseUrl: "../src/js",
paths: {
"mocha": "vendor/mocha/mocha",
"chai": "vendor/chai/chai"
},
urlArgs: "bust=" + (new Date()).getTime()
});
require([
"require",
"chai",
"mocha"
], function (require, chai) {
var should = chai.should();
mocha.setup("bdd");
require([
"specs.js",
], function(require) {
if (window.mochaPhantomJS) {
mochaPhantomJS.run();
} else {
mocha.run();
}
});
});
});
Like I said - my tests are all running fine, I just can't figure out why blanket's not working.
Update:
I can get it to run by including the script tag for mocha at the beginning, however, now it runs the mocha tests twice.
There's a problem with how you use RequireJS. If you load code with RequireJS and load code with <script> tags, and:
The two sets of code are not dependent on one another, then you can load them in any order.
The code loaded with <script> depends on code loaded by RequireJS, then you should convert the code loaded with <script> to be loaded with RequireJS. If you do not do this, you run into intermittent failures.
The code loaded with RequireJS depends on the code loaded with <script>, then the code loaded with <script> must load and execute before you start loading code with RequireJS.
From looking at the documentation for Blanket, I determine that your case is the second. You load the Blanket adapter before you start loading modules with RequireJS, but the adapter wants Mocha to be present already.
You will have to use a shim. I can't be certain of the exact shim you use (because I don't use blanket) but something like this should help you in the right direction:
shim: {
"blanket": {
exports: "blanket"
},
"mocha-blanket": ["mocha", "blanket"]
}
Obviously the names "blanket" and "mocha-blanket" have to be adapted to your situation. I do not see a need to have an exports value on the adapter itself since the adapter attaches itself to Mocha rather than export something in the global space.
I figured it out and did a write-up on getting Blanket to work with Mocha in AMD. Here's a blog post outlining the process as well as a repo with the working code.
I'm using the following to load my tests:
require(["../src/js/require-config"], function () {
require.config({
baseUrl: "../src/js",
paths: {
chai: "vendor/chai/chai"
}
});
require([
"chai"
], function (chai) {
chai.should();
window.expect = chai.expect;
mocha.setup("bdd");
require([
"specs.js"
], function () {
mocha.run();
});
});
});
And then the following code on the page:
<div id="mocha"></div>
<script src="../src/js/vendor/mocha/mocha.js"></script>
<script data-main="main-tests" src="../src/js/vendor/requirejs/require.js"></script>
<script src="../src/js/vendor/blanket/dist/qunit/blanket.js" data-cover-only="../src/js/component"></script>
<script type="text/javascript" src="../node_modules/grunt-blanket-mocha/support/mocha-blanket.js"></script>
<script>
/* global blanket */
if (window.PHANTOMJS) {
blanket.options("reporter", "../node_modules/grunt-blanket-mocha/support/grunt-reporter.js");
}
</script>
The published mocha adapter from blanket does not works.
Install the not yet released version with bower bower install blanket#master --save-dev
Also, the order of scripts inclusion matter
<script src="mocha.js"></script>
<script>mocha.setup('bdd');</script>
<script data-main="config.js" src="../bower_components/requirejs/require.js"></script>
<script src="../bower_components/blanket/dist/qunit/blanket.js" data-cover-never="bower_components"></script>
<script src="../bower_components/blanket/src/adapters/mocha-blanket.js"></script>
Related
I'm trying to integrate this library which is non-npm. I failed many times already as I always thrive for using some modern framework which makes it impossible for me to integrate.
I tried backbone.js with require.js, even Dart and now I'm stubbornly trying to achieve the same using gulp, jspm, aurelia. The problem is that this library probably doesn't follow the module concept. I had lot of problems with initialization of this lib, made a lot of shimming.
So the question is how can I use such kind of libraries. Using in the same time modern ways to build javascript applications.
For older libraries that don't follow modern module patterns the approach is usually to shim them.
If you're using webpack, you can shim modules by declaring imports and exports.
RequireJS has a similar shim config, but needs more wiring to declare dependencies. I'd strongly recommend webpack over Grunt/gulp/RequireJS.
However, looking at the mapy.cz library you linked, it dynamically loads many other assets by writing script tags to the page. I can see how that's hard to work with.
I think your options are really:
If the licence is a friendly open-source one, fork it and expose it in a more modern module format that can be easily imported via npm. Check out the UMD style - you can write a declaration that'll export the module in a format usable by most module systems (AMD, CommonJS, etc). The webpack library and externals page has some guidelines for writing modules in a format that others can use.
If it's not an open-source licence, you could get in touch with the author(s) to ask them to change how the library is bundled and loaded. It should be an easy sell: an npm module would allow more people to use their code, and would be easier to work with - especially if they started versioning it. You could offer to do it for them, or just do it as an example they can copy from.
They have a page detailing terms and conditions, as well as a 'contact us' button - I'd start there: http://napoveda.seznam.cz/cz/mapy/mapy-licencni-podminky/licencni-podminky-mapovych-podkladu/
After looking at the code, I got it working (I used require.js, but you can use whatever you like):
// main.js
////////////////
require(['mapy-loader'], function (Loader) {
// load mapy async and wait for it to finish
Loader.async = true;
Loader.load(null, null, function () {
var stred = SMap.Coords.fromWGS84(14.41, 50.08);
var mapa = new SMap(JAK.gel("mapa"), stred, 10);
mapa.addDefaultLayer(SMap.DEF_BASE).enable();
mapa.addDefaultControls();
});
});
<!doctype html>
<html>
<head>
<script data-main="main.js" src="https://cdnjs.cloudflare.com/ajax/libs/require.js/2.2.0/require.min.js"></script>
<script>
requirejs.config({
paths: {
"mapy-loader": "//api.mapy.cz/loader"
},
shim: {
'mapy-loader': {exports: 'Loader'}
}
});
</script>
</head>
<body>
<div id="mapa" style="width:600px; height:400px;"></div>
</body>
</html>
(It won't run in the snippet here, since the JavaScript should be placed in a file named main.js)
EDIT:
Adding jspm / System.js snippet:
(main.js is unchanged)
// main.js
////////////////
define(['mapy-loader'], function (Loader) {
// load it async and wait for it to finish!
Loader.async = true;
Loader.load(null, null, function () {
var stred = SMap.Coords.fromWGS84(14.41, 50.08);
var mapa = new SMap(JAK.gel("mapa"), stred, 10);
mapa.addDefaultLayer(SMap.DEF_BASE).enable();
mapa.addDefaultControls();
});
});
<!doctype html>
<html>
<head>
<script src="jspm_packages/system.js"></script>
<script>
System.config({
baseURL: "/",
defaultJSExtensions: true,
transpiler: "babel",
paths: {
"mapy-loader": "//api.mapy.cz/loader"
},
meta: {
'mapy-loader': {
format: 'global',
exports: 'Loader'
}
}
});
</script>
<script>
System.import('main.js');
</script>
Run
</head>
<body>
<div id="mapa" style="width:600px; height:400px;"></div>
</body>
</html>
Maybe I have fundamentally misunderstood how requirejs config works but I thought my configuration below made some libraries global so I could just use them in other files while only having to require and define files that I needed to use within the individual script. However I cannot reference $ (jQuery) in my application code without getting a reference error indicating it is not globally accessible. I've isolated the problem to the simple example below.
My file set up is as follows:
test
|
|-index.html
|-TestApp.js
|-MainApp.js
|-lib
| |-require.js
| |-jquery.js
| |-loadash.js
| |-backbone.js
|-css
|-test.css
The library file versions are RequireJS 2.1.22, jQuery 2.0.3, Loadash 3.10.1 and Backbone 1.2.1. I'm just trying to set up my environment and the approach I am taking is to pass my TestApp.js file to require.js to load the required files and bootstrap the application code in MainApp.js. The script in index.html is as follows:
<!DOCTYPE html>
<html>
<head>
<link rel='stylesheet' type='text/css' href='css/test.css'/>
</head>
<body>
<div></div>
<script src="./lib/require.js" type="text/javascript" data-main="./TestApp.js"></script>
</body>
</html>
The referenced css script file simply ensured the div is visible as an orange square. See below:
div {
height: 100px;
width: 100px;
background-color: #FA6900;
border-radius: 5px;
}
It's the script line in index.html that then kicks off the application code by passing my configuration file to requirejs. This is the TestApp.js passed across as data-main. The TestApp.js is here:
require.config({
paths: {
'jquery': 'lib/jquery',
'lodash': 'lib/lodash',
'backbone': 'lib/backbone'
},
map: {
'*': {
// Backbone requires underscore. This forces requireJS to load lodash instead:
'underscore': 'lodash'
}
},
shim: {
jquery: {exports: '$'},
underscore: {
deps: ['jquery'],
exports: '_'
},
backbone: {
deps: ['underscore'],
exports: 'Backbone'
},
TestApp: {
deps: ['backbone'],
exports: 'TestApp'
}
}
});
require(['MainApp'], function(MainApp) {
MainApp.run();
});
The file above references the paths to the library files I want to use, I then remap loadash to be loaded when underscore is required (I need some of the extra loadash capability), I then use the shim to ensure the dependancies are correct as the files are loaded. Passing this config file to require.js in the index.html seems to be working as all of the files are showing as loaded in my browser. However the problem seems to be they do not appear to be globally accessible as I thought they would be.
Following the config section the last require call loads the MainApp.js file and calls the exposed run function. The MainApp.js looks like this:
define(function(require) {
var run = function() {
$(document).ready(function() {
$('div').click(function() {
$('div').fadeOut('slow');
});
});
};
return {
run: run
};
});
As far as I understood I should not need to require the files I already mentioned in the require config, I thought they should be loaded and available to this code. This is where I have misunderstood what is going on or have missed a step out. The exposed run function is being called but the first line that calls $ throws the error:
ReferenceError: Can't find variable: $
So my questions are:
What have I got wrong in my thinking?
(or) What am I doing incorrectly?
What should I be doing in order to preload and make available
frequently referenced libraries so that I do not need to require and
define them in every file I have?
As far as I understood I should not need to require the files I already mentioned in the require config, I thought they should be loaded and available to this code.
You misunderstood how RequireJS works. You should read the documentation from start to finish. For now, here are things you should change.
You should require jquery in your MainApp module:
define(function(require) {
var $ = require("jquery");
You should remove your shims that you have for jquery, underscore and backbone as they all call define and shim is only for code that does not call define. I don't know what TestApp is but if it is your own code, you really should make it into a proper AMD module and remove the shim.
#Louis has made me realise the error in what I was doing above. Changing the shim in TestApp.js so that is reads:
MainApp: {
deps: ['backbone'],
exports: 'MainApp'
}
Corrected the problem, now Backbone, $ and _ are all available to the rest of my application code without cluttering up each files require. i.e. I do not need to begin every file with:
define (['lib/jquery', 'lib/loadash', 'lib/backbone'], function($, _ , Backbone) {
Given in my actual app the list of common deps is quite large this means I only need to define locally used resources and can control the paths from a single location.
How can I call requireJS require(['app'], function() {}); only once at the beginning for the whole application so that any subsequent require(["..."], function(...){}); don't need to be wrapped within require(['app']?
This is my set up:
1) Load require.js
<script data-main="js/app.js" src="requirejs/require.min.js"></script>
2) Have app.js shims and basUrl configured properly.
requirejs.config({
baseUrl: "scripts/js",
paths: {
"jquery": "../bower_components/jquery/dist/jquery.min",
"modernizr": "../bower_components/modernizr/modernizr",
.
.
.
},
shim: {
"jquery.migrate": ['jquery'],
.
.
.
}
});
3) Dynamically load JS on different pages:
// Home Page
require(['app'], function() {
require(["jquery", "foundation", "foundation.reveal"], function ($, foundation, reveal){
$(document).foundation();
});
});
// Catalog Page
require(['app'], function() {
require(["jquery", "lnav/LeftNavCtrl","controllers/ProductCtrl", "controllers/TabsCtrl"], function ($, NavCtrl, ProductCtrl, TabsCtrl){
$(function() {
NavCtrl.initLeftNav();
});
});
});
Unless I wrap with require(['app'], function()) each time I call require("...") to load external JS or AMD modules, the app is not initialized and I get JavaScript errors. The above code works but it's not very efficient.
Is there a way to start my requireJS app before I try loading scripts?
I tried calling at the very beginning right after I load require.min.js:
require(["app"], function (app) {
app.run();
});
but it didn't work.
There are no provisions in RequireJS to ensure that a specific module is always loaded before any other module is loaded, other than having your first module load the rest. What you are trying to do is share your first module among multiple pages so it cannot perform the work of loading what is specific to each page.
One way you can work around this is simply to load app.js with a regular script element:
<script src="requirejs/require.min.js"></script>
<script src="js/app.js"></script>
Then the next script element can start your application without requiring app.js:
<script>
require(["jquery", "foundation", "foundation.reveal"], function ($, foundation, reveal){
$(document).foundation();
});
</script>
This is actually how I've decided to launch my modules in the applications I'm working on right now. True, it is not as optimized as it could be because of the extra network round-trip, but in the case of the applications I'm working on, they are still in very heavy development, and I prefer to leave this optimization for later.
Note that generally you don't want to use script to load RequireJS modules but your app.js is not a real module as it does not call define, so this is okay.
Another option would be to use a building tool like Grunt, Gulp, Make or something else and create one app.js per page and have each page load its own app.js file. This file would contain the configuration and the first require call to load the modules specific to your page.
My program starts through this entry point in a twig template:
<script data-main="{{ asset('bundles/wwwcms/js/app') }}" src="{{ asset('bundles/wwwcms/js/require.js') }}"></script>
This outputs:
<script data-main="static.correct_require_url.net/js/app" src="static.correct_require_url/require.js"></script>
That all works fine, so require executes my app.js (config):
requirejs.config({
'baseUrl': 'js/lib',
'paths': {
'app': '../app',
'jquery': '//code.jquery.com/jquery-1.10.2.min',
'bootstrap': '//netdna.bootstrapcdn.com/bootstrap/3.0.2/js/bootstrap.min'
},
'shim': {
'bootstrap': {
deps: ['jquery']
}
}
});
// always require jquery and bootstrap onload
requirejs(['bootstrap']);
Which also works.
The directory structure is as follows:
app.js
require.js
/lib
- test.js
/app
- dirty.js
- import.js
Okay so here is where the error comes
For a page, let's say I want to load dirty.js and import.js. dirty.js depends on jquery, and import.js depends on "test.js" (something I just made up for demonstration purposes).
So I load the dependencies on the page this way:
<script type="text/javascript">
require(['app/dirty', 'app/import']);
</script>
When the page loads, dirty.js and import.js are loaded in just fine, from the correct url relative to "app". However, the dependency for import.js (test.js) does not get loaded correctly.
This is how import.js starts:
require(['jquery', 'test'], function($, test) {
...
});
As you can see, it's asking for lib/test.js. It pulls jQuery from a CDN, so that's taken care of. But for test.js, it uses the wrong path.
import.js (and all other modules loaded first) are pulled in using the correct static url path, but dependencies for modules are loaded using the wrong path- they are loaded using the url of that page!
So when I look at the network tab in the debugger console, import.js comes from:
static.blahblah.com/js/app/import.js.
but test.js comes from:
blahblah.com/route/to/current/page/js/app/test.js
(which obviously 404s every time)
What are possible reasons for this occurring? Am I doing something wrong? Any help would be greatly appreciated.
This is how the script tags look before require runs:
<script data-main="//static.bananajams.cloud.net/bundles/wwwcms/js/app" src="//static.bananajams.cloud.net/bundles/wwwcms/js/require.js"></script>
<script type="text/javascript">
require(['app/dirty', 'app/preview', 'app/import']);
</script>
Basically data-main is only a good idea if it's the single entry point for your code. It's loaded asynchronously, so there is no guarantees it runs before the other code in your app. See
RequireJS does not run data-main script before loading required modules
for more info on this.
Trying to create an AMD Javascript library to be included in non-AMD projects. Here's my setup:
app.coffee
define ->
class App
constructor: -> console.log 'instantiating App'
init: -> console.log 'Init called'
index.html
<body>
<script type="text/javascript" src="//code.jquery.com/jquery-1.10.2.min.js"></script>
<script type="text/javascript" src="dev-latest.js"></script>
<script type="text/javascript">
$(document).ready(function(){
console.log('doc', window.app);
});
$(function(){
console.log('func', window.app);
});
window.onload = function()
{
console.log('onload', window.app);
}
</script></body>
main.js
require(['cs!app'], function(app){
return window.app = new app;
});
I am building this project with r.js optimizer to get dev-latest.js as the output. Here's my build file (PS: Build is successful):
({
baseUrl: './vendor',
paths: {
app: '../app',
'require-lib': 'require'
},
name: '../main',
out: 'dev-latest.js',
include: 'require-lib',
preserveLicenseComments: false
})
When running the code in the browser here's the output:
doc undefined
func undefined
onload undefined
instantiating App dev-latest.js:1
app.init(); // running this manually in the browser console
Init called
How should I go about this and get app to load before being used ?
Using AMD you cant rely on a module being created outside of a module. The only reliable way is to load the result of a module into another module. So in your case need to create a new module which then can lsiten to $.read:
define( [App], (App)->
$(document).ready(function(){
console.log('doc', App);
});
)
Solved it by using browserify (just found about it) which uses the CommonJS form of dependency loading and saves all that clutter. Also a great template for starting projects is amitayd's grunt-browserify-jasmine setup