how to fix 404 warnings for images during karma unit testing - javascript

I'm unit testing one of my directives (angularjs) using grunt/karma/phantomjs/jasmine. My tests run fine
describe('bar foo', function () {
beforeEach(inject(function ($rootScope, $compile) {
elm = angular.element('<img bar-foo src="img1.png"/>');
scope = $rootScope.$new();
$compile(elm)();
scope.$digest();
}));
....
});
but I do get these 404s
WARN [web-server]: 404: /img1.png
WARN [web-server]: 404: /img2.png
...
Although they do nothing, they do add noise to the log output. Is there a way to fix this ? (without changing karma's logLevel of course, because I do want to see them)

That is because you need to configurate karma to load then serve them when requested ;)
In your karma.conf.js file you should already have defined files and/or patterns like :
// list of files / patterns to load in the browser
files : [
{pattern: 'app/lib/angular.js', watched: true, included: true, served: true},
{pattern: 'app/lib/angular-*.js', watched: true, included: true, served: true},
{pattern: 'app/lib/**/*.js', watched: true, included: true, served: true},
{pattern: 'app/js/**/*.js', watched: true, included: true, served: true},
// add the line below with the correct path pattern for your case
{pattern: 'path/to/**/*.png', watched: false, included: false, served: true},
// important: notice that "included" must be false to avoid errors
// otherwise Karma will include them as scripts
{pattern: 'test/lib/**/*.js', watched: true, included: true, served: true},
{pattern: 'test/unit/**/*.js', watched: true, included: true, served: true},
],
// list of files to exclude
exclude: [
],
// ...
You can have a look here for more info :)
EDIT : If you use a nodejs web-server to run your app, you can add this to karma.conf.js :
proxies: {
'/path/to/img/': 'http://localhost:8000/path/to/img/'
},
EDIT2 : If you don't use or want to use another server you can define a local proxy but as Karma doesn't provide access to port in use, dynamically, if karma starts on another port than 9876 (default), you will still get those annoying 404...
proxies = {
'/images/': '/base/images/'
};
Related issue : https://github.com/karma-runner/karma/issues/872

The confusing piece of the puzzle for me was the 'base' virtual folder. If you don't know that needs to be included in the asset paths of your fixtures you will find it hard to debug.
As-per the configuration documentation
By default all assets are served at http://localhost:[PORT]/base/
Note: this may not be true for other versions - I'm on 0.12.14 and it worked for me but the 0.10 docs dont mention it.
After specifying the files pattern:
{ pattern: 'Test/images/*.gif', watched: false, included: false, served: true, nocache: false },
I could use this in my fixture:
<img src="base/Test/images/myimage.gif" />
And I didn't need the proxy at that point.

