Requirejs do not add ".js" for modules using karma - requirejs

I have simple test, that must work in webstorm using karma and requirejs.
The problem is that for some reason requirejs do not add ".js" for modules i was loading for tests. So it crashed trying to load "../ts/mamats/mama", while "../ts/mamats/mama.js" exists
Test (main.jasmine.js):
define(["require", "exports", "../ts/mamats/mama"], function(require, exports, mama) {
describe("first test", function () {
it("should be true", function () {
var object = new mama.block();
expect(object instanceof mama.block).toBe(true);
});
});
});
//# sourceMappingURL=main.jasmine.js.map
every thing works correctly when i replace "../ts/mamats/mama" with "../ts/mamats/mama.js"
sourceMappingURL here because javaScript file generated from typeScript source file, and because of that i cannot add ".js" for modules manually
Test starts with this entry point (main-test.js):
var tests = Object.keys(window.__karma__.files).filter(function (file) {
return (/\.jasmine\.js$/).test(file);
});
requirejs.config({
baseUrl: '/base',
deps: tests,
callback: window.__karma__.start
});
Why requirejs don't add ".js" for modules here?
Karma conf file:
module.exports = function(config) {
config.set({
basePath: '../',
frameworks: ['jasmine', 'requirejs'],
files: [
'static-tests/main-test.js',
{ pattern: 'static/**/*', included: false },
{ pattern: 'static-tests/**/*', included: false }
],
exclude: [],
preprocessors: {},
reporters: ['progress'],
port: 9876,
colors: true,
logLevel: config.LOG_INFO,
autoWatch: false,
browsers: ['Chrome'],
singleRun: false
});
};

Here is an interesting read on how RequireJs handles this:
http://requirejs.org/docs/api.html#jsfiles
Reading that makes it seem like an issue with RequireJS, but there seems to be some debate on whether or not that is true. Regardless, this gist seems to solve the issue.
var tests = Object.keys(window.__karma__.files).filter(function (file) {
return /\.spec\.js$/.test(file);
}).map(function(file){
return file.replace(/^\/base\/src\/js\/|\.js$/g,'');
});
require.config({
baseUrl: '/base/src/js'
});
require(tests, function(){
window.__karma__.start();
});

It looks like trouble in require.js
The problem is in next:
1. When in deps appear absolute path - requirejs stop add ".js" for any require call
2. When in deps appear file with extension, for some reason requirejs again stop add ".js" for modules
Other Solution here - to replace bathUrl and add it to requirejs conf do not help.
For me solution is next:
var tests = Object.keys(window.__karma__.files).filter(function (file) {
return (/\-jasmine\.js$/).test(file);
}).map(function (file) {
return file.replace(/^\/|\.js$/g, '');
});
and
baseUrl: '',
for requirejs.conf
and i have no idea why requirejs still add "/base" for all url that are requested, but now all works fine

Related

Karma: Executed 0 of 0 Error

