How to use testr with karma-jasmine adapter? - javascript

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);
},

Related

Load Test csript inside test in intern.js

I'm trying to load test script according to custom argument passed through start command to start intern test.
To do this I'm trying to require the specific test script inside a test but i am getting Attempt to require unloaded module error.
This is my code set up. Can someone help on on this or sugest some alternative work around to make this work.
define(function (require) {
var intern = require('intern');
var AdvalentAutomationTestSuite = require('intern!object');
AdvalentAutomationTestSuite({
name: 'Advalent Automation Test',
'AdvalentTestSets': function () {
return this.remote
.then(function () {
var product = intern.args.product;
var script = 'Automation/TestScripts/FRG/' + product + '-Config';
require(script)
})
},
});
});
Update:
Including intern.js file:
define(function (require) {
var intern = require('intern');
console.log(intern)
return {
proxyPort: 9000,
proxyUrl: 'http://localhost:9000/',
defaultTimeout: 120000,
capabilities: {
'selenium_version': '2.48.2',
},
environments: [
{browserName: 'chrome', version: '48', platform: ['WINDOWS'], chromeOptions: {args: ['start-maximized']}},
],
maxConcurrency: 3,
tunnel: 'NullTunnel',
reporters: [
{id: 'JUnit', filename: 'test-reports/report.xml'},
{id: 'Runner'},
],
Loaders: {
'host-node': 'dojo/dojo',
'host-browser': 'node_modules/dojo/dojo.js'
},
loaderOptions: {
packages: [{name: 'intern-tutorial', location: '.'}]
},
functionalSuites: [
'Automation/TestScripts/FRG/FRG-Config',
],
defaultTimeout: 70000,
excludeInstrumentation: /^(?:tests|node_modules)\//
}
});
You should be fine with the default loader, although as #Troopers points out, it's loaders, not Loaders. The problem is that you're doing a dynamic require with a computed name:
var script = 'Automation/TestScripts/FRG/' + product + '-Config';
require(script)
AMD loaders don't completely support the require(script) syntax since they don't load modules synchronously. When a module is written in CJS-compatibility mode, the loader fakes it by scanning the module code for require calls and then preloading and caching the modules before executing the module code. When the require(script) call is eventually executed, the preloaded module is returned.
When you use a computed module name, the loader can't preload the module being required, so the synchronous require call will fail. To load a module with a computed name you'll need to use the require([ dependency ]) syntax, like:
var script = 'Automation/TestScripts/FRG/' + product + '-Config';
return new Promise(function (resolve) {
require([ script ], resolve);
});
At a higher level, though, it seems odd to be doing this in a test in the first place. It seems like something that should be handled at the module or config levels. For example, assuming 'Automation/TestScripts/FRG/' + product + '-Config' is a functional test suite, the config could simply add that suite to the functionalSuites list if the required command line argument were provided.
You need to specify a loader in your configuration file :
loaders: {
"host-node": "requirejs",
"host-browser": "node_modules/requirejs/require.js"
},
And install the npm package requirejs
The documentation is here
After few hit and trial I managed to make it work by changing my intern.js as follows:
define(function (require) {
var intern = require('intern');
var product = intern.args.product
return {
functionalSuites: [
'Automation/TestScripts/FRG/' + product + '-Config.js',
],
// rest of config code ...
}
});
Please suggest if there's any better way to do this.

requirejs throws a 404 trying to load a file from karma runner

