ngUpgraders / ng-forward

The default solution for those that want to write Angular 2.x style code in Angular 1.x
410 stars 36 forks source link

Impossible to test a component with templateUrl #165

Closed prbaron closed 8 years ago

prbaron commented 8 years ago

Hi,

I wrote this simple component to play with unit testing with input and output.

import "./city-row.scss";
import {Component, Inject, Input, Output, EventEmitter} from "ng-forward";
import {City} from "../../models/city.model";

@Component({
  selector: "city-row",
  templateUrl: "./app/components/city-row/city-row.html"
  //   template: `<button class="btn btn-danger btn-xs pull-right" (click)="ctrl.removeCity(ctrl.city)"><span
  //   class="glyphicon glyphicon-trash"></span></button>
  // <span class="city-row-name">{{ctrl.city.name}}</span>
  // `
})
@Inject()
export class CityRowComponent {
  @Input() city;
  @Output() onRemove = new EventEmitter<City>();

  constructor() {
  }

  ngOnInit() {}

  removeCity(city: City) {
    this.onRemove.next(city);
  }
}

If I use the template property, the test is passing. However if I use templateUrl, Karma is sending me the following error :

Error: Unexpected request: GET ./app/components/city-row/city-row.html
    No more request expected (line 1407)
    $httpBackend
    sendReq
    serverRequest
    processQueue
    $eval
    $digest
    invoke
    workFn
    inject
    compileComponent
    create
    inject
    compileComponent
    create
    TypeError: undefined is not an object (evaluating 'cityRowComponent.city') (line 49)
    attemptSync@/Users/pierrebaron/Sites/ngForward-poc/node_modules/jasmine-core/lib/jasmine-core/jasmine.js:1886:28
    run@/Users/pierrebaron/Sites/ngForward-poc/node_modules/jasmine-core/lib/jasmine-core/jasmine.js:1874:20
    execute@/Users/pierrebaron/Sites/ngForward-poc/node_modules/jasmine-core/lib/jasmine-core/jasmine.js:1859:13
    queueRunnerFactory@/Users/pierrebaron/Sites/ngForward-poc/node_modules/jasmine-core/lib/jasmine-core/jasmine.js:697:42
    execute@/Users/pierrebaron/Sites/ngForward-poc/node_modules/jasmine-core/lib/jasmine-core/jasmine.js:359:28
    fn@/Users/pierrebaron/Sites/ngForward-poc/node_modules/jasmine-core/lib/jasmine-core/jasmine.js:2479:44
    attemptAsync@/Users/pierrebaron/Sites/ngForward-poc/node_modules/jasmine-core/lib/jasmine-core/jasmine.js:1916:28
    run@/Users/pierrebaron/Sites/ngForward-poc/node_modules/jasmine-core/lib/jasmine-core/jasmine.js:1871:21
    execute@/Users/pierrebaron/Sites/ngForward-poc/node_modules/jasmine-core/lib/jasmine-core/jasmine.js:1859:13
    queueRunnerFactory@/Users/pierrebaron/Sites/ngForward-poc/node_modules/jasmine-core/lib/jasmine-core/jasmine.js:697:42
    fn@/Users/pierrebaron/Sites/ngForward-poc/node_modules/jasmine-core/lib/jasmine-core/jasmine.js:2464:31
    attemptAsync@/Users/pierrebaron/Sites/ngForward-poc/node_modules/jasmine-core/lib/jasmine-core/jasmine.js:1916:28
    run@/Users/pierrebaron/Sites/ngForward-poc/node_modules/jasmine-core/lib/jasmine-core/jasmine.js:1871:21
    execute@/Users/pierrebaron/Sites/ngForward-poc/node_modules/jasmine-core/lib/jasmine-core/jasmine.js:1859:13
    queueRunnerFactory@/Users/pierrebaron/Sites/ngForward-poc/node_modules/jasmine-core/lib/jasmine-core/jasmine.js:697:42
    execute@/Users/pierrebaron/Sites/ngForward-poc/node_modules/jasmine-core/lib/jasmine-core/jasmine.js:2326:25
    execute@/Users/pierrebaron/Sites/ngForward-poc/node_modules/jasmine-core/lib/jasmine-core/jasmine.js:757:24
    /Users/pierrebaron/Sites/ngForward-poc/node_modules/karma-jasmine/lib/adapter.js:320:23
    loaded@http://localhost:9876/karma.js:194:17
    global code@http://localhost:9876/context.html:80:28

I know there have been a lot of threads about this problem for Angular2. How to fix this with ngForward ?

For information, here is my test specification :

/// <reference path="../../../../../typings/index.d.ts" />

import {TestComponentBuilder} from "ng-forward/cjs/testing/test-component-builder";
import {Component} from "ng-forward/index";
import {City} from "../../../models/city.model";
import {CityRowComponent} from "../city-row";

describe("CityRowComponent", function () {
  let tcb;
  let fixture;
  let testComponent;
  let testComponentElement;
  let cityRowComponent;
  let cityRowComponentElement;

  beforeEach(() => {
    @Component({
      selector: "test-component",
      template: `<city-row [city]="ctrl.city" (on-remove)="ctrl.removeCity($event.detail)"></city-row>`,
      directives: [CityRowComponent]
    })
    class TestComponent {
      city = new City("London, England, United Kingdom", 1);

      removeCity(city: City) {
      }
    }

    tcb = new TestComponentBuilder();
    fixture = tcb.create(TestComponent);
    testComponent = fixture.componentInstance;
    testComponentElement = fixture.nativeElement;
    let childFixture = fixture.debugElement.componentViewChildren[0];
    cityRowComponent = childFixture.componentInstance;
    cityRowComponentElement = childFixture.nativeElement;
  });

  it("renders the component", () => {
    expect(cityRowComponent.city).toEqual(new City("London, England, United Kingdom", 1));
  });

  it("updates the city input", () => {
    testComponent.city = new City("Paris, Île-de-France, France", 2);
    fixture.detectChanges();
    expect(cityRowComponent.city).toEqual(new City("Paris, Île-de-France, France", 2));
  });

  it("removes the city", (done) => {
    cityRowComponent.onRemove.subscribe((city) => {
      expect(city.name).toEqual("London, England, United Kingdom");
      expect(city.shortName).toEqual("london");
      expect(city.geonameId).toEqual(1);
      done();
    });

    cityRowComponent.onRemove.next(new City("London, England, United Kingdom", 1));
  });
});
timkindberg commented 8 years ago

You'd have to prepopulate $trmplateCache or mock out the response for the HTML file.

prbaron commented 8 years ago

Ok, we still have to do it angular1 style.

Thanks !