Angular2 unit test with @Input()

前端 未结 4 1336
广开言路
广开言路 2020-12-23 15:53

I\'ve got a component that uses the @Input() annotation on an instance variable and I\'m trying to write my unit test for the openProductPage() met

相关标签:
4条回答
  • 2020-12-23 16:20

    I usually do something like:

    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 
    }
    

    Note that product and any other fields on the ProductThumbnail class can be private with this approach (which is the main reason I prefer it over Thierry's approach, despite the fact that it's a little more verbose).

    0 讨论(0)
  • 2020-12-23 16:30

    this is from official documentation https://angular.io/docs/ts/latest/guide/testing.html#!#component-fixture. So you can create new input object expectedHero and pass it to the component comp.hero = expectedHero

    Also make sure to call fixture.detectChanges(); last, otherwise property will not be bound to component.

    Working Example

    // 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
    });
    
    0 讨论(0)
  • 2020-12-23 16:38

    If you use TestBed.configureTestingModule to compile your test component, here's another approach. It's basically the same as the accepted answer, but may be more similar to how angular-cli generates the specs. 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()
    }
    
    0 讨论(0)
  • 2020-12-23 16:42

    You need to set the product value on the component instance after it has been loaded within your test.

    As a sample here is a simple component within an input that you can use as a foundation for your use case:

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

    And the corresponding 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');
      });
    }));
    

    See this plunkr as a sample: https://plnkr.co/edit/YAVD4s?p=preview.

    0 讨论(0)
提交回复
热议问题