Search code examples
kendo-ui-angular2

angular 2 testing kendo-autocomplete


I'm trying to test a component that has kendo-autocomplete control. When the test is ruining the popup with the result doesn't show at all. What do I need to do?

Below you have the code if you need any other information please let me know.

Component

import { Component, OnInit, Input, Output, Inject } from '@angular/core';
import { IFieldLookUpService } from 'app/services/ifield-look-up.service';
import { FieldLookUpValueResults } from 'app/models/field-look-up-result';

@Component({
  selector: 'field-lookup',
  templateUrl: './field-lookup.component.html',
  styleUrls: ['./field-lookup.component.css']
})
export class FieldLookupComponent implements OnInit {
  @Input() fieldId: number;
  @Input() fieldName: string;
  @Output() selectedValue: string;
  private source: FieldLookUpValueResults;
  public fieldLookUpValues: FieldLookUpValueResults;

  constructor(@Inject('IFieldLookUpService') private fieldLookUpService: IFieldLookUpService) { }

  ngOnInit() {
    this.loadData();
  }

  handleFilter(value) {
    this.fieldLookUpValues.results = this.source.results.filter((s) => s.text.toLowerCase().indexOf(value.toLowerCase()) !== -1);
  }
  private loadData() {
    this.fieldLookUpService.getLookUpValues(this.fieldId, this.fieldName)
    .subscribe(data => { this.source = data;
      this.fieldLookUpValues = new FieldLookUpValueResults(this.source.header, null);
    })
  }
}

Component.html

<div *ngIf="fieldLookUpValues">
  <kendo-autocomplete [data]="fieldLookUpValues.results" [valueField]="'text'" [suggest]="true" [value]="selectedValue" [filterable]="true" (filterChange)="handleFilter($event)">
      <ng-template kendoAutoCompleteHeaderTemplate>
          <strong>{{fieldLookUpValues.header}}</strong>
      </ng-template>
  </kendo-autocomplete>
</div>

spec

import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { DebugElement } from '@angular/core';
import { By } from '@angular/platform-browser';

import { FieldLookupComponent } from './field-lookup.component';
import { FieldLookUpValueResults, FieldLookUpValue } from 'app/models/field-look-up-result';

import { IFieldLookUpService } from 'app/services/ifield-look-up.service';

import { Observable } from 'rxjs/Observable';

import { DropDownsModule } from '@progress/kendo-angular-dropdowns';

fdescribe('FieldLookupComponent', () => {
  let component: FieldLookupComponent;
  let fixture: ComponentFixture<FieldLookupComponent>;
  let debugEl: DebugElement;
  let mockFieldLookUpService;
  let inputElement;

  beforeEach(async(() => {
    mockFieldLookUpService = jasmine.createSpyObj('mockFieldLookUpService', ['getLookUpValues']);
    let mockData = new FieldLookUpValueResults('LookUp Values Result Header',
    [
      new FieldLookUpValue('LookUp Value 1', '1'),
      new FieldLookUpValue('LookUp Value 2', '2'),
    ]);

    mockFieldLookUpService.getLookUpValues.and.returnValue(Observable.of(mockData));

    TestBed.configureTestingModule({
      declarations: [ FieldLookupComponent ],
      imports: [
        DropDownsModule
      ],
      providers: [
        { provide: 'IFieldLookUpService', useFactory: () => mockFieldLookUpService },
      ]
    })
    .compileComponents();
  }));

  beforeEach(() => {
    fixture = TestBed.createComponent(FieldLookupComponent);
    component = fixture.componentInstance;
    debugEl = fixture.debugElement;
    fixture.detectChanges();
    inputElement = debugEl.query(By.css('input')).nativeElement;
    console.log(component);
  });

  fit('should be created', () => {
    expect(component).toBeTruthy();
  });

  fit('should have the autocomplete input', () => {
    expect(inputElement).toBeTruthy();
  });

  fdescribe('when character L is set in autocompelte box', () => {
    let list: DebugElement;
    let listItems: DebugElement[];

    beforeEach(() => {
      inputElement.value = 'L';
      fixture.detectChanges();
      list = debugEl.query(By.css('ul')).nativeElement;
      listItems =  list.queryAll(By.css('li'));
    })

    fit('should have the kend pop-up shown', () => {
      expect(list).toBeTruthy();
    });

  });

});
I set the value 'L' to the autocomplete input and then I should see the popup but they are null (the list and ListItems)

inputElement.value = 'L';
fixture.detectChanges();
list = debugEl.query(By.css('ul')).nativeElement;
listItems =  list.queryAll(By.css('li'));

Solution

  • The Popup component used in the AutoComplete (applicable to other Kendo components with Popup) is appended at the root component by default. In other words, the Popup is not part of the component tree. For those interested in why this is so, read this Github issue

    With those details in mind, you will need to use the AutoComplete instance and retrieve the Popup element from its popupRef property.

    {{ autocomplete?.popupRef?.popupElement.nodeName }}
    

    Here is a plunker that demonstrates this approach:

    http://plnkr.co/edit/bQTmfBUT7r5z6wjt5MtL?p=preview

    Please note that you will need to wait a tick in the tests in order to get the popupRef correctly.

    P.S. IMHO, testing the rendered UL list is unneeded. The vendor providing the AutoComplete component has already tested the output items based on the passed [data] value. Considering this fact, I would just test the autocomplete.data property, which should be sufficient.

    You can always add functional tests on top of that to ensure that the application you are building is working as a whole.