karma config moving a file to base directory - requirejs

Is there a way to move a file loaded in the Karma config to new directory, such as /base/? I have an external project which contains the source files. I am able to load the file via ../../directory. However, it inserts the file into the /absolute/ folder. If I load the test(s) on another computer, the directory of /absolute/ is different. Is there a preprocessor or some configuration I am missing? I searched through the karma documentation, but couldn't find what I am looking for.
// list of files / patterns to load in the browser
files: [
{ pattern: 'node_modules/jquery/dist/jquery.min.js', included: false },
{ pattern: 'node_modules/knockout/build/output/knockout-latest.js', included: false },
{ pattern: 'node_modules/knockout-mapping/dist/knockout.mapping.min.js', included: false },
{ pattern: 'node_modules/knockout-postbox/build/knockout-postbox.min.js', included: false },
{ pattern: '../FantasyFootball/wwwroot/js/site.js', included: false, served: true, watched: true },
{ pattern: 'tests/*.js', included: false },
{ pattern: 'test-main.js', included: true }
],

Karma generates paths that start with /absolute/... for files you ask it to
load files that are outside Karma's basePath. Karma does this because there's no
simple way to provide a path to these files through the usual /base/ path that
is both unique and inferable. If you are to provide a relative path to a
file above basePath, Karma cannot just combine it with /base/. For instance,
if you had ../my/file.js and ../../my/file.js in your files array, then
combined with /base/, they would both turn into the path /my/file.js. For
cases like this, Karma generates a unique and inferable path by using
/absolute/ and appending the absolute path of the file on disk.
Ok, so where does that leave you? You want Karma to load files outside
basePath and you want to be able to use their paths in your loader's setup.
The problem can be overcome. You can modify karma.conf.js to provide
information useful to compute the paths you need:
client: {
absoluteTopDir: path.join("/absolute/", __dirname),
},
Then in test-main.js, you need to use the absoluteTopDir parameter:
var absoluteTopDir = window.__karma__.config.absoluteTopDir;
require.config({
baseUrl: "...",
paths: {
foo: absoluteTopDir + "../../my/file",
},
});
I've run Karma for years without any trouble but I recently ran into the problem
you ran into and used the method I described above in one of my test suites with
great success.
I've used this solution both with RequireJS and SystemJS.

Related

Uglify or concat a JavaScript file conditionallly

I have in my Scripts folder a "Lib" folder and an "App" folder.
The Lib folder contains 3rd part library JavaScript files. Some of these are minified without the original sources, others we have the original sources for.
The App folder contains all of our own JavaScript files, all of which are not minified.
I'm new to Grunt but I have a gruntfile which does the following:
Uglifies all the JS files in the Lib folder and produces minified versions with sourcemaps.
Uglifies all the JS files in the App folder and produces minified versions with sourcemaps.
Obvious problem: some of the files in the Lib folder are minified, so minifying them again/generating source maps is a bad idea and can fail for various reasons.
My solution: I run Uglify only on .js files in the Lib folder into lib-unmin.min.js. I then concat all the already minified files into a lib-min.min.js file, then I concat both those files together to get lib.min.js.
The new problem
What if I can't concat the already minified scripts to the end of the other minififed scripts without it breaking?
I have a dependency issue like this:
scripts/lib/a.js (required for b to run)
scripts/lib/b.min.js (required for c to run)
scripts/lib/c.js (required for the App scripts to run)
If I have an array of these file paths in my gruntfile, in that order, what's the easiest way of uglifying/concating all the files into a single minified JS file in that order, making sure we don't attempt to minify the minified file?
What do other developers do in similar situations?
Thanks!
I like to concat the files then uglify all of them together. This way uglify makes sure there aren't duplicate variable values overriding each other when it compresses the variable names.
You can bundle as many files as you want in the concats. Make different concat groups to uglify together and maintain the 'first, second, third, ...' order like this:
module.exports = function(grunt) {
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
uglify: {
app: {
options: {
sourceMap: true,
sourceMapName: 'build/maps/map.map'
},
files: {
'build/app.min.js': ['build/js/app-first-unmin.js', 'build/js/app-second-min.js', 'build/js/app-third-unmin.js']
}
}
},
concat: {
options: {
separator: ';'
},
firstUnminified: {
src: [
'lib/underscore.js'
],
dest: 'build/js/app-first-unmin.js'
},
secondMinified: {
src: [
'lib/moment.min.js'
],
dest: 'build/js/app-second-min.js'
},
thirdUnminified: {
src: [
'lib/favico.js'
],
dest: 'build/js/app-third-unmin.js'
}
},
});
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.registerTask('default', ['concat:firstUnminified', 'concat:secondMinified', 'concat:thirdUnminified','uglify']);
};

