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