FpDev FpDev - 3 months ago 53
AngularJS Question

Include file with module from AngularJS app into RequireJS config file in Karma

As we know, when use RequireJS in the configuration file we must define 'paths' and 'shim'. When writing tests (Karma, Jasmine), we need to create an additional configuration file for RequireJS and re-define the same data.

I try to extract common parts and load them dynamically. In Angular JS application, everything works without problems, but in test i have always error '404'. But let's get to the beginning. Simple example structure:

.
|-- newApp
| |-- app
| | `-- app.require.js
| |-- newApp.require.js
| `-- index.html
`-- test
|-- test.karma.js
`-- test.require.js


index.html load RequireJS config file

<script data-main="newApp.require.js" src="bower_components/requirejs/require.js"></script>


newApp.require.js init RequireJS

require([
'app/app.require'
], function (appRequire) {
"use strict";

require.config({
baseUrl: 'app',
paths: appRequire.paths,
shim: appRequire.shim,
deps: [
'NewAppBootstrap'
]
});
});


app.require.js Module / object with paths and shim

define([
'some/others/components.require'
], function (componentsRequire) {
"use strict";

var appRequire = {
'NewApp': 'app.module',
'NewAppBootstrap': 'app.bootstrap',
'NewAppRoute': 'app.routes'
};

var vendorRequire = {
'jQuery': {
exports: '$'
},
'angular': {
exports: 'angular'
}
};

return {
paths: Object.assign(
appRequire,
componentsRequire
),
shim: vendorRequire
};
});


Up to this point everything works fine. Now I would like to file app.require.js load into test.require.js. And the problems begin...

test.require.js

var TEST_REGEXP = /(spec|test)\.js$/i;
var allTestFiles = [];

Object.keys(window.__karma__.files).forEach(function (file) {
'use strict';

if (TEST_REGEXP.test(file)) {
var normalizedTestModule = file.replace(/^\/base\/|\.js$/g, '');
allTestFiles.push(normalizedTestModule);
}
});

require([
'app/app.require'
], function (appRequire) {
"use strict";

require.config({
baseUrl: '/base/newApp',
waitSeconds: 200,
paths: appRequire.paths,
shim: appRequire.shim,
deps: allTestFiles,
callback: window.__karma__.start
});
});


Unfortunately, I still have error:

WARN [web-server]: 404: /app/app.require.js
PhantomJS 2.1.1 (Linux 0.0.0) ERROR: 'There is no timestamp for app/app.require.js!'

PhantomJS 2.1.1 (Linux 0.0.0) ERROR
Error: Script error for "app/app.require"
http://requirejs.org/docs/errors.html#scripterror at node_modules/requirejs/require.js:143


I tried different paths, but still nothing. Does anyone know how to load this file? Whether it is at all possible load file in this place? I would be grateful for any tips.

Answer

By the time your code hits this require call:

require([
    'app/app.require'
],

There is no RequireJS configuration in effect, and data-main is not used, so by default RequireJS takes the directory that contains the HTML page that loads RequireJS as the baseUrl (See the documentation.) Since index.html sits at the root, then RequireJS resolves your module name to /app/app.require.js and does not find it.

You can work around it by using a full path:

require([
    'base/newApp/app/app.require'
], 

Or if it so happens that other code later is going to try to access this same module as app/app.require, then you should have a minimal configuration before your first require call:

require.config({
  baseUrl: '/base/newApp',
});

It is perfectly fine to call require.config multiple times. Subsequent calls will override values that are atomic (like baseUrl) and marge values that can be merged. (An example of the latter would be paths. If the first call sets a paths for the module foo and a 2nd call sets a paths for the module bar, then the resulting configuration will have paths for both foo and bar.)