Cache-busting scheme incompatible with r.js (require.js)?

In my application, I want to have an environment config that uses a different version name for every deploy so that the application is properly cache busted and users don't have stale versions of code in their browser cache. Note I have been following this guide.
Thus, in main.js, before I do anything, I call require.config with a generic config that uses the current date/time to bust the cache on the environment config file, then after the environment config is loaded, I use the environment "config.version" as part of the urlArgs to guarantee that the newly deployed code is included and not a stale version. Note that the object from the config file has other properties that will be used throughout the application as well (e.g. google analytics account number).
It seems that my r.js build file is fine if I remove the first require.config that allows me to setup the environment/config dependency, but when I add it back in, the infrastructure JS module that I'm using to group third-party scripts chokes saying it can't find my underscore lib (or any lib I include in there for that matter). Note that even if I don't include environment/config and just make the two require.config calls, the same error results. Is there a reason two require.config calls would cause this error? Thanks for any help.
//Error:
Error: ENOENT, no such file or directory '<%root_folder%>\dist\js\underscore.js'
In module tree:
infrastructure
My main JS file
//main.js
require.config({
baseUrl: "js",
waitSeconds: 0,
urlArgs: "bustCache=" + (new Date).getTime()
});
require(["environment/config"], function(config) {
"use strict";
require.config({
urlArgs: "bustCache=" + config.version,
baseUrl: "js",
waitSeconds: 0,
paths: {
underscore: "lib/lodash.underscore-2.4.1-min",
},
shim: {
"underscore":{
exports : "_"
}
}
});
//commented out, b/c not needed to produce the error
//require(["jquery", "infrastructure"], function($) {
//$(function() {
//require(["app/main"], function(app) {
//app.initialize();
//})
//});
//});
});
And here's the build file...
//build file
({
mainConfigFile : "js/main.js",
appDir: "./",
baseUrl: "js",
removeCombined: true,
findNestedDependencies: true,
dir: "dist",
optimizeCss: "standard",
modules: [
{
name: "main",
exclude: [
"infrastructure"
]
},
{
name: "infrastructure"
}
],
paths: {
"cdn-jquery": "empty:",
"jquery":"empty:",
"bootstrap.min": "empty:"
}
})
Here infrastructure.js
define(["underscore"], function(){});
config file (will have more keys like google analytics account number and other environment specific info.)
//config.js
define({version:"VERSION-XXXX", cdn: { jquery: "//path-to-jquery-1.11.0.min" }});
command I'm running: "r.js -o build.js"
Ok, yes, it is a problem with the two require.config calls. At runtime, there is absolutely no problem calling config multiple times. However, at build time, r.js is not able to follow the calls. So if your build depends on any later call to require.config you are going to have problems.
I see that your second call to require.config does not contain any value that is computed on the basis of what is loaded after the first call, except for urlArgs so you could move everything from that second call into the first one, except for urlArgs.

karma error 'There is no timestamp for'

