rolaveric / karma-systemjs

Karma plugin for using SystemJS as a module loader
MIT License
40 stars 19 forks source link

config.meta.deps is not an array in the browser (breaking systemjs) #44

Closed unional closed 9 years ago

unional commented 9 years ago

I guess this is a bug in karma and not karma-systemjs but I want to bring it up here as I discover and start the conversation from systemjs.

A apologize that this is quite long because it was very difficult to trace, so I want to give you as much information as possible.

The resulting bug of this issue is systemjs will fail with the following error:

  Error: 'undefined' is not a function (evaluating 'metaDeps.concat(getCJSDeps(load.source))')

After tracing the rabbit for a long time, the problem lies in meta[module].deps is not an array after it is loaded in karma.

As the basis of my example, I have the following in my config:

meta: {
  "*": {
    deps: ['jquery']
  }
}

In karma-sysmtejs adaptor.run:

    run: function(karma, System, Promise) {
      // Stop karma from starting automatically on load
      karma.loaded = function() {
      };

      // Load SystemJS configuration from karma config
      // And update baseURL with '/base', where Karma serves files from
      if (karma.config.systemjs.config) {
          console.log(karma.config.systemjs.config.meta["*"].deps, karma.config.systemjs.config.meta["*"].deps instanceof Array);
        ......

produces:

LOG: ['jquery'], false

However, I validate that in index.js, at the end of initSystemjs:

  config.client.systemjs = {
    testFileSuffix: kSystemjsConfig.testFileSuffix,
    testFileRegex: kSystemjsConfig.testFileRegex,
    config: kSystemjsConfig.config
  };
  console.log("index.js", 189, kSystemjsConfig.config.meta["*"].deps, kSystemjsConfig.config.meta["*"].deps instanceof Array);

produces:

LOG: index.js, 189, ['jquery'], true

Because the instanceof Array failed, it fail the following code in systemjs. In proto.js:

function extendMeta(a, b, prepend) {
  for (var p in b) {
    var val = b[p];
    if (!(p in a))
      a[p] = val;
    else if (val instanceof Array && a[p] instanceof Array)  // <---- here. It fails this check
      a[p] = [].concat(prepend ? val : a[p]).concat(prepend ? a[p] : val);
    else if (typeof val == 'object' && typeof a[p] == 'object') // <---- so this is ran instead
      a[p] = extend(extend({}, a[p]), val, prepend);
    else if (!prepend)
      a[p] = val;
  }
}

This cause the deps becomes an object instead of an array, thus missing the concat method and failed systemjs.

Do you think this is purely karma bug?

unional commented 9 years ago

https://github.com/systemjs/systemjs/issues/769#issuecomment-138630414 Reference issue on systemjs

rolaveric commented 9 years ago

I'm not 100% sure who's at fault here. I would say it's Karma for not passing arrays from the framework (nodejs) to the browser with the proper Array prototype - I would have thought it was using JSON methods to pass the config.client data. However it's possible I've misused config.client for evil.

I could change the framework to encode the SystemJS config as a JSON string, then decode it in the adapter. That should solve the problem for you.

unional commented 9 years ago

I have created bugs on karma and socket.io to track this. I think it is a real bug that should be fixed there. It is great that you have a backup plan on how to get around it. I don't need the fix right now, so let's see will the issue be fixed in time on the other side. :+1:

rolaveric commented 9 years ago

Hey @unional I see the issues on karma and socket.io are still open with no recent activity, so I reckon I'll apply the JSON.stringify() -> JSON.parse() workaround into karma-systemjs for now.