2
votes

I'm trying to use fakeAsync to test an Angular 2 component, but the fixture variable is not being set. In fact, the promise callback is not being called. Here is the code:

@Component({
  template: '',
  directives: [GroupBox, GroupBoxHeader]
})
class TestComponent {
  expandedCallback() { this.expandedCalled = true; }
}

it('testing...', inject([TestComponentBuilder], fakeAsync((tcb) => {

  var fixture;

  tcb.createAsync(TestComponent).then((rootFixture) => {
    fixture = rootFixture
  });

  tick();

  fixture.detectChanges();
})));

When I run this code, I get:

Failed: Cannot read property 'detectChanges' of undefined TypeError: Cannot read property 'detectChanges' of undefined

I can't figure out why the callback isn't fired. In this repository, it works fine: https://github.com/juliemr/ng2-test-seed/blob/master/src/test/greeting-component_test.ts

Any clue?

Note: I'm using ES6, Traceur, Angular 2 beta, Karma and Jasmine.

------ UPDATE ------

It follows a repository with the failing test:

https://github.com/cangosta/ng2_testing_fakeasync

2
It looks like the problem is with the TestComponent. If I remove the line "directives: [GroupBox]" from the component definition, the error no longer occurscangosta
It seems to be a bug of the angular 2 framework: github.com/angular/angular/issues/5601cangosta
Yes github.com/juliemr/ng2-test-seed/blob/master/src/test/… is working because the template is inlineVishal Sakaria

2 Answers

2
votes
1
votes

Try this way https://github.com/antonybudianto/angular2-starter/blob/master/app/simplebind/child.component.spec.ts#L15

The point is you create a test dummy component (TestComponent for example) and register the component you want to test in directives: [...] and use template: <my-cmp></my-cmp>, then pass the TestComponent to tsb.createAsync(TestComponent)..., and use injectAsync.

I prefer this way since I can easily mock the data from parent, and pass any input and handle output to/from the component.

import {
it,
injectAsync,
describe,
expect,
TestComponentBuilder,
ComponentFixture
} from 'angular2/testing';
import { Component } from 'angular2/core';
import { ChildComponent } from './child.component';

@Component({
    selector: 'test',
    template: `
    <child text="Hello test" [(fromParent)]="testName"></child>
    `,
    directives: [ChildComponent]
})
class TestComponent {
    testName: string;

    constructor() {
        this.testName = 'From parent';
    }
}

let testFixture: ComponentFixture;
let childCompiled;
let childCmp: ChildComponent;

describe('ChildComponent', () => {
    it('should print inputs correctly', injectAsync([TestComponentBuilder],
    (tsb: TestComponentBuilder) => {
        return tsb.createAsync(TestComponent).then((fixture) => {
            testFixture = fixture;
            testFixture.detectChanges();

            childCompiled = testFixture.nativeElement;
            childCmp = testFixture.debugElement.children[0].componentInstance;

            expect(childCompiled).toBeDefined();
            expect(childCmp).toBeDefined();
            expect(childCompiled.querySelector('h6'))
                .toHaveText('From parent');
            expect(childCompiled.querySelector('h5'))
                .toHaveText('Hello test');
        });
    }));

    it('should trigger changeMe event correctly', () => {
        childCmp.changeMe();
        testFixture.detectChanges();
        expect(childCmp.num).toEqual(1);
        expect(childCompiled.querySelector('h6'))
            .toHaveText('Changed from child. Count: ' + childCmp.num);
    });
});