title: Angular2: Unit-test router with cached template
body: <p>I'm dealing with some problems doing test on different environments:</p>
  
  <ul>
  <li><strong>SRC</strong>: unminified components, using both .js and .html/.css template files</li>
  <li><strong>DIST</strong>: minified components (only .js, no templates)</li>
  </ul>
  
  <p>I made two different karma-conf and karma-test-shim, one for SRC and one for DIST.
  In the SRC's one, since i mostly execute tests on components in fakeAsync contexts, i'm caching all my templates and .css at karma's startup, as shown in the following karma-test-shim, to avoid XHR errors.</p>
  
  <p><strong>karma-test-shim.src.js</strong></p>
  
  <pre><code>// Turn on full stack traces in errors to help debugging
  Error.stackTraceLimit = Infinity;
  
  jasmine.DEFAULT_TIMEOUT_INTERVAL = 10000;
  
  var karmaFiles = Object.keys(window.__karma__.files); // All files served by Karma.
  
  window.$templateCache = {}; // deckaring Window template cache for caching .html template and .css
  
  // Cancel Karma's synchronous start,
  // we will call `__karma__.start()` later, once all the specs are loaded.
  __karma__.loaded = function () { };
  
  // Just a special configuration for Karma and coverage
  System.config({
      packages: {
          "@angular/core/testing": { main: "../../../../../../node_modules/@angular/core/bundles/core-testing.umd.js" },
          "@angular/compiler/testing": { main: "../../../../base/node_modules/@angular/compiler/bundles/compiler-testing.umd.js" },
          "@angular/common/testing": { main: "../../../../base/node_modules/@angular/common/bundles/common-testing.umd.js" },
          "@angular/http/testing": { main: "../../../../base/node_modules/@angular/http/bundles/http-testing.umd.js" },
          "@angular/router/testing": { main: "../../../../../../node_modules/@angular/router/bundles/router-testing.umd.js" },
          "@angular/platform-browser/testing": { main: "../../../../base/node_modules/@angular/platform-browser/bundles/platform-browser-testing.umd.js" },
          "@angular/platform-browser-dynamic/testing": { main: "../../../../base/node_modules/@angular/platform-browser-dynamic/bundles/platform-browser-dynamic-testing.umd.js" }
      },
      meta: {
          "src/*": { format: "register" }, // Where covered files located
          "packages/*": { format: "register" } // Where covered files located
      }
  });
  
  Promise.all([
    System.import('@angular/core/testing'),
    System.import('@angular/platform-browser-dynamic/testing'),
    System.import('@angular/platform-browser-dynamic') // Contains RESOURCE_CACHE_PROVIDER
  ]).then(function (providers) {
          var testing = providers[0];
          var testingBrowserDynamic = providers[1];
          var browserDynamic = providers[2];
  
          testing.TestBed.initTestEnvironment(
            testingBrowserDynamic.BrowserDynamicTestingModule,
            testingBrowserDynamic.platformBrowserDynamicTesting()
          );
  
           testing.TestBed.configureCompiler({
               providers: [
                   browserDynamic.RESOURCE_CACHE_PROVIDER
               ]
           })
  
      // Import main module
      }).then(function () {
          return Promise.all(
              karmaFiles 
              .filter(onlySpecFiles)
              .map(file2moduleName)
              .map(function (path) {
                  return System.import(path).then(function (module) {
                      if (module.hasOwnProperty('main')) {
                          module.main();
                      } else {
                          throw new Error('Module ' + path + ' does not implement main() method.');
                      }
                  });
              }));
  
      })
      // Caching all component's templates files (.html/.css)
      .then(function () {
          return Promise.all(
              karmaFiles
              .filter(function (filename) {
                  var template = filename.endsWith('.html');
                  var css = filename.endsWith('.css');
                  return template || css;
              })
              .map(function (filename) {
                  return new Promise(function(resolve, reject) {
                      $.ajax({
                          type: 'GET',
                          url: filename,
                          dataType: 'text',
                          success: function (contents) {
                              filename = filename.replace("/base", "..");
                              window.$templateCache[filename] = contents;
                              resolve();
                          }
                      })
                  })
              })
          )
      })
      .then(function () {
        __karma__.start();
    }, function (error) {
        console.error(error.stack || error);
        __karma__.start();
    });
  
  // Filter spec files
  function onlySpecFiles(path) {
      return /\.spec\.js$/.test(path);
  }
  
  // Normalize paths to module names.
  function file2moduleName(filePath) {
      return filePath.replace(/\\/g, '/')
        .replace(/^\/base\//, '');
  }
  </code></pre>
  
  <p>So far so good but i started getting problems on the following spec:</p>
  
  <p><strong>loginPage.spec.js</strong></p>
  
  <pre><code>[...]
  
  import { LoginPageComponent } from "loginPage";
  
  import { RESOURCE_CACHE_PROVIDER } from "@angular/platform-browser-dynamic";
  
  
  @Component({
      selector: "loginpage-host",
      template: "&lt;loginPage&gt;&lt;/loginPage&gt;"
  })
  export class LoginPageHostComponent {
      @ViewChild(LoginPageComponent)
      public loginPageComponent;
  }
  
  export function main() {
      describe('LoginPageComponent', () =&gt; {
  
          beforeEach(()  =&gt; {
              TestBed.configureTestingModule({
                  imports: [RouterTestingModule.withRoutes([]),CommonModule, HttpModule, CoreModule, ComponentsModule, GlobalizationModule],
                  declarations: [LoginPageHostComponent, LoginPageComponent],
                  providers: [
                      MockBackend,
                      BaseRequestOptions,
                      {
                          provide: AuthHttp,
                          useFactory: (backend: ConnectionBackend, options: BaseRequestOptions) =&gt; new Http(backend, options),
                          deps: [MockBackend, BaseRequestOptions]
                      },
                      {
                          provide: Http,
                          useFactory: (backend: ConnectionBackend, options: BaseRequestOptions) =&gt; new Http(backend, options),
                          deps: [MockBackend, BaseRequestOptions]
                      },
                      {
                          provide: Configuration,
                          useFactory: () =&gt; new Configuration()
                      }
                  ]
              })
  
               // TestBed.configureCompiler({
               //     providers: [RESOURCE_CACHE_PROVIDER]
               // });
          });
  
          it('should work',
              fakeAsync(() =&gt; {
                  TestBed
                      .compileComponents()
                      .then(() =&gt; {
                          let fixture = TestBed.createComponent(LoginPageHostComponent);
  
                          let logPageHostComponentInstance = fixture.debugElement.componentInstance;
                          expect(logPageHostComponentInstance).toEqual(jasmine.any(LoginPageHostComponent));
                          expect(logPageHostComponentInstance.loginPageComponent).toEqual(jasmine.any(LoginPageComponent));
                          fixture.destroy();
                          discardPeriodicTasks(); 
                      });
              }));
      });
  }
  </code></pre>
  
  <p>On SRC i get this error: </p>
  
  <blockquote>
    <p>Chrome 56.0.2924 (Windows 10 0.0.0) LoginPageComponent should work
    FAILED    Error: Cannot make XHRs from within a fake async test.</p>
  </blockquote>
  
  <p>If i manually provide the RESOURCE_CACHED_PROVIDER to the spec it works:</p>
  
  <pre><code>TestBed.configureCompiler({
        providers: [RESOURCE_CACHE_PROVIDER]
  });
  </code></pre>
  
  <p>but it fails on DIST due to the fact that there's no cached template to load for loginPage.</p>