Trying to get karma working with requirejs. I don't understand why I am getting all of these errors when running Karma:
ERROR: 'There is no timestamp for /base/test/mainSpec.js?bust=1387739317116!'
ERROR: 'There is no timestamp for /base/app/main.js?bust=1387739317116!'
ERROR: 'There is no timestamp for /base/bower_components/jquery/jquery.js?bust=1387739317116!'
When I go to the network tab in inspector, all of the files are there with no 404s.
I'm a little confused because karma seems to be looking for a 'base' directory but there is no 'base' directory in my project. According to the karma docs:
Karma serves files under the /base directory. So, on the server
requests to files will be served up under
http://localhost:9876/base/*. The Require.js config for baseUrl gives
a starting context for modules that load with relative paths. When
setting this value for the Karma server it will need to start with
/base. We want the baseUrl for our tests to be the same folder as the
base url we have in src/main.js, so that relative requires in the
source won’t need to change. So, as we want our base url to be at
src/, we need to write /base/src.
This confusing to say the least. Am I supposed to have a baseUrl configuration in my main.js file that points to '/base'?
note: This post was valid by Karma in 2014 Jan 16. I am not certain of the current state of that lib, maybe they fixed their weird configuration logic and added meaningful error messages. If not, then this post can be probably very helpful by fixing configuration issues related to Karma.
These kind of errors occur by misconfiguration. You should add everything your test uses to the file patterns in your config file.
For example:
module.exports = function (config) {
config.set({
basePath: './',
frameworks: ['jasmine', 'requirejs'],
files: [
{pattern: 'test/bootstrap.js', included: true},
{pattern: 'test/**/*.js', included: false},
{pattern: 'src/**/*.js', included: false},
{pattern: 'vendor/**/*.js', included: false}
],
exclude: [
],
reporters: ['progress'],
port: 9876,
colors: true,
logLevel: config.LOG_INFO,
autoWatch: true,
browsers: ['Firefox'],
captureTimeout: 6000,
singleRun: false
});
};
In this example the bootstrap.js is the only file included by Karma in the HTML, the other files are dependencies which are loaded by the code in the bootstrap.js. The pattern order is very important and sadly it is far from logical: the next pattern does not override the previous one. So if I'd give the test/**/*.js pattern as first and test/bootstrap.js as second, it would not work because the bootstrap would not be included. In these cases Karma sends you an "empty testsuite" message, which is useless if you don't know how to configure it...
If your tests try to use a file which is not covered by the patterns you gave in your Karma configuration file, then you will get the "There is no timestamp for xy" error message, which is very similar to the previously mentioned "empty testsuite". If you don't know the system you won't have a clue, what it means, or what you have to do in order to fix it ...
The exclude part of the configuration object is for files, which have been added to the file patterns for inclusion, but you don't want to include or use them in your tests. These can be for example requirejs configuration files for development and production environments, etc...
For me it was simply making the mistake of setting basePath: 'base' instead of baseUrl: '/base'.
baseUrl: '/base' ftw!
The basePath is to identify the root of your project relative to the configuration file (karma.conf.js). Take a look at this example: https://github.com/karma-runner/karma/blob/v0.8.5/test/client/karma.conf.js
In the browser, I also got this error about the timestamp but it doesn't affect anything. The tests are working properly. I guess it should be a warning more than an error :-)
Jeff's right, you should exclude the requirejs config file of your app, because "we don't want to actually start the application in our tests. [LINK]".
The test-main.js config file is a separate file from the requirejs config file your app uses, which in your case might be config.js or main.js, depending on where you config your requirejs.
They both configures path and dependencies (could be specifying about the same ones), but the former is to provide requirejs support for the tests you write. This whole requirejs setup is a separate one from the requirejs you use in your app. So don't include the latter, it confuses Karma.
And the link above is a working Karma with its requirejs demo, check it out.
After trying all the solutions posted on different sources, Finally I got it Fixed. Check it here: Make "no timestamp" error configurable #6 .
Example from the issue for the karma.conf.js file:
client: {
requireJsShowNoTimestampsError: '^(?!.*(^/base/app/node_modules/))'
}
in my karma.conf.js file, I simply excluded my file that contained my require.config function (in my case happened to be config.js) and the errors went away.
exclude: [
'app/config.js',
'bower_components/jasmine/**/*.js'
],
This error can also happen when the files in question don't actually exist!
So check to make sure that the file you're getting this error for actually exists in your project!
Once you find out what the files are, you can ignore them using a pattern like so in your karma.conf.js, if it turns out their existence should be ignored in some cases:
exclude: [
'path/to/files/to/ignore/**/*.js'
]
I had an exact same error in my project and I found that the best and fastest way to debug where is the problem is to list the files that our karma have loaded.
If you used karma init (if not, just do it) and respond YES to the question about the usage of RequireJS you probably have a file like this:
var tests = [];
var TEST_REGEXP = /(spec|test)\.js$/i;
var BASE_URL = '/base/build/js';
var BASE_URL_REGEXP = /^\/base\/build\/js\/|\.js$/g;
// Get a list of all the test files to include
Object.keys(window.__karma__.files).forEach(function (file) {
console.log(file;) // ADD THIS CONSOLE LOG TO LIST LOADED FILES
if (TEST_REGEXP.test(file)) {
var normalizedTestModule = file.replace(BASE_URL_REGEXP, '')
tests.push(normalizedTestModule)
}
})
require.config({
// Karma serves files under /base, which is the basePath from your config file
baseUrl: BASE_URL,
paths: {
},
shim: {
},
deps: tests,
// we have to kickoff jasmine, as it is asynchronous
callback: window.__karma__.start
})
Then you can play with your karam.conf.js file and load new files to check whats going on in karma local path.
Expanding from #Naruto Sempai's answer:
I resolved this issue by first setting the basePath attribute in my karma.conf.js file. This path contains the needed ../ (previous directory) strings until my path was at the root of my source/test files.
Then I modified my test-main.js file (containing my RequireJS configuration) and set the baseUrl to /base.
Now, no timestamp errors.
--
To illustrate my environment and paths I configured, heres a basic setup example:
Source file location:
/Users/ben/some-project/src/main/resources/var/www/project/js/app
Test file location:
/Users/ben/some-project/src/test/var/www/project/
Karma Config location:
/Users/ben/some-project/src/test/var/www/project/karma.conf.js
Test RequireJS Config location:
/Users/ben/some-project/src/test/var/www/project/test-main.js
My karma.conf.js:
module.exports = function (config) {
config.set({
basePath: '../../../../'
});
}
to make my "root" at /Users/ben/some-project/src/.
My test-main.js:
requirejs.config({
baseUrl: '/base'
});