You can create generic middleware inside your karma.conf.js
- bit over the top but did the job for me
First define dummy 1px images (I've used base64):
const DUMMIES = {
png: {
base64: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg==',
type: 'image/png'
},
jpg: {
base64: 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEAYABgAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCAABAAEDASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD3+iiigD//2Q==',
type: 'image/jpeg'
},
gif: {
base64: 'data:image/gif;base64,R0lGODlhAQABAAAAACwAAAAAAQABAAA=',
type: 'image/gif'
}
};
Then define middleware function:
function surpassImage404sMiddleware(req, res, next) {
const imageExt = req.url.split('.').pop();
const dummy = DUMMIES[imageExt];
if (dummy) {
// Table of files to ignore
const imgPaths = ['/another-cat-image.png'];
const isFakeImage = imgPaths.indexOf(req.url) !== -1;
// URL to ignore
const isCMSImage = req.url.indexOf('/cms/images/') !== -1;
if (isFakeImage || isCMSImage) {
const img = Buffer.from(dummy.base64, 'base64');
res.writeHead(200, {
'Content-Type': dummy.type,
'Content-Length': img.length
});
return res.end(img);
}
}
next();
}
Apply middleware in your karma conf
{
basePath: '',
frameworks: ['jasmine', '#angular/cli'],
middleware: ['surpassImage404sMiddleware'],
plugins: [
...
{'middleware:surpassImage404sMiddleware': ['value', surpassImage404sMiddleware]}
],
...
}

Based on #glepretre's answer, I've created an empty .png file and added this to the config to hide 404 warnings:
proxies: {
'/img/generic.png': 'test/assets/img/generic.png'
}

To fix, in your karma.conf.js make sure to point to the served file with your proxies:
files: [
{ pattern: './src/img/fake.jpg', watched: false, included: false, served: true },
],
proxies: {
'/image.jpg': '/base/src/img/fake.jpg',
'/fake-avatar': '/base/src/img/fake.jpg',
'/folder/0x500.jpg': '/base/src/img/fake.jpg',
'/undefined': '/base/src/img/fake.jpg'
}

Even though its an old thread, it took me a couple hours to actually get my image to actually be served from karma to eliminate the 404. The comments were just not thorough enough. I believe I can clarify the solution with this screenshot. Essentially the one thing that many comments were missing is the fact that the proxy value must start with "/base", even though base is not in any of my folder pathing, nor is it in my requests.
("base" without the forward slash resulted in karma returning a 400 BAD REQUEST)
Now after running ng test, I can successfully serve "./src/assets/favicon.png" from the url: http://localhost:9876/test/dummy.png
In my project I am using the following npm package versions:
karma v4.3.0
jasmine-core v3.2.1
karma-jasmine v1.1.2
#angular/cli v8.3.5
angular v8.2.7

If you have root path somewhere in your configuration file you can also use something like this:
proxies: {
'/bower_components/': config.root + '/client/bower_components/'
}

If you are using fake URLs for your images in test, you can write a custom middleware function to return 200 for URLs that start with "$", taken from Angular's own karma.conf.js:
karma.conf.js
module.exports = function (config) {
config.set({
middleware: ['fake-url'],
plugins: [
// ...
{
'middleware:fake-url': [
'factory',
function () {
// Middleware that avoids triggering 404s during tests that need to reference
// image paths. Assumes that the image path will start with `/$`.
// Credit: https://github.com/angular/components/blob/59002e1649123922df3532f4be78c485a73c5bc1/test/karma.conf.js
return function (request, response, next) {
if (request.url.indexOf('/$') === 0) {
response.writeHead(200);
return response.end();
}
next();
};
},
],
},
]
});
}
foo.spec.ts
img.src = '/$/foo.jpg'; // No 404 warning! :-)

Related

hash updated but the browser still loads the old cache using gulp-rev

I've been scratching head to bold due to this
I have set hash to name of all html files using gulp-rev and they are all matched in manifest file . I use gulp-rev-collector to match all updated hash as well .
I'm sure if any of content of client side file changed , I get new hashed file name after gulp
build but the Browser doesn't update and request new file , It still uses old cache file until I clean cache and hard reload .
here is simplified codes below:
gulp-rev
gulp.task('minify:html', function () {
var options = {
removeComments: true,
collapseWhitespace: true,
collapseBooleanAttributes: false,
removeEmptyAttributes: false,
removeScriptTypeAttributes: true,
removeStyleLinkTypeAttributes: true,
minifyJS: true,
minifyCSS: true
};
return gulp
.src([paths.src.html, '!./node_modules/**/*.html', '!./templates/**/*.html', '!./index.html',
'!./dist/**/*.html']) // views
.pipe(htmlmin(options))
.pipe(rev())
.pipe(gulp.dest('./dist'))
.pipe(rev.manifest())
.pipe(gulp.dest('./dist/rev/html'))
})
revision dist views
gulp.task('revDistViews', function () {
return gulp.src(['./dist/rev/**/*.json', './dist/views/*.html'])
.pipe( revCollector({
replaceReved: true,
}) )
.pipe( gulp.dest('./dist/views') );
})
gulp build
gulp.task('build', function (callback) {
runSequence('clean:dist', 'clean:views', 'scss', 'concat:js', 'file:include', 'copy:lib',
'copy:locales', 'copy:img', 'minify:html', 'minify:index', 'minify:scripts',
'revImages','minify:css', 'rev', 'revDistViews','revScripts', callback)
})
I can see hash changed after built in /dist folder . but the Chrome still use old Cache instead of new file
Is there any solution I could use by client side ?
Note: none of cache policy set in response header

Angular, Karma (SystemJS) XHR error (404 Not Found) - [Separate Src/Build]

I'm working with a build system using Angular(2), typescript, karma and SystemJs.
The application build works perfectly taking the src files from apps/samples/** to build/** this is the structure of the build directory. I run my gulp task build the files and browser-sync presents me with my app :)
apps/
samples/
app/
app.component.ts
app.module.ts
main.ts
assets/
scss/
js/ //#angular and other node libs get kept here
test/
app.component.spec.ts
index.html
systemjs.config.js
systemjs.config.extras.js
build/
app/
app.component.js
app.component.js.map
app.module.js
app.module.js.map
main.js
main.js.map
assets/
css/
js/ //#angular and other node libs get kept here
test/
app.component.spec.js
app.component.spec.js.map
index.html
systemjs.config.js
systemjs.config.extras.js
Gulpfile.babel.js
karma.conf.js
karma-test-shim.js
package.json
Now as mentioned before I have no problems with typescript or any other part of the build the problem comes when running karma I keep getting an error as follows:
Chrome 55.0.2883 (Windows 10 0.0.0) ERROR: 'Unhandled Promise rejection:', '(SystemJS) XHR error (404 Not Found) loading http://localhost:9876/base/systemjs.config.js
Error: XHR error (404 Not Found) loading http://localhost:9876/base/systemjs.config.js
Error loading http://localhost:9876/base/systemjs.config.js', '; Zone:', '<root>', '; Task:', 'Promise.then', '; Value:', Error{stack: '(SystemJS) XHR error (404 Not Found) loading http://localhost:9876/base/systemjs.config.js
Error: XHR error (404 Not Found) loading http://localhost:9876/base/systemjs.config.js
Error loading http://localhost:9876/base/systemjs.config.js', message: '(SystemJS) XHR error (404 Not Found) loading http://localhost:9876/base/systemjs.config.js
Error: XHR error (404 Not Found) loading http://localhost:9876/base/systemjs.config.js
Error loading http://localhost:9876/base/systemjs.config.js', originalStack: 'Error: (SystemJS) XHR error (404 Not Found) loading http://localhost:9876/base/systemjs.config.js
Error: XHR error (404 Not Found) loading http://localhost:9876/base/systemjs.config.js
Error loading http://localhost:9876/base/systemjs.config.js', zoneAwareStack: 'Error: (SystemJS) XHR error (404 Not Found) loading http://localhost:9876/base/systemjs.config.js
Error: XHR error (404 Not Found) loading http://localhost:9876/base/systemjs.config.js
Error loading http://localhost:9876/base/systemjs.config.js', name: 'Error', toString: function toString() { ... }, originalErr: Error{stack: 'Error: XHR error (404 Not Found) loading http://localhost:9876/base/systemjs.config.js', message: 'XHR error (404 Not Found) loading http://localhost:9876/base/systemjs.config.js', originalStack: 'Error: XHR error (404 Not Found) loading http://localhost:9876/base/systemjs.config.js', zoneAwareStack: 'Error: XHR error (404 Not Found) loading http://localhost:9876/base/systemjs.config.js', name: 'Error', toString: function toString() { ... }}}, '(SystemJS) XHR error (404 Not Found) loading http://localhost:9876/base/systemjs.config.js
Error: XHR error (404 Not Found) loading http://localhost:9876/base/systemjs.config.js
Error loading http://localhost:9876/base/systemjs.config.js'
Now i've been working from a combination of the angular quickstart project and a tutorial here https://www.agvision.ro/angular-2-karma-jasmine-unit-testing/
Here is my karma.config.js
module.exports = function(config) {
var appBase = 'build/app/'; // transpiled app JS and map files
var appSrcBase = 'apps/samples/app//'; // app source TS files
var appAssets = '/build/app/'; // component assets fetched by Angular's compiler
// Testing helpers (optional) are conventionally in a folder called `testing`
var testingBase = 'testing/'; // transpiled test JS and map files
var testingSrcBase = 'testing/'; // test source TS files
config.set({
basePath: '',
frameworks: ['jasmine'],
plugins: [
require('karma-jasmine'),
require('karma-chrome-launcher'),
require('karma-jasmine-html-reporter')
],
client: {
builtPaths: [appBase, testingBase], // add more spec base paths as needed
clearContext: false // leave Jasmine Spec Runner output visible in browser
},
customLaunchers: {
// From the CLI. Not used here but interesting
// chrome setup for travis CI using chromium
Chrome_travis_ci: {
base: 'Chrome',
flags: ['--no-sandbox']
}
},
files: [
// System.js for module loading
'node_modules/systemjs/dist/system.src.js',
// Polyfills
'node_modules/core-js/client/shim.js',
// zone.js
'node_modules/zone.js/dist/zone.js',
'node_modules/zone.js/dist/long-stack-trace-zone.js',
'node_modules/zone.js/dist/proxy.js',
'node_modules/zone.js/dist/sync-test.js',
'node_modules/zone.js/dist/jasmine-patch.js',
'node_modules/zone.js/dist/async-test.js',
'node_modules/zone.js/dist/fake-async-test.js',
// RxJs
{ pattern: 'node_modules/rxjs/**/*.js', included: false, watched: false },
{ pattern: 'node_modules/rxjs/**/*.js.map', included: false, watched: false },
// Paths loaded via module imports:
// Angular itself
{ pattern: 'node_modules/#angular/**/*.js', included: false, watched: false },
{ pattern: 'node_modules/#angular/**/*.js.map', included: false, watched: false },
{ pattern: 'build/systemjs.config.js', included: false, watched: false },
{ pattern: 'build/systemjs.config.extras.js', included: false, watched: false },
'karma-test-shim.js', // optionally extend SystemJS mapping e.g., with barrels
// transpiled application & spec code paths loaded via module imports
{ pattern: appBase + '**/*.js', included: false, watched: true },
{ pattern: testingBase + '**/*.js', included: false, watched: true },
// Asset (HTML & CSS) paths loaded via Angular's component compiler
// (these paths need to be rewritten, see proxies section)
{ pattern: appBase + '**/*.html', included: false, watched: true },
{ pattern: appBase + '**/*.css', included: false, watched: true },
// Paths for debugging with source maps in dev tools
{ pattern: appSrcBase + '**/*.ts', included: false, watched: false },
{ pattern: appBase + '**/*.js.map', included: false, watched: false },
{ pattern: testingSrcBase + '**/*.ts', included: false, watched: false },
{ pattern: testingBase + '**/*.js.map', included: false, watched: false}
],
// Proxied base paths for loading assets
proxies: {
// required for component assets fetched by Angular's compiler
"/app/": appAssets
},
exclude: [],
preprocessors: {},
reporters: ['progress', 'kjhtml'],
port: 9876,
colors: true,
logLevel: config.LOG_INFO,
autoWatch: true,
browsers: ['Chrome'],
singleRun: true
})
}
and here is my karma-test-shim.js
// /*global jasmine, __karma__, window*/
Error.stackTraceLimit = 0; // "No stacktrace"" is usually best for app testing.
// Uncomment to get full stacktrace output. Sometimes helpful, usually not.
// Error.stackTraceLimit = Infinity; //
jasmine.DEFAULT_TIMEOUT_INTERVAL = 1000;
// builtPaths: root paths for output ("built") files
// get from karma.config.js, then prefix with '/base/' (default is 'app/')
var builtPaths = (__karma__.config.builtPaths || ['app/'])
.map(function (p) {
return '/base/build/' + p;
});
__karma__.loaded = function () {
};
function isJsFile(path) {
return path.slice(-3) == '.js';
}
function isSpecFile(path) {
return /\.spec\.(.*\.)?js$/.test(path);
}
// Is a "built" file if is JavaScript file in one of the "built" folders
function isBuiltFile(path) {
return isJsFile(path) &&
builtPaths.reduce(function (keep, bp) {
return keep || (path.substr(0, bp.length) === bp);
}, false);
}
var allSpecFiles = Object.keys(window.__karma__.files)
.filter(isSpecFile)
.filter(isBuiltFile);
System.config({
baseURL: 'base/',
// Extend usual application package list with test folder
packages: {'testing': {main: 'index.js', defaultExtension: 'js'}},
// Assume npm: is set in `paths` in systemjs.config
// Map the angular testing umd bundles
map: {
'#angular/core/testing': 'npm:#angular/core/bundles/core-testing.umd.js',
'#angular/common/testing': 'npm:#angular/common/bundles/common-testing.umd.js',
'#angular/compiler/testing': 'npm:#angular/compiler/bundles/compiler-testing.umd.js',
'#angular/platform-browser/testing': 'npm:#angular/platform-browser/bundles/platform-browser-testing.umd.js',
'#angular/platform-browser-dynamic/testing': 'npm:#angular/platform-browser-dynamic/bundles/platform-browser-dynamic-testing.umd.js',
'#angular/http/testing': 'npm:#angular/http/bundles/http-testing.umd.js',
'#angular/router/testing': 'npm:#angular/router/bundles/router-testing.umd.js',
'#angular/forms/testing': 'npm:#angular/forms/bundles/forms-testing.umd.js',
},
});
System.import('systemjs.config.js').then(function (m) {
console.log(m);
})
//.then(importSystemJsExtras)
.then(initTestBed)
.then(initTesting);
/** Optional SystemJS configuration extras. Keep going w/o it */
function importSystemJsExtras() {
return System.import('systemjs.config.extras.js')
.catch(function (reason) {
console.log(
'Warning: System.import could not load the optional "systemjs.config.extras.js". Did you omit it by accident? Continuing without it.'
);
console.log(reason);
});
}
function initTestBed() {
return Promise.all([
System.import('#angular/core/testing'),
System.import('#angular/platform-browser-dynamic/testing')
])
.then(function (providers) {
var coreTesting = providers[0];
var browserTesting = providers[1];
coreTesting.TestBed.initTestEnvironment(
browserTesting.BrowserDynamicTestingModule,
browserTesting.platformBrowserDynamicTesting());
})
}
// Import all spec files and start karma
function initTesting() {
return Promise.all(
allSpecFiles.map(function (moduleName) {
return System.import(moduleName);
})
)
.then(__karma__.start, __karma__.error);
}
Now im getting the error and have read post after post after post some mention the base/ directory that karma puts files in, some have mentioned packages and modules and more but nowere gives a definitive answer as to why karma wont load system js.
Im a neewb with angular2 and prefer the build strucutre so wont be changing that aspect, anything else would be helpfull even if im missing something really simple.
Try changing:
{ pattern: 'build/systemjs.config.js', included: false, watched: false },
{ pattern: 'build/systemjs.config.extras.js', included: false, watched: false }
to:
{ pattern: '/systemjs.config.js', included: false, watched: false },
{ pattern: '/systemjs.config.extras.js', included: false, watched: false }

