ZoneAwarePromise has been overridden

Jacob McCarthy picture Jacob McCarthy · Sep 14, 2016 · Viewed 8.3k times · Source

After upgrading an application to rc-7 and running my unit tests to be sure nothing broke, I got this error message on about half of my unit tests.

"Error: Zone.js has detected that ZoneAwarePromise '(window|global).Promise' has been overwritten. Most likely cause is that a Promise polyfill has been loaded after Zone.js (Polyfilling Promise api is not necessary when zone.js is loaded. If you must load one, do so before loading zone.js) in node_modules/zone.js/dist/zone.js (line 21)"

The closest I thing I can think of is that I mock responses from http calls in my unit tests by manually returning observables.

This is an Angular2 application using Jasmine and Karma for unit testing.

UPDATE So it would seem this is likely a loading order issue as per the error message, however I am not loading the polyfills anywhere I can determine unless I am accidentally grabbing them. I've attached my karma.conf.js and systemjs.conf.js to aid in finding the error.

Karma.conf.js

module.exports = function(config) {
  var gulpConfig = require('../gulp/config')();

  /**
   * List of npm packages that imported via `import` syntax
   */
  var dependencies = [
    '@angular',
    'lodash',
    'rxjs'
  ];

  var configuration = {
    basePath: '../../',

    browserNoActivityTimeout: 20000,
    frameworks: ['jasmine'],
    browsers: ['PhantomJS'],
    reporters: ['progress', 'coverage'],

    preprocessors: {},

    // Generate json used for remap-istanbul
    coverageReporter: {
      includeAllSources: true,
      dir: 'coverage/appCoverage/remap/',
      reporters: [
        { type: 'json', subdir: 'report-json' }
      ]
    },

    files: [
      'node_modules/reflect-metadata/Reflect.js',
      'node_modules/zone.js/dist/zone.js',
      'node_modules/zone.js/dist/long-stack-trace-zone.js',
      'node_modules/zone.js/dist/proxy.js',
      'node_modules/zone.js/dist/sync-test.js',
      'node_modules/zone.js/dist/jasmine-patch.js',
      'node_modules/zone.js/dist/async-test.js',
      'node_modules/zone.js/dist/fake-async-test.js',

      'node_modules/angular/angular.js',
      'node_modules/core-js/client/shim.min.js',
      'node_modules/systemjs/dist/system.src.js'
    ],

    // proxied base paths
    proxies: {
      // required for component assests fetched by Angular's compiler
      "/src/": "/base/src/",
      "/app/": "/base/src/app/",
      "/node_modules/": "/base/node_modules/"
    },

    port: 9876,
    colors: true,
    logLevel: config.LOG_INFO,
    autoWatch: true,
    //browserNoActivityTimeout: 100000
  };

  configuration.preprocessors[gulpConfig.tmpApp + '**/!(*.spec)+(.js)'] = ['coverage'];
  configuration.preprocessors[gulpConfig.tmpApp + '**/*.js'] = ['sourcemap'];
  configuration.preprocessors[gulpConfig.tmpTest + '**/*.js'] = ['sourcemap'];

  var files = [
    gulpConfig.tmpTest + 'test-helpers/global/**/*.js',
    gulpConfig.src + 'systemjs.conf.js',
    'config/test/karma-test-shim.js',
    createFilePattern(gulpConfig.tmpApp + '**/*.js', { included: false }),
    createFilePattern(gulpConfig.tmpTest + 'test-helpers/*.js', { included: false }),
    createFilePattern(gulpConfig.app + '**/*.html', { included: false }),
    createFilePattern(gulpConfig.app + '**/*.css', { included: false }),
    createFilePattern(gulpConfig.app + '**/*.ts', { included: false, watched: false }),
    createFilePattern(gulpConfig.tmpApp + '**/*.js.map', { included: false, watched: false })
  ];

  configuration.files = configuration.files.concat(files);

  dependencies.forEach(function(key) {
    configuration.files.push({
        pattern: 'node_modules/' + key + '/**/*.js',
        included: false,
        watched: false
    });
  });

  if (process.env.APPVEYOR) {
    configuration.browsers = ['IE'];
    configuration.singleRun = true;
    configuration.browserNoActivityTimeout = 90000; // Note: default value (10000) is not enough
  }

  config.set(configuration);

  // Helpers
  function createFilePattern(path, config) {
    config.pattern = path;
    return config;
  }
}

UPDATE My solution involved ensuring all my zone.js files were being loaded last in karma.conf.js. I'm guessing something else I have included was also including the polyfill, but was being loaded after zone.js so the error was raised. After moving zone.js to the end everything worked fine.

Answer

David Kronmueller picture David Kronmueller · Sep 15, 2016

I encountered the same problem. (Angular 2 RC.7 Jasmine Karma) It was due to the order I was loading the test files in my karma.conf.js. I was loading /zone.js/dist/zone.js before /systemjs/dist/system-polyfills.js. Changing the order of the files to load the zone.js AFTER the systemjs polyfills resolved this problem.

Here is my current setup in karma.conf.js that resolved the error for me.

files: [
  {pattern: 'dist/vendor/es6-shim/es6-shim.js', included: true, watched: false},
  {pattern: 'dist/vendor/reflect-metadata/Reflect.js', included: true, watched: false},
  {pattern: 'dist/vendor/systemjs/dist/system-polyfills.js', included: true, watched: false},
  {pattern: 'dist/vendor/systemjs/dist/system.src.js', included: true, watched: false},
  {pattern: 'dist/vendor/zone.js/dist/zone.js', included: true, watched: false},
  {pattern: 'dist/vendor/zone.js/dist/proxy.js', included: true, watched: false},
  {pattern: 'dist/vendor/zone.js/dist/sync-test.js', included: true, watched: false},
  {pattern: 'dist/vendor/zone.js/dist/long-stack-trace-zone.js', included: true, watched: false},
  {pattern: 'dist/vendor/zone.js/dist/async-test.js', included: true, watched: false},
  {pattern: 'dist/vendor/zone.js/dist/fake-async-test.js', included: true, watched: false},
  {pattern: 'dist/vendor/zone.js/dist/jasmine-patch.js', included: true, watched: false},

  {pattern: 'config/karma-test-shim.js', included: true, watched: true},

  // Distribution folder.
  {pattern: 'dist/**/*', included: false, watched: true}
],