allenhwkim
allenhwkim

Reputation: 27738

Unit Test Failed: Cannot read property 'componentInstance' of undefined

Unit test works fine with angular2-seed project. The problem is it does not work with my project which resembles angular2-seed project.

Only difference between my project and angular2-seed is that I use gulpfile.ts without using tools directory. I defined all gulp tasks in a single file.

I need some help to give me some hint on this error.

I have this very simplified component

import {Component} from 'angular2/core';
import {RouterLink, Router} from 'angular2/router';
import {CORE_DIRECTIVES} from 'angular2/common';

@Component({
  selector: 'cet-login',
  moduleId: module.id,
  templateUrl: 'apps/common/features/login/login.tpl.html',
  directives: [RouterLink, CORE_DIRECTIVES]
})
export class LoginComponent {
  constructor(
    private router: Router
  ) {}
}

and I have very simple unit test

import {
  TestComponentBuilder,
  describe,
  expect,
  injectAsync,
  it
} from 'angular2/testing';
import {Component} from 'angular2/core';
import {LoginComponent} from './login.cmp';

export function main(): void {
  'use strict';
  describe('Login component', () => {
    it('should work',
      injectAsync([TestComponentBuilder], (tcb: TestComponentBuilder) => {
        return tcb.createAsync(TestComponent)
          .then(rootTC => {
            rootTC.detectChanges();
            expect(1).toBe(1);
          });
      }));
  });
}

class Mock {}

@Component({
  selector: 'test-cmp',
  template: '<cet-login></cet-login>',
  directives: [LoginComponent]
})
class TestComponent {}

I also have gulpfile.ts test section like the following;

gulp.task('test:buildjs', 'Compile typescript test files', ['test:buildcss'], () => {
  var tsProject = tsProjectFn();

  var result = gulp.src(PATH.src.ts)
    .pipe(plumber())
    .pipe(sourcemaps.init())
    .pipe(inlineNg2Template({base: PATH.src.base}))
    .pipe(tsc(tsProject));

  return result.js
    .pipe(sourcemaps.init())
    .pipe(gulp.dest(PATH.dest.test));
});

gulp.task('test:unit', 'Start a karma server and run a unit test', (done: any) => {
  return new karma.Server({
    configFile: __dirname + '/karma.config.js',
    singleRun: true
  }).start(done);
});

When I run gulp test, which runs test:buildjs and test:unit, I have the following error

1) should work
     Login component
     Failed: Cannot read property 'componentInstance' of undefined
TypeError: Cannot read property 'componentInstance' of undefined
    at new ComponentFixture_ (C:/repos/FAR/node_modules/angular2/src/testing/test_component_builder.js:38:51)
    at C:/repos/FAR/node_modules/angular2/src/testing/test_component_builder.js:204:52
    at Zone.run (C:/repos/FAR/node_modules/zone.js/dist/zone-microtask.js:1217:24)
    at zoneBoundFn (C:/repos/FAR/node_modules/zone.js/dist/zone-microtask.js:1194:26)
    at lib$es6$promise$$internal$$tryCatch (C:/repos/FAR/node_modules/zone.js/dist/zone-microtask.js:442:17)
    at lib$es6$promise$$internal$$invokeCallback (C:/repos/FAR/node_modules/zone.js/dist/zone-microtask.js:454:18)
    at lib$es6$promise$$internal$$publish (C:/repos/FAR/node_modules/zone.js/dist/zone-microtask.js:425:12)
    at C:/repos/FAR/node_modules/zone.js/dist/zone-microtask.js:97:10
    at Zone.run (C:/repos/FAR/node_modules/zone.js/dist/zone-microtask.js:1217:24)
    at zoneBoundFn (C:/repos/FAR/node_modules/zone.js/dist/zone-microtask.js:1194:26)
    at lib$es6$promise$asap$$flush (C:/repos/FAR/node_modules/zone.js/dist/zone-microtask.js:236:10)

Any idea what I miss and what I am doing wrong?

Upvotes: 0

Views: 3190

Answers (2)

allenhwkim
allenhwkim

Reputation: 27738

Found the cause of this problem. The following line should be commented out for successful test.

import {enableProdMode} from 'angular2/core';
enableProdMode();

Upvotes: 0

Thierry Templier
Thierry Templier

Reputation: 202176

I don't know which version of Angular2 (in my case beta7+) you use but in my unit tests, I need to register TEST_BROWSER_PLATFORM_PROVIDERS and TEST_BROWSER_APPLICATION_PROVIDERS to be able to use the TestComponentBuilder class:

import {
  it,
  describe,
  expect,
  beforeEach,
  inject,
  injectAsync,
  TestComponentBuilder,
  ComponentFixture,
  setBaseTestProviders
} from 'angular2/testing';

import {
  TEST_BROWSER_PLATFORM_PROVIDERS,
  TEST_BROWSER_APPLICATION_PROVIDERS
} from 'angular2/platform/testing/browser';

import {MyListComponent} from "./my-list";
import {MyService} from "../services/my-service";

describe('MyList Tests', () => {
  setBaseTestProviders(TEST_BROWSER_PLATFORM_PROVIDERS,
                       TEST_BROWSER_APPLICATION_PROVIDERS);

  let list:MyListComponent;

  beforeEach(() => {
    list = new MyListComponent();
  });

  it('should render list', injectAsync([TestComponentBuilder], (tcb: TestComponentBuilder) => {
    return tcb.createAsync(MyListComponent).then((componentFixture: ComponentFixture) => {
      const element = componentFixture.nativeElement;
      componentFixture.detectChanges();
      expect(element.querySelectorAll('li').length).toBe(3);
    });
  }));
});

See this plunkr: https://plnkr.co/edit/oVBPsH?p=preview.

Upvotes: 1

Related Questions