Karma (mocha) - Unexpected token N whenever unit test fails

I'm using Karma + Mocha to run my unit tests, everything works pretty well except whenever the tests fails,
When I run a test like
expect(player).to.be.an('object');
and it fails I would expect it to say that "Object was expected but string given" or something like that, Instead all I get is (for every single failed test, no matter how it fails, even when I try to asset true with false):
SyntaxError: Unexpected token N
at Object.parse (native)
at Array.map (native)
I know for a fact that there's no syntax errors in my code, so Im guessing that's something to do with karma/mocha and the way they handle the failed tests.. I just dont know where to look.. here is my gulp task:
var karmaServer = require('karma').server;
gulp.task('test', function (done) {
gutil.log('preparing tests.');
var runOnlyOnce = true;
// check if a parameter named "watch" is passed. if so - run tests in watch mode.
if (argv.watch){
runOnlyOnce = false;
}
if (runOnlyOnce){
gutil.log('Running only once.\nTo run in "watch" mode try: gulp test --watch');
} else {
gutil.log('Running in watch mode. Oh yeah.');
}
karmaServer.start({
configFile: __dirname +'/karma.conf.js',
singleRun: runOnlyOnce
}, function(exitCode) {
gutil.log('Karma has exited with ' + exitCode);
if (exitCode != 0){
gutil.log(gutil.colors.bgRed("Test(s) failed."));
}
process.exit(exitCode);
});
});
Here is my karma.conf file:
module.exports = function (config) {
'use strict';
config.set({
basePath: '',
frameworks: ['browserify', 'mocha', 'source-map-support'],
// reporters configuration
reporters: ['mocha'],
preprocessors: {
'test/**/*.spec.js': ['browserify']
},
files: [
{pattern: 'app/**/*.js', watched: true, included: false, served: false}, // watch these files, but dont bundle them for tests
'test/**/*.spec.js'
],
browserify: {
debug: true,
transform: ['babelify']
},
plugins: [
'karma-mocha-reporter',
'karma-mocha',
'karma-phantomjs-launcher',
'karma-chrome-launcher',
'karma-browserify',
'babel-plugin-espower',
'karma-ie-launcher',
'karma-source-map-support'
],
port: 9876,
colors: true,
usePolling: true,
atomic_save: false,
autoWatch : 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,
browsers: ["Chrome"] //, "IE", 'PhantomJS'
});
};
Any help would be much appreciated!!! Thank you!
So I found the problem, all I did was to remove the debug flag from the karma.conf file..
instead of
browserify: {
debug: true,
transform: ['babelify']
},
I did:
browserify: {
debug: false,
transform: ['babelify']
},
that did the trick.
I hope this helps anyone! cheers!

