Angular unit test input value

AngularUnit TestingAngular2 Testing

Angular Problem Overview


I have been reading official Angular2 documentation for unit testing (https://angular.io/docs/ts/latest/guide/testing.html) but I am struggling with setting a component's input field value so that its reflected in the component property (bound via ngModel). The screen works fine in the browser, but in the unit test I cannot seem to be able to set the fields value.

I am using below code. "fixture" is properly initialized as other tests are working fine. "comp" is instance of my component, and the input field is bound to "user.username" via ngModel.

it('should update model...', async(() => {
    let field: HTMLInputElement = fixture.debugElement.query(By.css('#user')).nativeElement;
    field.value = 'someValue'
    field.dispatchEvent(new Event('input'));
    fixture.detectChanges();

    expect(field.textContent).toBe('someValue');
    expect(comp.user.username).toBe('someValue');
  }));

My version of Angular2: "@angular/core": "2.0.0"

Angular Solutions


Solution 1 - Angular

Inputs don't have textContent, only a value. So expect(field.textContent).toBe('someValue'); is useless. That's probably what's failing. The second expectation should pass though. Here's a complete test.

@Component({
  template: `<input type="text" [(ngModel)]="user.username"/>`
})
class TestComponent {
  user = { username: 'peeskillet' };
}

describe('component: TestComponent', () => {
  beforeEach(() => {
    TestBed.configureTestingModule({
      imports: [FormsModule],
      declarations: [ TestComponent ]
    });
  });

  it('should be ok', async(() => {
    let fixture = TestBed.createComponent(TestComponent);
    fixture.detectChanges();
    fixture.whenStable().then(() => {
      let input = fixture.debugElement.query(By.css('input'));
      let el = input.nativeElement;

      expect(el.value).toBe('peeskillet');

      el.value = 'someValue';
      el.dispatchEvent(new Event('input'));

      expect(fixture.componentInstance.user.username).toBe('someValue');
    });
  }));
});

The important part is the first fixture.whenStable(). There is some asynchronous setup with the forms that occurs, so we need to wait for that to finish after we do fixture.detectChanges(). If you are using fakeAsync() instead of async(), then you would just call tick() after fixture.detectChanges().

Solution 2 - Angular

Just add

fixture.detectChanges();

fixture.whenStable().then(() => {
  // here your expectation
})

Solution 3 - Angular

Use your expect/assert within the whenStable.then function like this:

component.label = 'blah';
fixture.detectChanges();

fixture.whenStable().then(() => {
    expect(component.label).toBe('blah');
}

Solution 4 - Angular

If you want to implement Unit Testing with @Input content then go through this below code.

testing.component.ts

    import { Component, OnInit } from '@angular/core';
    @Component({
      selector: 'app-testing',
      templateUrl: `<app-input [message]='text'></app-input>`,
      styleUrls: ['./testing.component.css']
    })
    export class TestingComponent implements OnInit {
    public text = 'input message';
      constructor() { }
    
      ngOnInit() {
      }
    
    }

input.component.ts

    import { Component, OnInit, Input } from '@angular/core';
    
    @Component({
      selector: 'app-input',
      templateUrl: `<div *ngIf="message">{{message}}</div>`,
      styleUrls: ['./input.component.css']
    })
    export class InputComponent implements OnInit {
    @Input() public message: string;
      constructor() { }
    
      ngOnInit() {
        console.log(this.message);
      }
    
    }

input.component.spec.ts

    import { async, ComponentFixture, TestBed } from '@angular/core/testing';
    
    import { InputComponent } from './input.component';
    import { TestingComponent } from '../testing/testing.component';
    
    describe('InputComponent', () => {
      let component: InputComponent;
      let fixture: ComponentFixture<InputComponent>;
    
      beforeEach(async(() => {
        TestBed.configureTestingModule({
          declarations: [ InputComponent, TestingComponent ]
        })
        .compileComponents();
      }));
    
      beforeEach(() => {
        fixture = TestBed.createComponent(InputComponent);
        component = fixture.componentInstance;
        fixture.detectChanges();
      });
    
      it('should create', () => {
        expect(component).toBeTruthy();
      });
    
      it('should correctly render the passed @Input value', () => {
        component.message = 'test input';
        fixture.detectChanges();
        expect(fixture.nativeElement.innerText).toBe('test input');
      });
    
    });

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionZygaView Question on Stackoverflow
Solution 1 - AngularPaul SamsothaView Answer on Stackoverflow
Solution 2 - AngularktretyakView Answer on Stackoverflow
Solution 3 - AngularAkash YellappaView Answer on Stackoverflow
Solution 4 - AngularPriti jhaView Answer on Stackoverflow