3

I was using webpack+aurelia for a project and recently switch to JSPM version 0.16.52. I use jasmine's spyOn for utility or factory functions that are imported into my classes. However tests that have spyOn(object, 'method') have this error:

"Module Exports Cannot Be Changed Externally"

This occurs when jasmine sets the spied method on the module obj[methodName] = spiedMethod'

Here is a very simple example:

test.js

import * as env from '../../src/env';

describe('stackoverflow example', () => {

  it('runs the test', () => {
    // this gets thrown and swallowed. jasmine does not report an error, but does not increase the test count.
    let envSpy = spyOn(env, 'getBaseUrl');
  });

});

env.js

export function getBaseUrl(location) {
  return location.port ? `http://${location.hostname}:9001/api/`: '/api/';
}

karam.conf.js

'use strict'
const path = require('path')

module.exports = function(config) {
  config.set({

    // base path that will be used to resolve all patterns
    basePath: __dirname,

    // frameworks to use
    frameworks: ['jspm', 'jasmine'],

    // list of files / patterns to load in the browser
    files: [],

    // list of files to exclude
    exclude: [],

    jspm: {
      // Edit this to your needs
      loadFiles: [
        'test/unit/setup.js',
        'test/unit/**/*.js'
      ],
      serveFiles: [
        'src/**/*.*',
        'jspm_packages/system-polyfills.js'
      ],
      paths: {
        '*': 'src/*',
        'test/*': 'test/*',
        'github:*': 'jspm_packages/github/*',
        'npm:*': 'jspm_packages/npm/*'
      }
    },

    // preprocess matching files before serving them to the browser
    preprocessors: {
      'test/**/*.js': ['babel'],
      'src/**/*.js': ['babel']
    },
    'babelPreprocessor': {
      options: {
        sourceMap: 'inline',
        presets: [ ['es2015', { loose: true }], 'stage-1'],
        plugins: [
          'syntax-flow',
          'transform-decorators-legacy',
          'transform-flow-strip-types',
          [ 'istanbul', { 'ignore': 'test/' } ]
        ]
      }
    },

    // test results reporter to use
    reporters: ['mocha'],

    // web server port
    port: 9876,

    // enable / disable colors in the output (reporters and logs)
    colors: true,

    // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
    logLevel: config.LOG_INFO,

    // enable / disable watching file and executing tests whenever any file changes
    autoWatch: true,

    // start these browsers
    browsers: ['Chromium'],

    // Continuous Integration mode
    // if true, Karma captures browsers, runs the tests and exits
    singleRun: false
  });
};

setup,js

import 'babel-polyfill'; // for async/await
import 'aurelia-polyfills';
import {initialize} from 'aurelia-pal-browser';
initialize();

UPDATE

When I pulled down a fresh copy of Aurelia-esnext I did not receive the error. So commented out all my tests in my production app and the first spyOn worked, but as i added more tests I started recieving the error again, and it seems to be the way the module is loaded by systemjs. Below is how the imported module object looks when it is loaded into the test

Fresh Copy does not throw

{
  __esModule: true,
  getBaseUrl: (),
  __proto__: Object
}

Original that throws

{
  __esModule: (...)
  get __esModule: ()
  set __esModule: ()
  getBaseUrl: (...)
  get getBaseUrl: ()
  set getBsaeUrl: ()
  _proto__: Object
}

Update I found the snippet of code in system.js where the difference in import occurs. In my larger original project loader.defined[name]; returned undefined and the fresh copy of aurelia loader.defined[name]; is defined...still have not found a workaround

system.src.js

function getModule(name, loader) {
    var exports;
    var entry = loader.defined[name];

    if (!entry) {
      exports = loader.get(name);
      if (!exports)
        throw new Error('Unable to load dependency ' + name + '.');
    }

    else {
      if (entry.declarative)
        ensureEvaluated(name, entry, [], loader);

      else if (!entry.evaluated)
        linkDynamicModule(entry, loader);

      exports = entry.module.exports;
    }

    if ((!entry || entry.declarative) && exports && exports.__useDefault)
      return exports['default'];

    return exports;
  }
jmzagorski
  • 1,135
  • 18
  • 42

0 Answers0