grunt-closure-tools config issue with multiple targets

I want to work with closure compiler, so I added grunt-closure-tools to my Grunt config, but my config is erroring with:
Verifying property closureCompiler.loader exists in config...ERROR
Here is the reference material for grunt-closure-tools:
https://www.npmjs.com/package/grunt-closure-tools
or
https://github.com/thanpolas/grunt-closure-tools
Here is my GruntFile.js:
module.exports = function(grunt) {
var path = require('path');
require('load-grunt-config')(grunt, {
//pkg: grunt.file.readJSON('package.json'),
configPath: path.join(process.cwd(), 'grunt'), //path to task.js files, defaults to grunt dir
init: true, //auto grunt.initConfig
data: { //data passed into config. Can use with <%= test %>
pkg: require('./package.json')
},
loadGruntTasks: { //can optionally pass options to load-grunt-tasks. If you set to false, it will disable auto loading tasks.
pattern: ['grunt-contrib-*', 'grunt-jslint', 'grunt-newer', 'imagemin-*','grunt-closure-tools'],
scope: 'devDependencies'
},
postProcess: function(config) {} //can post process config object before it gets passed to grunt
});
//require('load-grunt-tasks')(grunt);
grunt.registerTask("default", ["newer:jslint", "newer:concat", "closureCompiler:loader", "newer:sass"]);
};
I am using load-grunt-config to break up my config into multiple parts. Here is my closure.js file, mostly modeled on grunt-closure-tools github page example:
module.exports = {
options: {
compilerFile: '/usr/local/Cellar/closure-compiler/20141023/libexec/build/compiler.jar',
checkModified: true,
compilerOpts: {
create_source_map: null,
compilation_level: 'ADVANCED_OPTIMIZATIONS',
},
d32: true, // will use 'java -client -d32 -jar compiler.jar'
},
util: {
src: 'includes/javascript/util/util.js',
dest: 'includes/javascript/build/util.min.js'
},
loader: {
src : 'includes/javascript/loaders/loader.js',
dest: 'includes/javascript/build/loader.min.js'
}
};
Any help with this error is appreciated.
After some digging and no small amount of thrashing of teeth, I have managed to getting my config working. My Gruntfile.js:
module.exports = function(grunt) {
var path = require('path');
require('load-grunt-config')(grunt, {
//pkg: grunt.file.readJSON('package.json'),
configPath: path.join(process.cwd(), 'grunt'), //path to task.js files, defaults to grunt dir
init: true, //auto grunt.initConfig
data: { //data passed into config. Can use with <%= test %>
pkg: require('./package.json')
},
loadGruntTasks: { //can optionally pass options to load-grunt-tasks. If you set to false, it will disable auto loading tasks.
pattern: ['grunt-contrib-*', 'grunt-jslint', 'grunt-newer', 'imagemin-*','grunt-closure-tools'],
scope: 'devDependencies'
},
postProcess: function(config) {} //can post process config object before it gets passed to grunt
});
//require('load-grunt-tasks')(grunt);
grunt.registerTask("default", ["newer:jslint", "newer:concat", "closureCompiler:loader", "newer:sass"]);
};
and my closureCompiler.js file (shortened for clarity):
module.exports = {
options: {
compilerFile: '/usr/local/Cellar/closure-compiler/20141023/libexec/build/compiler.jar',
checkModified: true,
compilerOpts: {
// create_source_map: null
},
execOpts: {
maxBuffer: 999999 * 1024
},
TieredCompilation: true // will use 'java -server -XX:+TieredCompilation -jar compiler.jar'
},
loader: {
TEMPcompilerOpts: {
create_source_map: 'includes/javascript/build/loader.min.js.map'
},
src : 'includes/javascript/loaders/loader.js',
dest: 'includes/javascript/build/loader.min.js'
}
};
I had quite a few errors in my config:
I had to rename closure.js to closureCompiler.js so load-grunt-config could find the file. Oops, my bad.
The d32: true switch on the Closure Compiler means use 32-bit JVM, which I do not have on my system. I switched to TieredCompilation: true instead.
create_source_map: null in the options did not work for me. I found the reference in the source code of grunt-closure-tools but didn't spend the time to sort out what was wrong. Instead, I added TEMPcompilerOpts to the target config with the map file I wanted Closure to make.
I hope other benefit from my experience with this solution. From this point, I am going to use the ability of Closure Compiler to create source maps to merge my dev and prod build targets into a single target.

