1

I have a problem with testing the select control in angular 6 and I am probably missing something obvious.

I have such a select control.

<select class="form-control form-control-light form-control-sm w-25 m-1" aria-label="Recent" [(ngModel)]="_selectedTenant">
<option *ngFor="let tenant of _tenants" [ngValue]="tenant.value">{{tenant.name}}</option>

It binds to pretty simple component.

export class TopNavbarComponent implements OnInit {

 _currentLang: string;
 _tenants: Tenant[];
 _selectedTenant: string;

 constructor(private translate: TranslateService, private tenantService: TenantService) {
 }

 ngOnInit() {
   this._currentLang = this.translate.currentLang;

this.tenantService.getTenants().subscribe(
  (tenants) => {
    this._tenants = tenants
    this._selectedTenant = this._tenants[0].value;
  },
  (error) => console.error(error)
)}}

And my test class with this one failing test

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

  let translateService: TranslateService;

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      imports: [FormsModule, TranslateModule.forRoot({
        loader: { provide: TranslateLoader, useClass: JsonTranslationLoader }
      })],
      declarations: [TopNavbarComponent],
      providers: [TranslateService]
    })
      .compileComponents();

    translateService = TestBed.get(TranslateService);

    translateService.currentLang = 'en';

  }));

  beforeEach(() => {
    fixture = TestBed.createComponent(TopNavbarComponent);
    component = fixture.componentInstance;
    fixture.detectChanges();
  });

it('should init after ngOnInit observables completes', fakeAsync(() => {
    const topnavElement: HTMLElement = fixture.nativeElement;
    const selectElement = topnavElement.querySelector('select');

    expect(selectElement.value).toEqual('');

    tick();
    fixture.detectChanges();

    expect(component._tenants).toBeTruthy();
    expect(component._tenants.length).toEqual(2);
    expect(component._selectedTenant).toEqual(component._tenants[0].value);

    fixture.detectChanges();

    console.log(selectElement);
    expect(selectElement.value).toEqual(component._selectedTenant);
  }));

And yet last expect fails. Select value is never there, it always appears as ''. I tried attribute selectedOptions but its length is 0.

I am unable to get this one value that supposed to be selected after setting _selectedTenant up in onInit that is bound to select with ngModel.

I now that this question is probably trivial but I never found an answer anywhere why this might be happening.

I am sure I will feel stupid after someone resolves this in like 1 minute after posting :(

Nevertheless, thanks foryour help!

0

2 Answers 2

1

I had the same issue, here's what worked for me:

expect(selectElement.getAttribute('ng-reflect-model')).toEqual(component._selectedTenant);
Sign up to request clarification or add additional context in comments.

1 Comment

This works however the attribute name right now is ng-reflect-model. Maybe it changed in one of angular versions?
0

While testing dom contents and values, you should fetch the dom elements every time when your view gets updated (i.e after doing fixture.detectChanges())

Add these two lines after fixture.detectChanges()

topnavElement = fixture.nativeElement;
selectElement = topnavElement.querySelector('select');

And use let instead of const, because you will be modifying those variables.

full spec

it('should init after ngOnInit observables completes', fakeAsync(() => {
    let topnavElement: HTMLElement = fixture.nativeElement;
    let selectElement = topnavElement.querySelector('select');

    expect(selectElement.value).toEqual('');

    tick();
    fixture.detectChanges();

    expect(component._tenants).toBeTruthy();
    expect(component._tenants.length).toEqual(2);
    expect(component._selectedTenant).toEqual(component._tenants[0].value);

    fixture.detectChanges();

    // fetch dom elements again to get updated data
    topnavElement = fixture.nativeElement;
    selectElement = topnavElement.querySelector('select');

    console.log(selectElement);
    expect(selectElement.value).toEqual(component._selectedTenant);
  }));

4 Comments

Unfortunately the result is exactly the same :( I kind of like this answer because it is a logical explanation but it does not work in this scenario. Value is still empty. Nicolas.leblanc's answer solves problem although the name of the attribute was changed to ng-reflect-model
Yes that should definitely work. Not sure if querySelector being the problem. Can you try selectElement = fixture.debugElement.queryAll(By.css('select')); and then expect(selectElement.nativeElement.value).toEqual(component._selectedTenant);
Sorry it has to be query() not queryAll().
Sorry still the same. Expected '' to be '1'

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.