I am trying to load a test helper module using requirejs, but it fails even when it has been already loaded as a dependency at the start of karma run, and I can't figure out what's the problem, I always get
There is no timestamp for /base/spec/helpers/testHelpers!'
Tests run fine, inside them I require any module of the app without problem, it only fails when I require specifically something from spec folder.
I have checked all karma related questions and none of them apply to these case.
My karma.conf file:
module.exports = function (config) {
'use strict';
config.set({
basePath: '',
frameworks: ['jasmine', 'requirejs'],
files: [
'bootstrapTests.js',
{
pattern: 'app/**/*.js',
included: false
},
{
pattern: 'entities/**/*.js',
included: false
},
{
pattern: 'config/**/*.js',
included: false
},
{
pattern: 'libs/**/*.js',
included: false
},
{
pattern: 'spec/**/*Spec.js',
included: false
},
{
pattern: 'spec/helpers/**/*.js',
included: false
}
],
exclude: [
'bootstrap.js',
'bootstrap.built.js'
],
preprocessors: {
'app/**/*.js': ['coverage'],
'entities/**/*.js': ['coverage']
},
coverageReporter: {
reporters: [
{
type: 'text-summary'
}
]
},
reporters: ['progress', 'coverage'],
port: 9876,
colors: true,
logLevel: config.LOG_INFO,
autoWatch: true,
browsers: ['PhantomJS'],
singleRun: false
});
};
My bootstrapTests.js file:
var tests = [];
for (var file in window.__karma__.files) {
if (window.__karma__.files.hasOwnProperty(file)) {
// Add all spec files and helpers
if (/spec\/.+.js$/.test(file)) {
tests.push(file);
}
}
}
require.config({
baseUrl: '/base',
paths: {
'backbone': 'libs/backbone',
'marionette': 'libs/backbone.marionette',
'jquery': 'libs/jquery-2.1.1',
'json2': 'libs/json2',
'underscore': 'libs/underscore',
'twig': 'libs/twig',
'editor': 'app/editor',
'widgets': 'app/widgets',
'menu': 'app/menu',
'helpers': 'spec/helpers'
},
map: {
'*': {
'jquery': 'config/jquery/jqueryPrivate'
},
'config/jquery/jqueryPrivate': { 'jquery': 'jquery' }
},
deps: tests,
callback: window.__karma__.start
});
so in my tests,
define([
'app/app',
'backbone',
'editor/editorController',
'editor/editorApp',
], function (
myApp,
Backbone,
editorController
) {
'use strict';
describe('editorApp', function () {
.....
works like a charm, but when I try
define([
'app/common/routerUtilities',
'backbone',
'helpers/testHelpers'
], function (
routerUtilities,
Backbone,
testHelpers
) {
'use strict';
describe('routerUtilities', function () {
...
it fails trying to fetch testHelpers, always get the error even when the module is already loaded. I tried specifying the path in all possible ways besides the shortened one: spec/helpers/testHelpers, /base/spec/helpers/testHelpers, /spec/helpers/testHelpers, ../../helpers/testHelpers, etc...
The file is included in tests array as a dependency (checked), so it's loaded (checked with console.log) along my tests and other test setup modules:
LOG: ['/base/spec/app/appSpec.js',
'/base/spec/app/common/routerUtilitiesSpec.js',
'/base/spec/app/editor/EditorLayoutViewSpec.js',
'/base/spec/app/editor/editorAppSpec.js',
'/base/spec/app/editor/editorControllerSpec.js',
'/base/spec/app/menu/menuControllerSpec.js',
'/base/spec/helpers/envSetup.js',
'/base/spec/helpers/testHelpers.js']
I've checked that is included in window._ karma _.files as well (edited for brevity):
LOG: Object{
/base/bootstrapTests.js: 'c389a1d36d1c48f2879d434b10fd5a25b6b07758',
/base/app/app.js: '7ad39554809146effd20dd1db908fc068f8119ba',
/base/app/common/routerUtilities.js: '4da0e1d1794cccc727b544cacbc6d672c0d9965a',
...
/base/config/marionette/renderer.js: '34a5e729f6133aa13841c5e949307cd437ca331b',
/base/config/marionette/templateCache.js: '9f1901d4c6f43f5f90dadacb1c4ac179efd14b15',
/base/spec/app/appSpec.js: 'e01f4fea3533e25cfcd4f7621e1c1c5559e0eed8',
/base/spec/app/common/routerUtilitiesSpec.js: 'a06b9793a635633d053142dff24d1ba4427dd365',
/base/spec/app/editor/EditorLayoutViewSpec.js: 'a24c7e8742e38b86d626bd6f3e45baacfa6af5eb',
/base/spec/app/editor/editorAppSpec.js: '800c0e8e82840ebd0d1af07c3ec4556a24ee0b04',
/base/spec/app/editor/editorControllerSpec.js: 'd2e259a477da85b6a2f742f5c6c3a4a34b7e340b',
/base/spec/helpers/envSetup.js: '297aa1e59477d967aa210bece1726e8a372cb630',
/base/spec/helpers/testHelpers.js: '5266065d344ca69f8f5980db16bf6d131492ebd0'
}
The content of spec/helpers/testHelpers.js is:
define([
'backbone'
], function (
Backbone
) {
'use strict';
var testHelpers = {
setupRoutingTest: function () {
Backbone.history.start();
Backbone.history.navigate('');
},
teardownRoutingTest: function () {
Backbone.history.navigate('');
Backbone.history.stop();
}
};
return testHelpers;
});
My folder structure is:
|-app
|---common
|---editor
|---menu
|---widgets
|-config
|---jquery
|---marionette
|-entities
|-features
|-gruntTasks
|---lib
|-spec
|---app
|-----common
|-----editor
|-----menu
|-----widgets
|---entities
|---helpers
|-tmp
Hi it looks like the karma-requirejs doesn't like the resources to be loaded into the tests array.
Try to modify the code to exclude the helper files and it could help
var tests = [];
for (var file in window.__karma__.files) {
if (window.__karma__.files.hasOwnProperty(file)) {
// Add all spec files and helpers
if (/spec\/.+.js$/.test(file)) {
tests.push(file);
}
}
}
This drove me a little nuts a while back. Make sure you're using karma-requirejs, not just requirejs.
https://www.npmjs.org/package/karma-requirejs
On that note, don't also load the production version of requirejs.

Grunt build not exposing the globals I need

When I run my project locally with my grunt:server task, the project works as I expect. However, after building which takes all the vendor code and puts it into one file, two of my needed module aren't avialable, and the project doesn't work.
Here is my requirejs configuration:
requirejs.config
baseUrl: './js'
shim:
'underscore':
exports: '_'
'backbone':
deps: ['underscore', 'jquery']
exports: 'Backbone'
'stack':
deps: ['d3.global']
exports: 'stack'
'highlight':
exports: 'hljs'
paths:
'underscore': '../components/underscore/underscore'
'backbone': '../components/backbone/backbone'
'jquery': '../components/jquery/jquery'
'd3': '../components/d3/d3'
'd3.global': '../components/d3.global/d3.global'
'stack': '../components/stack/stack'
'highlight': '../components/highlightjs/highlight.pack'
require ['app/vendors'],->
console.log("Backbone", Backbone)
console.log("_", _)
console.log("$", $)
console.log("d3", d3)
console.log("stack", stack)
console.log("hljs", hljs)
app/vendors looks like
define [
'underscore'
'jquery'
'backbone'
'text'
'd3.global'
'stack'
'highlight'
], ->
When I run the project locally via grunt, I see all the globals printed out. However, when I build the project, Backbone Underscore and JQuery print out, while stack fails (hljs is also not available, and if I remove stack from app/vendors, it doesn't fix highlight, so its probably not an order thing).
the requirejs optimizer is called with the following configuration:
requirejs:
compile:
options:
baseUrl: 'js/'
appDir: './<%= yeoman.tmp_dist %>/'
dir: './<%= yeoman.dist %>/'
wrap: true
removeCombined: true
keepBuildDir: true
inlineText: true
mainConfigFile: '<%= yeoman.tmp_dist %>/js/main.js'
# no minification, is done by the min task
optimize: "none"
modules: [
{ name: 'app/vendors', exclude: [] }
{ name: 'app/app', exclude: ['app/vendors'] }
{ name: 'main', exclude: ['app/app', 'app/vendors'] }
Could there be something wrong with the stack and highlight files that I need to fix in order to make requirejs optimization and uglify work with them?
I installed highlightjs via bower by adding "highlightjs": "~8.0" to my bower.json file and running bower install. I downloaded stack.js from mbostock's stack project. I'm using v0 at the moment, with minor changes to make it work in this project. The source for all these are in the components directory of my github project.
BOUNTY If anyone is willing to clone the repo themselves, and try running the project with grunt server and grunt build to help me track down the problem, I'd greatly appreciate it. At the moment I have the vendor scripts in the github repo itself, so all you should need is compass and bower to run it.
This is due to wrap: true in the r.js config. Here's a simple configuration that isolates the issue:
main.js
define([ 'legacy' ], function(legacy) {
var greeting = 'hi';
console.log(greeting, legacy.foo);
});
legacy.js
var globalThing = { foo: 1, bar: 2 };
build.json
{
"name": "main",
"optimize": "none",
"out": "main-built.js",
"shim": { "legacy": { "exports": "globalThing" } },
"wrap": true
}
Let's run r.js (r.js -o build.json) and consider the result (formatted by me):
(function() { // this immediately-invoked function expression (IIFE)
// is here because r.js has "wrap: true" in the config
var globalThing = { foo: 1, bar: 2 };
// code generated from the "shim" entry in the config
define('legacy', function(global) {
return function() {
var ret, fn;
// since global.globalThing is undefined,
// that's where it goes wrong
return ret || global.globalThing;
};
}(this));
define('main', [ 'legacy' ], function(legacy) {
var greeting = 'hi';
console.log(greeting, legacy.foo);
});
})(); // end of the IIFE
As you can see from the code above, globalThing isn't global any more. The same happens with the stack and highlight libraries in your project as they use var and function declarations to define their globals.
To tackle this issue, we have a couple of options. The first is to consider whether you really need wrap: true in the config. If you drop it, the globals will get global again and everything should start working as expected. The second option is to try adding wrapShim: true to the config. You can read about nuances of using this option here. If we try it with our sample configuration, we'll get something like this:
(function() {
(function(root) {
define('legacy', [], function() {
return function() {
var globalThing = { foo: 1, bar: 2 };
return root.globalThing = globalThing;
}.apply(root, arguments);
});
})(this);
define('main', [ 'legacy' ], function(legacy) {
var greeting = 'hi';
console.log(greeting, legacy.foo);
});
})();
Looks good to me.

how to fix 404 warnings for images during karma unit testing

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! :-)

Require.js Error: Load timeout for modules: backbone,jquerymobile

I am trying to use r.js to optimize my code but I keep running to this error:
Tracing dependencies for: init
Error: Load timeout for modules: backbone,jquerymobile
The command I am running is this:
$ java -classpath /Users/dixond/build-tools/rhino1_7R4/js.jar:/Users/dixond/build-tools/closurecompiler/compiler.jar org.mozilla.javascript.tools.shell.Main /Users/dixond/build-tools/r.js/dist/r.js -o /Users/dixond/Sites/omm_mobile/js/build.js
My build.js file looks like this:
( {
//appDir: "some/path/",
baseUrl : ".",
mainConfigFile : 'init.js',
paths : {
jquery : 'libs/jquery-1.8.3.min',
backbone : 'libs/backbone.0.9.9',
underscore : 'libs/underscore-1.4.3',
json2 : 'libs/json2',
jquerymobile : 'libs/jquery.mobile-1.2.0.min'
},
packages : [],
shim : {
jquery : {
exports : 'jQuery'
},
jquerymobile : {
deps : ['jquery'],
exports : 'jQuery.mobile'
},
underscore : {
exports : '_'
},
backbone : {
deps : ['jquerymobile', 'jquery', 'underscore'],
exports : 'Backbone'
}
},
keepBuildDir : true,
locale : "en-us",
optimize : "closure",
skipDirOptimize : false,
generateSourceMaps : false,
normalizeDirDefines : "skip",
uglify : {
toplevel : true,
ascii_only : true,
beautify : true,
max_line_length : 1000,
defines : {
DEBUG : ['name', 'false']
},
no_mangle : true
},
uglify2 : {},
closure : {
CompilerOptions : {},
CompilationLevel : 'SIMPLE_OPTIMIZATIONS',
loggingLevel : 'WARNING'
},
cssImportIgnore : null,
inlineText : true,
useStrict : false,
pragmas : {
fooExclude : true
},
pragmasOnSave : {
//Just an example
excludeCoffeeScript : true
},
has : {
'function-bind' : true,
'string-trim' : false
},
hasOnSave : {
'function-bind' : true,
'string-trim' : false
},
//namespace: 'foo',
skipPragmas : false,
skipModuleInsertion : false,
optimizeAllPluginResources : false,
findNestedDependencies : false,
removeCombined : false,
name : "init",
out : "main-built.js",
wrap : {
start : "(function() {",
end : "}());"
},
preserveLicenseComments : true,
logLevel : 0,
cjsTranslate : true,
useSourceUrl : true
})
And my init.js looks like this:
requirejs.config({
//libraries
paths: {
jquery: 'libs/jquery-1.8.3.min',
backbone: 'libs/backbone.0.9.9',
underscore: 'libs/underscore-1.4.3',
json2 : 'libs/json2',
jquerymobile: 'libs/jquery.mobile-1.2.0.min'
},
//shimming enables loading non-AMD modules
//define dependencies and an export object
shim: {
jquerymobile: {
deps: ['jquery'],
exports: 'jQuery.mobile'
},
underscore: {
exports: '_'
},
backbone: {
deps: ['jquerymobile', 'jquery', 'underscore', 'json2'],
exports: 'Backbone'
}
}
});
requirejs(["backbone",], function(Backbone) {
//Execute code here
});
What am I doing wrong in this build process?
Require.js has a Config option called waitSeconds. This may help.
RequireJS waitSeconds
Here's an example where waitSeconds is used:
requirejs.config({
baseUrl: "scripts",
enforceDefine: true,
urlArgs: "bust=" + (new Date()).getTime(),
waitSeconds: 200,
paths: {
"jquery": "libs/jquery-1.8.3",
"underscore": "libs/underscore",
"backbone": "libs/backbone"
},
shim: {
"underscore": {
deps: [],
exports: "_"
},
"backbone": {
deps: ["jquery", "underscore"],
exports: "Backbone"
},
}
});
define(["jquery", "underscore", "backbone"],
function ($, _, Backbone) {
console.log("Test output");
console.log("$: " + typeof $);
console.log("_: " + typeof _);
console.log("Backbone: " + typeof Backbone);
}
);
The Error
I recently had a very similar issue with an angularJS project using requireJS.
I'm using Chrome canary build (Version 34.0.1801.0 canary) but also had a stable version installed (Version 32.0.1700.77) showing the exact same issue when loading the app with Developer console open:
Uncaught Error: Load timeout for modules
The developer console is key here since I didn't get the error when the console wasn't open. I tried resetting all chrome settings, uninstalling any plugin, ... nothing helped so far.
The Solution
The big pointer was a Google group discussion (see resources below) about the waitSeconds config option. Setting that to 0 solved my issue. I wouldn't check this in since this just sets the timeout to infinite. But as a fix during development this is just fine. Example config:
<script src="scripts/require.js"></script>
<script>
require.config({
baseUrl: "/another/path",
paths: {
"some": "some/v1.0"
},
waitSeconds: 0
});
require( ["some/module", "my/module", "a.js", "b.js"],
function(someModule, myModule) {
//This function will be called when all the dependencies
//listed above are loaded. Note that this function could
//be called before the page is loaded.
//This callback is optional.
}
);
</script>
Most common other causes for this error are:
errors in modules
wrong paths in configuration (check paths and baseUrl option)
double entry in config
More Resources
Troubleshooting page from requireJS: http://requirejs.org/docs/errors.html#timeout point 2, 3 and 4 can be of interest.
Similar SO question: Ripple - Uncaught Error: Load timeout for modules: app http://requirejs.org/docs/errors.html#timeout
A related Google groups discussion: https://groups.google.com/forum/#!topic/requirejs/70HQXxNylYg
In case others have this issue and still struggling with it (like I was), this problem can also arise from circular dependencies, e.g. A depends on B, and B depends on A.
The RequireJS docs don't mention that circular dependencies can cause the "Load timeout" error, but I've now observed it for two different circular dependencies.
Default value for waitSeconds = 7 (7 seconds)
If set to 0, timeout is completely disabled.
src: http://requirejs.org/docs/api.html
The reason for the issue is that Require.js runs into the timeout since the project might have dependencies to large libraries. The default timeout is 7 seconds. Increasing the value for this config option (called waitSeconds) solves it of course but it is not the right approach.
Correct approach would be to improve the page loading time. One of the best technics to speed up a page loading is minification - the process of compressing the code. There are some good tools for minification like r.js or webpack.
I only get this error when running tests on Mobile Safari 6.0.0 (iOS 6.1.4). waitSeconds: 0 has given me a successful build for now. I'll update if my build fails on this again
TLDR:
Requiring the same file twice with two valid different names, possibly two of the following:
absolute path: '/path/to/file.js'
relative path: './path/to/file.js'
as a module: 'path/to/file'
as a module on main paths config:
paths: {
'my/module/file' : '/path/to/file'
}
Recently had this same issue. I did change some require paths in bulk so I knew the issue was about that.
I could clearly see on both server side logs and network debugging tab the file being served in less than a second. It was not a real timeout issue.
I tried to use xrayrequire as suggested to find any circular dependency without success. I looked for requires of the conflicting file and found out I was requiring it twice with different names.

Categories