using r.js optimization to optimize modules

If I use Modules options, I see the whole files are copied and I am not sure how to use a single optimized file.
I can build a file with references to JS files and use that file to generate a single file.
But using Modules option, I see only the source files are copied directly and I see no optimization....any idea on how to use modules option and optimize it?
Here is the snippet...
({
baseUrl: ".",
dir: "app/main-built-125",
modules: [{
name: "scripts/Address/AddressList"
}, {
name: "scripts/Office/OfficeDetails"
}],
paths: {
jquery: 'empty'
},
fileExclusionRegExp: /^\./,
})
You'll need to use the include option to specify which dependencies to include with the module.
Note that by default dependencies of the defined modules (the one set as name) should be fetched and included in the builded file (Of course, as long as they're defined in the define() deps array).

Use RequireJS config file as the build file?

I've got some paths configured in require-config.js as follows:
var require = {
baseUrl: '/javascript',
paths: {
'jquery': 'jquery/jquery-1.8.1.min'
// etc. -- several paths to vendor files here
},
}
I am trying to get the optimization working for deployment. The docs say I should have a build.js that looks something like this:
({
baseUrl: 'javascript',
paths: {
'jquery': 'jquery/jquery-1.8.1.min'
},
name: 'main',
out: 'main-build.js'
})
Is there a way to have the optimizer read my config file instead of (or in addition to) build.js? I don't want to have to manually keep the paths configured the same in both files if they change.
I tried to just run node r.js -o path/to/require-config.js, but it threw an error, "malformed: SyntaxError: Unexpected token var"
Edit: for clarification, my require-config.js file is the config only, not my main module. I did this so I could use the same configuration but load a different main module when unit testing.
You'll need to adjust the way your config options are defined. Taken from the RequireJS documentation:
In version 1.0.5+ of the optimizer, the mainConfigFile option can be used to specify the location of the runtime config. If specified with the path to your main JS file, the first requirejs({}), requirejs.config({}), require({}), or require.config({}) found in that file will be parsed out and used as part of the configuration options passed to the optimizer:
So basically you can point your r.js build file to your config options that will also be shared with the browser.
You will need to make use of the mainConfigFile option
For other's reference:
https://github.com/jrburke/r.js/blob/master/build/example.build.js
The build settings (no need to repeat your config.js lib inclusions here):
baseUrl: 'app',
name: 'assets/js/lib/almond', // or require
// Read config and then also build it into the app
mainConfigFile: 'app/config.js',
include: ['config'],
// Needed for almond (and does no harm for require)
wrap: true,

Resources