How to use testr with karma-jasmine adapter?

Everything works (Karama, Jasmine, Underscore, Backbone, testr) as evidenced by the _UnitTestUnitTest passing. But simple testr statements always fail.
The basic _UnitTestUnitTest works!
it('works for jquery', function() {
expect( $("document")).toBeTruthy();
});
it('works for underscore', function() {
expect(_.size([1,2,3])).toEqual(3);
});
it('works for backbone', function() {
var model = Backbone.Model.extend();
expect(model).toBeTruthy();
});
it('works for testr', function() {
expect(testr).toBeTruthy();
});
However, in my other real unit test, it fails on the testr line:
AccountSummaryCollection_CLASS = testr('models/sales-rep/AccountSummaryCollection');
I'm certain i'm including my dependency of 'models/sales-rep/AccountSummaryCollection' correctly in my config (I see it hosted and getting loaded by require.js deps!!!
However, the big problem is it claims our application module is not loaded even though it is. I also tried to wrap the whole AccountSummaryUnitTest.js inside of require([‘AccountSummaryCollection’], function(){…. This produces a new error where inside a dependency (AccountSummary.js) the error “Backbone is not defined” is thrown. That makes no sense in the context because obviously the AccountSummaryCollection has already resolved Backbone.Collection. This bad resolution is what makes me suspect it is testr that is fishy.
I also tried to manually include the file using the karma config, but requirejs does not like that since it’s a conflicting define() function.
Below: serving actually means Requested by Client and the {{{dependency}}} file is my own trace to confirm they are added to the deps list in the karma-spec-runner.js.
It fails at this line:
AccountSummaryUnitCollection line 27: AccountSummaryCollection_CLASS = testr('models/sales-rep/AccountSummaryCollection');
Here's the "spec runner" javascript (basically copied from the docs, with some extra logging).
var dependencies = [];
for (var file in window.__karma__.files) {
if (window.__karma__.files.hasOwnProperty(file)) {
//
if (/Test\.js$/.test(file)) {
//traces my test files fine!
console.log("{{{testing file}}} --> "+ file );
dependencies.push(file);
}
}
}
// jam our application files into the deps
for (var file in window.__karma__.files) {
if (window.__karma__.files.hasOwnProperty(file)) {
if (file.indexOf('src/main/app/') !== -1 ) {
//traces my dep files fine!
console.log("{{{dependency}}} file --> "+ file );
dependencies.push(file);
}
}
}
require.config({
baseUrl: 'base/src/main/app/',
paths: {
'resources' : '../resources/',
'jquery' : '../resources/js/lib/jquery-2.1.0.min',
'text' : '../resources/js/lib/text-2.0.10',
'i18n' : '../resources/js/lib/i18n-2.0.4',
'd3' : '../resources/js/lib/d3.v3.1.10.min',
'AppMeasurement' : '../resources/js/lib/appMeasurement',
'underscore' : '../resources/js/lib/underscore-1.5.2',
'Backbone' : '../resources/js/lib/backbone-1.1.2.min',
'testr' : '../../test/lib/testr'
},
deps: dependencies,
shim: {
d3: {
exports: 'd3'
},
AppMeasurement: {
exports: 'AppMeasurement'
},
underscore: {
deps:["jquery"],
exports: '_'
},
Backbone: {
deps:["jquery"],
exports: 'Backbone'
},
testr:{
exports: 'testr'
}
},
callback: window.__karma__.start,
locale: "en-us"
});
Here's the karma section of my gruntfile
karma: {
unit: {
background: false,
options: {
logLevel : 'debug',
basePath:'./',
// files for karma to host
files: [
{pattern: 'src/main/resources/js/lib/**/*.js', included: false, served: true},
{pattern: 'src/main/resources/js/plugins/**/*.js', included:false, served: true },
{pattern: 'src/test/lib/sinon.js', included: false },
{pattern: 'src/test/lib/testr.js', included: false },
{pattern: 'src/test/js/stubs/**/*.js', included: false, served: true},
// manually load our application unit test & deps to examine the simplest case
{pattern:'src/main/app/models/sales-rep/AccountSummary.js', included: false },
{pattern:'src/main/app/models/sales-rep/AccountSummaryCollection.js', included: false },
{pattern: '_UnitTestUnitTest.js', included: false},
{pattern: 'src/test/js/unit/AccountSummaryCollectionUnitTest.js', included: false},
'src/test/js/karma-spec-runner.js'
],
plugins: [
"karma-jasmine",
"karma-phantomjs-launcher",
"karma-requirejs",
'karma-chrome-launcher',
],
frameworks: [
"jasmine",
"requirejs"
],
browsers: [
//"PhantomJS"
"Chrome"
]
}
}
},
Here's a sample test that fails
Note that the testr config is per unit test. Plus, this test WORKS in plain in the browser jasmine!
// tried with and without the leading require statement as noted in main question.
require( ['models/sales-rep/AccountSummaryCollection'], function() {
describe('AccountSummaryCollectionUnitTest', function () {
var AccountSummaryCollection_CLASS;
function configureTestr() {
testr.config({
whitelist: [
'models/sales-rep/AccountSummaryCollection',
'models/sales-rep/AccountSummary'
]
});
}
beforeEach(function () {
configureTestr();
console.log("initializing AccountSummaryCollection_CLASS");
//fails on following line
AccountSummaryCollection_CLASS = testr('models/sales-rep/AccountSummaryCollection');
});
You need specific versions of libs to get it to work right:
testr 1.0.2 (NOT 1.0.3!!!!!)
Backbone 1.0.0 (not 1.1.2 for some reason)
underscore 1.6
require-2.1.11 [production] (for some reason we had 2.1.2)
Then I had to include:true for underscore and backbone in the Karma config. Then the shim works with require 2.1.11 without the mismatched anonymous define error.
Additioanlly, to make sure to delay the test execution. I did not have luck with the waitSeconds (that just increases the test duration).
The key part of the require config:
// since we are forcing Backbone in the dom instead of requiring it
callback: function(){
setTimeout(function () {
window.__karma__.start();
}, 4000);
},

Categories