I think I have everything set up properly. I followed the specs of the Karma Tutorial for RequireJS, but everything I've tried seems to result in the same error.
It appears that my test-main.js file is being loaded since a console.log() will fire. However, in the Object.keys loop, the files will get listed, but TEST_REGEXP fails so the allTestFiles ends up being an empty array. I'm sure it's something silly, but it's created just like the Tutorial - with the exception of using node_modules for jquery, require, underscore.
My test-main.js file:
var allTestFiles = [];
var TEST_REGEXP = /test\.js$/;
var pathToModule = function(path) {
return path.replace(/^\/base\//, '').replace(/\.js$/, '');
};
Object.keys(window.__karma__.files).forEach(function(file)
{
if(TEST_REGEXP.test(file))
{
// Normalize paths to RequireJS module names
allTestFiles.push(pathToModule(file));
}
});
if(console) console.log(allTestFiles);
require.config(
{
// Karma serves files under /base, which is the basePath from the config file
baseUrl: '/base/src',
paths:
{
'jquery':'../node_modules/jquery/dist/jquery',
'underscore':'../node_modules/underscore/underscore-min'
},
shim:
{
'underscore': { exports: '_' }
},
// dynamically load all test files
deps: allTestFiles,
// kick off jasmine, as it is asynchronous
callback: window.__karma__.start
});
My karma.conf.js file:
module.exports = function(config) {
config.set({
// base path that will be used to resolve all patterns (eg. files, exclude)
basePath: '',
// frameworks to use
// available frameworks: https://npmjs.org/browse/keyword/karma-adapter
frameworks: ['jasmine', 'requirejs'],
// list of files / patterns to load in the browser
files: [
'test/test-main.js',
{pattern: 'node_modules/jquery/dist/jquery.js', included: false},
{pattern: 'src/*.js', included: false},
{pattern: 'test/**/*Spec.js', included: false}
],
// list of files to exclude
exclude: [
'src/main.js'
],
// preprocess matching files before serving them to the browser
// available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
preprocessors: {
},
// test results reporter to use
// possible values: 'dots', 'progress'
// available reporters: https://npmjs.org/browse/keyword/karma-reporter
reporters: ['progress'],
// web server port
port: 9876,
// enable / disable colors in the output (reporters and logs)
colors: true,
// level of logging
// possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
logLevel: config.LOG_INFO,
// enable / disable watching file and executing tests whenever any file changes
autoWatch: true,
// start these browsers
// available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
browsers: ['Chrome'],
// Continuous Integration mode
// if true, Karma captures browsers, runs the tests and exits
singleRun: false
});
};
I came across a solution to the problem.
I ended up changing my test-main.js file above the require.config section to this:
// Karma RequireJS configuration
var tests = [];
for (var file in window.__karma__.files) {
if (/Spec\.js$/.test(file)) {
tests.push(file);
}
}
If I simply changed TEST_REGEXP to /Spec\.js$/ I ended up getting a timestamp error. I don't know why. More interesting is why following the guide produces errors. But it is all working now.

RequireJS replacing Node's Require method

I'm running into an issue where node's require method has been replaced by requirejs' require method. We're running a backbone app and I've set up some mocha tests. The goal was to be able to run the tests in the browser, and also use grunt-mocha-test and run them in terminal on every build with grunt-contrib-watch.
I don't fully yet understand how all these pieces fit together, so please forgive any lack of explanation, understanding.
This is the set up of one of our test files, models.js:
describe("Models", function() {
var should;
var firstModule = 'models/firstModel';
var secondModule = 'models/secondModel';
var chaiModule = 'chai';
modules = [
firstModule,
secondModule,
chaiModule
];
before(function(done) {
require(modules, function(firstModel, secondModel, chai){
FirstModel = eventModel;
SecondModel = eventDetailsModel;
should = chai.should();
done();
});
});
beforeEach(function(done) {
NewFirstModel = new FirstModel();
NewSecondModel = new SecondModel();
done();
});
describe("first model", function() {
it("should exist", function (done) {
NewFirstModel.should.exist();
done();
});
});
});
Using grunt-contrib-requirejs with these settings:
compile:
options:
baseUrl: "<%= tmpDir %>/scripts"
mainConfigFile: "<%= tmpDir %>/scripts/init.js"
name: "../../bower_components/almond/almond"
out: "<%= distDir %>/scripts/app.js"
preserveLicenseComments: false
cjsTranslate: true
wrapShim: true
uglify:
ascii_only: true
The mochaTest grunt task:
test:
options:
reporter: 'spec',
src: ['app/test/*.js']
I've got a test.html file which includes each individual test file and properly tests everything I throw at them.
However, when I run the mochaTest grunt task, which points to the same test files, I get the following error:
AssertionError: path must be a string
referring to this line in models.js:
require(modules, function(firstModel, secondModel, chai){
If I console log the require method, it comes back as RequireJS' require method. I've tried a few different things, including setting nodeRequire: require in the init.js file referenced in the requirejs config. Any clues? Thanks!!!

Proper way to share dependencies in Karma with RequireJS

I use Karma and jasmine for my unit tests. I have a main-test.js file to configure karma, and a main.js to configure my application.
main-test.js:
//
...
//
require.config({
baseUrl: '/base',
paths: {
jquery: 'components/jquery/dist/jquery', // this is copypaste
//another dependencies
},
//
...configuration
//
});
main.js
require.config({
paths: {
jquery: 'components/jquery/dist/jquery', // this is copypaste
//another dependencies
},
//
...configuration
//
});
What is the proper way to share paths between those two configurations?
We met the same problem with my team and ended up by requiring the main config into test-main.js:
// requiring global requireJS config
require(['/base/config/require.conf.js'], function() {
'use strict';
// first require.config overload: Karma specific
require.config({
baseUrl: '/base/src',
paths: {
'angularMocks': '../bower_components/angular-mocks/angular-mocks'
},
shim: {
'angularMocks': {
deps: ['angular']
}
}
});
require(['angularMocks'], function() {
var specFiles = [];
for (var file in window.__karma__.files) {
if (window.__karma__.files.hasOwnProperty(file)) {
if (/\/base\/src\/.*_test\.js$/.test(file)) {
specFiles.push(file);
}
}
}
// second overload to include specFiles and start Karma
require.config({
deps: specFiles,
callback: window.__karma__.start
});
});
});
Our starter app structure for projects using AngularJS + RequireJS is available here: angular-requirejs-ready.
I do not claim this is the proper way, only our way ;)

Trying to use grunt-contrib-requirejs to minify all JS to one file

I have the following directory structure (relevant bits only):
app
- build
- script.js
- js
- lib
- require.js
- jquery-1.10.2.js
- app.js
- index.html
Gruntfile.js
Gruntfile.js contains the following:
module.exports = function (grunt) {
var gruntConfig = {
pkg: grunt.file.readJSON('package.json'),
requirejs: {
compile: {
options: {
name: 'app',
baseUrl: 'app/assets/js',
out: 'app/assets/build/script.js',
include: ['lib/require'],
uglify: {
// beautify: true,
defines: {
DEBUG: ['name', 'false']
}
},
paths: {
jquery: "lib/jquery-1.10.2"
}
}
}
},
};
grunt.initConfig(gruntConfig);
grunt.loadNpmTasks('grunt-contrib-requirejs');
};
app.js contains the following:
require(['jquery'], function ($) {
// Do stuff
});
How do I set it up so that it copies all the JavaScript needed into build/script.js, not just app.js and require.js when I tell it to (erroring when I try to use jQuery)? I also want to be able to add modules without adding them to my Gruntfile, just by adding them to script.js.
You can have a mainConfigFile defined and inside config file have paths to you lib code like this
Contents of gruntfile:
requirejs: {
compile: {
options: {
baseUrl: "app/js/",
mainConfigFile: app/config.js",
out: "build/script.js",
name: "config"
}
}
}
Contents of config file:
require.config({
paths: {
lib: "<path to>/js/lib",
jquery: "<path to>/js/lib/jquery-1.10.2.min",
.
and particular file required
.
}
Requirejs will add the contents of all path files to the optimized code.
Try adding this to your options object:
findNestedDependencies: true
This way grunt-contrib-requirejs (actually just requirejs) will find whatever dependencies are listed on your config file.
Hope it works for you.

Load files in specific order with RequireJs

I'm new to RequireJS and I'm stuck with the loading order.
I have a global project configuration that I need to be loaded before the modules located in js/app/*.
Here's my struture :
index.html
config.js
js/
require.js
app/
login.js
lib/
bootstrap-2.0.4.min.js
Here's the config.js file :
var Project = {
'server': {
'host': '127.0.0.1',
'port': 8080
},
'history': 10, // Number of query kept in the local storage history
'lang': 'en', // For future use
};
And here's my requirejs file (app.js) :
requirejs.config({
//By default load any module IDs from js/lib
baseUrl: 'js/lib',
//except, if the module ID starts with "app",
//load it from the js/app directory. paths
//config is relative to the baseUrl, and
//never includes a ".js" extension since
//the paths config could be for a directory.
paths: {
bootstrap: '../lib/bootstrap-2.0.4.min',
app: '../app',
},
shim: {
'app': {
deps: ['../../config'],
exports: function (a) {
console.log ('loaded!');
console.log (a);
}
} // Skual Config
},
});
var modules = [];
modules.push('jquery');
modules.push('bootstrap');
modules.push('app/login');
// Start the main app logic.
requirejs(modules, function ($) {});
But sometimes, when I load the page, I have a "Project" is undefined, because login.js has been loaded BEFORE config.js.
How can I force config.js to be loaded at first, no matter what ?
Note: I saw order.js as a plugin for RequireJS but it's apparently not supported since the v2, replaced by shim.
Ran into a similar problem today - we have bootstrapped data that we want to make sure is loaded before anything else, and that the module exposing that data is set up before any other modules are evaluated.
The easiest solution I found to force load order is to simply require a module be loaded before continuing on with app initialization:
require(["bootstrapped-data-setup", "some-other-init-code"], function(){
require(["main-app-initializer"]);
});
There's a possible solution to build a queue for modules to be loaded. In this case all modules will be loaded one-by-one in exact order:
var requireQueue = function(modules, callback) {
function load(queue, results) {
if (queue.length) {
require([queue.shift()], function(result) {
results.push(result);
load(queue, results);
});
} else {
callback.apply(null, results);
}
}
load(modules, []);
};
requireQueue([
'app',
'apps/home/initialize',
'apps/entities/initialize',
'apps/cti/initialize'
], function(App) {
App.start();
});
You won't have to worry about the load order if you define your js files as AMD modules. (Or you can use the shim config if you can't modify the config.js and login.js to call define).
config.js should look something like this:
define({project: {
'server': {
'host': '127.0.0.1',
'port': 8080
},
'history': 10, // Number of query kept in the local storage history
'lang': 'en', // For future use
}});
login.js:
define(['jquery', '../../config'], function($, config) {
// here, config will be loaded
console.log(config.project)
});
Again, shim config should only be used if calling define() inside the modules is not an option.

Resources