it-swarm.com.de

Angular2 Unit Test mit @Input ()

Ich habe eine Komponente, die die Annotation @Input() für eine Instanzvariable verwendet, und ich versuche, meinen Komponententest für die Methode openProductPage() zu schreiben wie ich meinen Unit Test einrichte. Ich könnte diese Instanz öffentlich machen, aber ich denke nicht, dass ich darauf zurückgreifen sollte.

Wie richte ich meinen Jasmin-Test so ein, dass ein verspottetes Produkt injiziert wird (mitgeliefert?) Und ich die openProductPage() -Methode testen kann?

Meine Komponente:

import {Component, Input} from "angular2/core";
import {Router} from "angular2/router";

import {Product} from "../models/Product";

@Component({
    selector: "product-thumbnail",
    templateUrl: "app/components/product-thumbnail/product-thumbnail.html"
})

export class ProductThumbnail {
    @Input() private product: Product;


    constructor(private router: Router) {
    }

    public openProductPage() {
        let id: string = this.product.id;
        this.router.navigate([“ProductPage”, {id: id}]);
    }
}
51
hartpdx

Normalerweise mache ich etwas wie:

describe('ProductThumbnail', ()=> {
  it('should work',
    injectAsync([ TestComponentBuilder ], (tcb: TestComponentBuilder) => {
      return tcb.createAsync(TestCmpWrapper).then(rootCmp => {
        let cmpInstance: ProductThumbnail =  
               <ProductThumbnail>rootCmp.debugElement.children[ 0 ].componentInstance;

        expect(cmpInstance.openProductPage()).toBe(/* whatever */)
      });
  }));
}

@Component({
 selector  : 'test-cmp',
 template  : '<product-thumbnail [product]="mockProduct"></product-thumbnail>',
 directives: [ ProductThumbnail ]
})
class TestCmpWrapper { 
    mockProduct = new Product(); //mock your input 
}

Beachten Sie, dass product und alle anderen Felder in der ProductThumbnail -Klasse können bei diesem Ansatz privat sein (was der Hauptgrund ist, warum ich ihn trotz der Tatsache Thierrys vorziehen würde) dass es etwas ausführlicher ist).

14
awqueous

Wenn du benutzt TestBed.configureTestingModule Um Ihre Testkomponente zu kompilieren, haben wir einen anderen Ansatz. Es ist im Grunde das Gleiche wie die akzeptierte Antwort, kann aber ähnlicher sein, wie Angular-Cli die Spezifikationen generiert. FWIW.

import { Component, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { DebugElement } from '@angular/core';

describe('ProductThumbnail', () => {
  let component: ProductThumbnail;
  let fixture: ComponentFixture<TestComponentWrapper>;

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      declarations: [ 
        TestComponentWrapper,
        ProductThumbnail
      ],
      schemas: [CUSTOM_ELEMENTS_SCHEMA]
    })
    .compileComponents();

    fixture = TestBed.createComponent(TestComponentWrapper);
    component = fixture.debugElement.children[0].componentInstance;
    fixture.detectChanges();
  });

  it('should create', () => {
    expect(component).toBeTruthy();
  });
});

@Component({
  selector: 'test-component-wrapper',
  template: '<product-thumbnail [product]="product"></product-thumbnail>'
})
class TestComponentWrapper {
  product = new Product()
}
39
Danny Bullis

dies ist aus der offiziellen Dokumentation https://angular.io/docs/ts/latest/guide/testing.html#!#component-fixture . Sie können also ein neues Eingabeobjekt expectedHero erstellen und es an die Komponente comp.hero = expectedHero übergeben.

Stellen Sie außerdem sicher, dass Sie fixture.detectChanges(); zuletzt aufrufen, da andernfalls die Eigenschaft nicht an die Komponente gebunden wird.

Arbeitsbeispiel

// async beforeEach
beforeEach( async(() => {
    TestBed.configureTestingModule({
        declarations: [ DashboardHeroComponent ],
    })
    .compileComponents(); // compile template and css
}));

// synchronous beforeEach
beforeEach(() => {
    fixture = TestBed.createComponent(DashboardHeroComponent);
    comp    = fixture.componentInstance;
    heroEl  = fixture.debugElement.query(By.css('.hero')); // find hero element

    // pretend that it was wired to something that supplied a hero
    expectedHero = new Hero(42, 'Test Name');
    comp.hero = expectedHero;
    fixture.detectChanges(); // trigger initial data binding
});
28
Vazgen Manukyan

Sie müssen den Wert product für die Komponenteninstanz festlegen, nachdem sie in Ihren Test geladen wurde.

Als Beispiel dient hier eine einfache Komponente innerhalb einer Eingabe, die Sie als Grundlage für Ihren Anwendungsfall verwenden können:

@Component({
  selector: 'dropdown',
  directives: [NgClass],
  template: `
    <div [ngClass]="{open: open}">
    </div>
  `,
})
export class DropdownComponent {
  @Input('open') open: boolean = false;

  ngOnChanges() {
    console.log(this.open);
  }
}

Und der entsprechende Test:

it('should open', injectAsync([TestComponentBuilder], (tcb: TestComponentBuilder) => {
  return tcb.createAsync(DropdownComponent)
  .then(fixture => {
    let el = fixture.nativeElement;
    let comp: DropdownComponent = fixture.componentInstance;

    expect(el.className).toEqual('');

    // Update the input
    comp.open = true; // <-----------

    // Apply
    fixture.detectChanges(); // <-----------

    var div = fixture.nativeElement.querySelector('div');
    // Test elements that depend on the input
    expect(div.className).toEqual('open');
  });
}));

Sehen Sie sich dieses Beispiel an: https://plnkr.co/edit/YAVD4s?p=preview .

18