Open piebe opened 9 years ago
I've never used it myself, but does bundle
property in the SystemJS config help?
https://github.com/systemjs/systemjs/blob/master/docs/config-api.md#bundle
The biggest pain is that you need to list out the modules included in the bundle, or at least one which you know will always get loaded. We could change 'karma-systemjs' to always load any bundles it finds in the SystemJS config ahead of time.
I'm not sure how this would solve the problem? The bundle is actually already loaded properly. The problem is that the module names inside the bundle register with a name that does not start with /base/ while karma-systemjs changes the baseurl to /base/. The code under test does search the modules out of the bundle with the /base/ prefix and the modules are not found.
I found a workaround by listing all modules inside the bundle in config.paths and let them jump out of the base directory. Again using angular.js as an example:
paths: {
'angular.js': '../angular.js'
}
However, given the number of modules and bundles I will be working with, this is not a very practical solution.
Wow, ok. I always assumed the baseURL was only ever used when retrieving modules from the server. Once they were retrieved (eg. Run through System.register()), I assumed the baseURL was forgotten. Though I suppose that would cause problems if you legitimately had to go below the base. eg. Folders 'app/' and 'lib/', and 'app/' is the baseURL.
Hmmm. I'm not sure. I can only think of 3 possible solutions:
paths
instead of baseURL
to handle the base/
prefix in Karma (eg. {paths: {'/': '/base/', '/': '/base/'}})I know https://github.com/Workiva/karma-jspm supports bundles. I'll take a closer look at how they solve it.
I think I have a related issue:
My config.js (in src/main/javascript) has:
System.config({
"baseURL": "/js"
}
In my karma.conf.js (in /) I can fix "paths":
"basePath": "src/main/javascript",
"config": {
"paths": {
// Add extra ../ to counteract '/js' above:
"babel": "../../../../node_modules/babel-core/browser.js",
But I can't fix "files":
"files": [
"app/testing/**/*.js",
],
So I get errors:
[web-server]: 404: /base/js/app/main.js (unwanted /js)
In this case, I just want to karma-systemjs to recognize the config.js baseURL param and adjust path requests accordingly (i.e., in this case serve "files" from "/js"). Or provide a "config" baseURL option.
[Side question]: AFAYAC, what are the pros and cons of karma-systemjs vs karma-jspm?
Hi @richburdon
Your issue isn't related because it doesn't look like you're using bundles anywhere.
You can still use paths
for files
, you just need to understand that files
paths will be mapped to /base/{baseURL}/{path}
on the browser.
So you should be able to use paths['app/testing/*'] = '/src/main/javascript/app/testing/*';
or something similar to get your paths working.
For your side question, the philosophical differences between karma-systemjs
and karma-jspm
is that karma-jspm
assumes you're using JSPM, and therefore can make certain predictions by using your package.json
file, while karma-systemjs
can only assume you're using SystemJS - nothing more, nothing less.
My personal recommendation is that if you're using JSPM, then use karma-jspm
.
Also sorry @piebe, I haven't had the time to look into bundles yet. I'd be more than happy to merge in a PR if anyone else gets to it first.
Hi, I think I have a similar issue as described by @piebe. In karma.conf.js
config object, I register the Angular 2 dev bundle that registers many modules:
files: [
"../../node_modules/angular2/bundles/angular2.dev.js",
// ...
],
The bundle registrations in angular2.dev.js
are in the format:
System.register("angular2/angular2", ["angular2/common", /* ... other dependencies */], true, function(require, exports, module) {
// ...
});
I can see in logs/Chrome dev tool that the angular 2 bundle is well loaded, but all other imports are not. Example, errors from Karma logs:
11 12 2015 21:03:22.490:WARN [web-server]: 404: /base/angular2/http.js
11 12 2015 21:03:22.554:WARN [web-server]: 404: /base/angular2/http/testing.js
11 12 2015 21:03:22.569:WARN [web-server]: 404: /base/angular2/testing.js
11 12 2015 21:03:22.606:WARN [web-server]: 404: /base/angular2/angular2.js
I think it is caused by imports like import {...} from 'angular2/angular2
.
But I don't know if it is related to the /base/ prefix. When I apply @piebe's workaround, I get instead:
11 12 2015 21:13:57.521:WARN [web-server]: 404: /angular2/testing.js
11 12 2015 21:13:57.676:WARN [web-server]: 404: /angular2/http/testing.js
11 12 2015 21:13:57.706:WARN [web-server]: 404: /angular2/angular2.js
Loading modules this way works well when the Angular 2 bundle is loaded in index.html through a <script>
tag.Unfortunately, we cannot rely on browser to load these files since we need to automate with Karma :) So far I haven't found a way to make it work without wepback preparing a test bundle, which is too heavy.
Any idea about how to solve it? Thanks a lot!
Currently, there are two ways to solve this problem with karma-systemjs
. The first is to add bundles
and meta
configuration in either your SystemJS config file, or in the systemjs.config
property of your karma config. I have all of my angular2 bundles copied to <baseURL>/lib
, so the following config reflects that:
System.config({
defaultJSExtensions: true,
bundles: {
'lib/router.dev': [ // path to bundle file
'angular2/router' // module ID contained within the bundle
],
'lib/http.dev': [
'angular2/http'
],
'lib/testing.dev': [
'angular2/testing',
'angular2/router/testing',
'angular2/http/testing'
],
'lib/angular2.dev': [
'angular2/core',
'angular2/common',
'angular2/compiler',
'angular2/platform/browser',
'angular2/src/facade/lang'
],
'lib/Rx': [
'rxjs/Rx'
]
},
meta: {
'lib/es6-shim': {
exports: 'Symbol',
format: 'global'
},
'lib/Rx': {
format: 'register',
deps: [ 'lib/es6-shim' ]
},
'lib/angular2.dev': {
format: 'register',
deps: [ 'lib/Rx' ]
},
'lib/router.dev': {
format: 'register',
deps: [ 'lib/angular2.dev' ]
},
'lib/http.dev': {
format: 'register',
deps: [ 'lib/angular2.dev' ]
},
'lib/testing.dev': {
format: 'register',
deps: [ 'lib/router.dev', 'lib/http.dev' ]
}
}
});
This will tell SystemJS where to find the correct bundles for the angular2 module IDs. You'll also need to add entries for these files in systemjs.serveFiles
.
The second way to solve this is to pass an object in the systemjs.serveFiles
array. However this exposes a problem: the files
array in the karma configuration has its objects normalized before framework.js
is run, so objects passed through this array will not match any paths known to karma unless they are manually normalized. My karma configuration for this solution currently looks like this (found at test/karma.conf.js
):
var path = require('path');
config.set({
basePath: '..',
// ...
systemjs: {
configFile: 'www/system.config.js',
// before SystemJS is loaded
includeFiles: [
'www/lib/es6-shim.js'
],
serveFiles: [
{ pattern: path.resolve(__dirname, '../www/lib/Rx.js'), included: true },
{ pattern: path.resolve(__dirname, '../www/lib/angular2.dev.js'), included: true },
{ pattern: path.resolve(__dirname, '../www/lib/router.dev.js'), included: true },
{ pattern: path.resolve(__dirname, '../www/lib/http.dev.js'), included: true },
{ pattern: path.resolve(__dirname, '../www/lib/testing.dev.js'), included: true },
'**/*.js',
'**/*.css',
'**/*.html'
]
},
// ...
});
IMO, both solutions are valid (it just depends on how much you rely on the loader in your setup), but the second solution (at this time) is a bit clunky.
I spoke too soon on the second method I outlined above. It doesn't quite work as easily as that. The bundles are going to be included on the page before the loader is configured, which means they will get registered before the baseURL
is set. This means that the module angular2/core
will be registered as the module http://localhost:9876/angular2/core
. Once the loader is configured, the baseURL
will be set to something in http://localhost:9876/base/
and any lookup of angular2/core
will look for the module http://localhost:9876/base/angular2/core
, which doesn't exist. To alleviate this problem, the following paths
and packages
configuration have to be passed to systemjs.config
in your karma config:
packages: {
angular2: { defaultExtension: false },
rxjs: { defaultExtension: false }
},
paths: {
systemjs: 'lib/system.src.js',
'system-polyfills': 'lib/angular2-polyfills.js',
'angular2/*': '/angular2/*',
'rxjs/*': '/rxjs/*'
}
This extra paths
and packages
configuration could be avoided if there was a configuration option to include files as script tags after configuring the loader, but before importing spec files.
My code uses an external created systemjs bundle.
The bundle is loaded by using karma.config.files. ie
When running the tests the bundle is loaded and the containing modules are registered. For example jquery can be found in System.defined as http://localhost:9876/angular.js
However when the test (or the code being tested) requests the module it searches for http://localhost:9876/base/angular.js and the module cannot be found since the base part is not part of the registered name...