title: Angular Material/Jasmine testing - errors while loading Material Harnesses
body: <p>I'm trying to test components built with Angular Material, however I'm encountering a problem initializing Material elements using <code>Harness Loader</code> <a href="https://material.angular.io/guide/using-component-harnesses" rel="nofollow noreferrer">as per documentation (section 'Getting started'.)</a>. I'd like to extract the logic of initializing them outside of the test methods to make them more concise, but it doesn't seem to work.</p>
  <p>Within <code>describe()</code>:</p>
  <pre class="lang-js prettyprint-override"><code>let usernameFormField: MatFormFieldHarness;
  let registrationButton: MatButtonHarness;
  
  beforeEach(async(() =&gt; {
      TestBed.configureTestingModule({
          imports: [MaterialModule, BrowserAnimationsModule, ReactiveFormsModule],
          declarations: [RegistrationComponent],
          providers: [ /*provide spies */ ]
      }).compileComponents().then(async () =&gt; {
          fixture = TestBed.createComponent(RegistrationComponent);
          loader = TestbedHarnessEnvironment.loader(fixture);
  
          // what works, but I don't like
          /*loader.getHarness(
              MatFormFieldHarness.with({selector: '#username-form-field'})
          ).then(harness =&gt; {
              usernameFormField = harness;
          });*/
  
          // what doesn't work
          usernameFormField = await loader
              .getHarness(MatFormFieldHarness.with({selector: '#username-form-field'}))
  
          // other form elements
  
          // to my confusion, this works without any problem
          registrationButton = await loader.getHarness(MatButtonHarness);
      });
  }));
  </code></pre>
  <p>The <code>await</code> on <code>loader.getHarness()</code> causes lots of errors, seemingly about code not running in 'ProxyZone'.</p>
  <pre><code>context.js:265 Unhandled Promise rejection: Expected to be running in 'ProxyZone', but it was not found. ; Zone: &lt;root&gt; ; Task: Promise.then ; Value: Error: Expected to be running in 'ProxyZone', but it was not found.
      at Function.push../node_modules/zone.js/dist/zone-testing.js.ProxyZoneSpec.assertPresent (zone-testing.js:210) [&lt;root&gt;]
      at Function.setup (testbed.js:61) [&lt;root&gt;]
      at new TestbedHarnessEnvironment (testbed.js:572) [&lt;root&gt;]
      at TestbedHarnessEnvironment.createEnvironment (testbed.js:633) [&lt;root&gt;]
      at TestbedHarnessEnvironment.createComponentHarness (testing.js:341) [&lt;root&gt;]
      at TestbedHarnessEnvironment.&lt;anonymous&gt; (testing.js:384) [&lt;root&gt;]
      at Generator.next (&lt;anonymous&gt;) [&lt;root&gt;]
      at :9876/_karma_webpack_/node_modules/tslib/tslib.es6.js:74:1 [&lt;root&gt;]
      at new ZoneAwarePromise (zone-evergreen.js:960) [&lt;root&gt;]
      at __awaiter (tslib.es6.js:70) [&lt;root&gt;]
      at TestbedHarnessEnvironment._getQueryResultForElement (testing.js:379) [&lt;root&gt;]
      at :9876/_karma_webpack_/node_modules/@angular/cdk/fesm2015/testing.js:366:1 [&lt;root&gt;]
      at Array.map (&lt;anonymous&gt;) [&lt;root&gt;]
      at TestbedHarnessEnvironment.&lt;anonymous&gt; (testing.js:366) [&lt;root&gt;] Error: Expected to be running in 'ProxyZone', but it was not found.
      at Function.push../node_modules/zone.js/dist/zone-testing.js.ProxyZoneSpec.assertPresent (http://localhost:9876/_karma_webpack_/node_modules/zone.js/dist/zone-testing.js:210:1) [&lt;root&gt;]
      at Function.setup (http://localhost:9876/_karma_webpack_/node_modules/@angular/cdk/fesm2015/testing/testbed.js:61:1) [&lt;root&gt;]
      at new TestbedHarnessEnvironment (http://localhost:9876/_karma_webpack_/node_modules/@angular/cdk/fesm2015/testing/testbed.js:572:1) [&lt;root&gt;]
      at TestbedHarnessEnvironment.createEnvironment (http://localhost:9876/_karma_webpack_/node_modules/@angular/cdk/fesm2015/testing/testbed.js:633:1) [&lt;root&gt;]
      at TestbedHarnessEnvironment.createComponentHarness (http://localhost:9876/_karma_webpack_/node_modules/@angular/cdk/fesm2015/testing.js:341:1) [&lt;root&gt;]
      at TestbedHarnessEnvironment.&lt;anonymous&gt; (http://localhost:9876/_karma_webpack_/node_modules/@angular/cdk/fesm2015/testing.js:384:1) [&lt;root&gt;]
      at Generator.next (&lt;anonymous&gt;) [&lt;root&gt;]
      at http://localhost:9876/_karma_webpack_/node_modules/tslib/tslib.es6.js:74:1 [&lt;root&gt;]
      at new ZoneAwarePromise (http://localhost:9876/_karma_webpack_/node_modules/zone.js/dist/zone-evergreen.js:960:1) [&lt;root&gt;]
      at __awaiter (http://localhost:9876/_karma_webpack_/node_modules/tslib/tslib.es6.js:70:1) [&lt;root&gt;]
      at TestbedHarnessEnvironment._getQueryResultForElement (http://localhost:9876/_karma_webpack_/node_modules/@angular/cdk/fesm2015/testing.js:379:25) [&lt;root&gt;]
      at http://localhost:9876/_karma_webpack_/node_modules/@angular/cdk/fesm2015/testing.js:366:1 [&lt;root&gt;]
      at Array.map (&lt;anonymous&gt;) [&lt;root&gt;]
      at TestbedHarnessEnvironment.&lt;anonymous&gt; (http://localhost:9876/_karma_webpack_/node_modules/@angular/cdk/fesm2015/testing.js:366:1) [&lt;root&gt;]
  </code></pre>
  <p>I'd also tried running this with a global <code>async</code> function (with the following syntax:)</p>
  <pre class="lang-js prettyprint-override"><code>beforeEach(async( async () =&gt; {
      // magic happening here
  }));
  </code></pre>
  <p>I even tried extracting these harnesses into separate functions, to call them as late as possible, but it also didn't work well:</p>
  <pre class="lang-js prettyprint-override"><code>const usernameFormField = () =&gt; {
      loader.getHarnes(...);
  }
  
  // later in code; not the most elegant, but good enough
  const usernameField = await usernameFormField();
  expect(await usernameField().hasErrors()).toBeFalsy();
  </code></pre>
  <p>As <a href="https://stackoverflow.com/questions/54963635/angular-7-testing-async-function-call-async-await">this post</a> discusses, the 'double-async' construct is valid, if a little clumsy. However, it didn't work for me; the only variant that did was <code>beforeEach(async( () =&gt; { ... } ));</code>. Is it possible to use async-await inside <code>beforeEach</code> in async zone, or am I stuck with handling everything manually using Promises?</p>
  <p><strong>EDIT</strong>: a similar problem shows up not only in <code>beforeEach()</code>, but also in test methods themselves, even when I don't preinitialize the harnesses:</p>
  <pre class="lang-js prettyprint-override"><code>it('should display \'log out\' and \'my account\' buttons when user is authenticated',
      async () =&gt; {
          const EXAMPLE_USERNAME = 'username';
  
          spyOnProperty(authenticationService, 'authenticatedUser')
              .and.returnValue(EXAMPLE_USERNAME);
  
         expect(fixture.componentInstance.authenticatedUser)
  .toEqual(EXAMPLE_USERNAME);
  
          const logOutButton = await loader
              .getHarness(MatButtonHarness.with({text: BUTTON_LOG_OUT_TEXT}));
          expect(await logOutButton.isDisabled()).toBeFalsy();
  
          // the following line causes a problem
          /*const myAccountButton = await loader
              .getHarness(MatButtonHarness.with({text: BUTTON_MY_ACCOUNT_TEXT}));
          expect(await myAccountButton.isDisabled()).toBeFalsy();
          await myAccountButton.click();
          expect(routerSpy.navigateByUrl).toHaveBeenCalled();*/
      });
  </code></pre>
  <p>When I uncomment only the first commented line, the code breaks and the test doesn't pass. <strong>When I include the async zone, the test passes, but the errors persist.</strong> I initially thought this is a problem with initializing the component, but now it seems it's more related to HarnessLoader.</p>
  <p><strong>EDIT 2</strong>: Coderer's answer links to some problems with <code>karma.conf.js</code>, so here are some of my configuration files:</p>
  <p><code>karma.conf.js</code>:</p>
  <pre class="lang-js prettyprint-override"><code>// custom headless chrome from
  // https://coryrylan.com/blog/building-angular-cli-projects-with-github-actions
  
  module.exports = function (config) {
    config.set({
      // adding any files here didn't seem to work
      basePath: '',
      frameworks: ['jasmine', '@angular-devkit/build-angular'],
      plugins: [
        require('karma-jasmine'),
        require('karma-chrome-launcher'),
        require('karma-jasmine-html-reporter'),
        require('karma-coverage-istanbul-reporter'),
        require('@angular-devkit/build-angular/plugins/karma')
      ],
      client: {
        clearContext: false, // leave Jasmine Spec Runner output visible in browser
        jasmine: {
          random: false
        }
      },
      coverageIstanbulReporter: {
        dir: require('path').join(__dirname, './coverage/elx-front-end'),
        reports: ['html', 'lcovonly', 'text-summary'],
        fixWebpackSourcePaths: true
      },
      reporters: ['progress', 'kjhtml'],
      port: 9876,
      colors: true,
      logLevel: config.LOG_INFO,
      autoWatch: true,
      browsers: ['Chrome'],
      singleRun: false,
      restartOnFileChange: true,
      customLaunchers: {
        ChromeHeadlessCI: {
          base: 'ChromeHeadless',
          flags: ['--no-sandbox', '--disable-gpu']
        }
      }
    });
  };
  </code></pre>
  <p><code>src/test.ts</code>: (importing as described <a href="https://github.com/angular/angular/issues/11317#issuecomment-245215143" rel="nofollow noreferrer">here</a> also didn't work)</p>
  <pre class="lang-ts prettyprint-override"><code>// This file is required by karma.conf.js and loads recursively all the .spec and framework files
  
  import &quot;zone.js/dist/zone-testing&quot;;
  import {getTestBed} from &quot;@angular/core/testing&quot;;
  import {BrowserDynamicTestingModule, platformBrowserDynamicTesting} from &quot;@angular/platform-browser-dynamic/testing&quot;;
  
  declare const require: any;
  
  // First, initialize the Angular testing environment.
  getTestBed().initTestEnvironment(
      BrowserDynamicTestingModule,
      platformBrowserDynamicTesting()
  );
  // Then we find all the tests.
  const context = require.context(&quot;./&quot;, true, /\.spec\.ts$/);
  // And load the modules.
  context.keys().map(context);
  </code></pre>
  <p><code>tsconfig.base.json</code>:</p>
  <pre class="lang-json prettyprint-override"><code>{
      &quot;compileOnSave&quot;: false,
      &quot;compilerOptions&quot;: {
          &quot;baseUrl&quot;: &quot;./&quot;,
          &quot;outDir&quot;: &quot;./dist/out-tsc&quot;,
          &quot;sourceMap&quot;: true,
          &quot;declaration&quot;: false,
          &quot;downlevelIteration&quot;: true,
          &quot;experimentalDecorators&quot;: true,
          &quot;module&quot;: &quot;es2020&quot;,
          &quot;moduleResolution&quot;: &quot;node&quot;,
          &quot;resolveJsonModule&quot;: true,
          &quot;allowSyntheticDefaultImports&quot;: true,
          &quot;importHelpers&quot;: true,
          &quot;target&quot;: &quot;es2018&quot;,
          &quot;strict&quot;: true,
          &quot;typeRoots&quot;: [
              &quot;node_modules/@types&quot;
          ],
          &quot;lib&quot;: [
              &quot;es2018&quot;,
              &quot;dom&quot;
          ],
          &quot;paths&quot;: { /* custom paths */}
      },
      &quot;angularCompilerOptions&quot;: {
          &quot;fullTemplateTypeCheck&quot;: true,
          &quot;strictInjectionParameters&quot;: true
      }
  }
  </code></pre>
  <p><code>tsconfig.spec.json</code>:</p>
  <pre class="lang-json prettyprint-override"><code>{
      &quot;extends&quot;: &quot;./tsconfig.base.json&quot;,
      &quot;compilerOptions&quot;: {
          &quot;outDir&quot;: &quot;./out-tsc/spec&quot;,
          &quot;types&quot;: [
              &quot;jasmine&quot;,
              &quot;node&quot;
          ]
      },
      &quot;files&quot;: [
          &quot;src/test.ts&quot;,
          &quot;src/polyfills.ts&quot;
      ],
      &quot;include&quot;: [
          &quot;src/**/*.spec.ts&quot;,
          &quot;src/**/*.d.ts&quot;
      ]
  }
  </code></pre>
  <p>fragment of <code>angular.json</code>:</p>
  <pre class="lang-json prettyprint-override"><code>&quot;architect&quot;: {
      ...
      &quot;test&quot;: {
          &quot;builder&quot;: &quot;@angular-devkit/build-angular:karma&quot;,
          &quot;options&quot;: {
              &quot;main&quot;: &quot;src/test.ts&quot;,
              &quot;polyfills&quot;: &quot;src/polyfills.ts&quot;,
              &quot;tsConfig&quot;: &quot;tsconfig.spec.json&quot;,
              &quot;karmaConfig&quot;: &quot;karma.conf.js&quot;,
              &quot;assets&quot;: [
                  &quot;src/favicon.ico&quot;,
                  &quot;src/assets&quot;
              ],
              &quot;styles&quot;: [
                  &quot;./node_modules/@angular/material/prebuilt-themes/deeppurple-amber.css&quot;,
                  &quot;src/styles.scss&quot;,
                  &quot;src/dimens.scss&quot;
                  ],
                  &quot;scripts&quot;: []
              }
          }
      }
  }
  </code></pre>