angular: [testing] valueChanges-Event of Control is not executed when dispatching Event for Input-Field

  • What is the current behavior?

I want to Unit Test my Typeahead component that is configured as followed:

    <input type="text" #query class="form-control"
           id="searchField"
           [ngFormControl]="searchTerm">
  searchTerm = new Control();
  ngOnInit() {
    Observable.merge(
      Observable.of(""),
      this.searchTerm.valueChanges.debounceTime(500))
      .switchMap((term :string) => this.taskService.findTasks({'q': term}))
      .subscribe();
  }

Trying to unit test the form like this:

  iit('should execute a Typeahead-Search', <any> fakeAsync(() => {
    fixture.detectChanges();
    let taskList = fixture.componentInstance,
      element = fixture.nativeElement;
    var spy : Spy = spyOn(taskService, 'findTasks').and.callThrough();
    let input = element.querySelector('#searchField');
    input.value = 'Term';
    dispatchEvent(input, 'input');
    //dispatchEvent(input, 'change'); doesn't matter what I dispatch here
    //dispatchEvent(input, 'blur');
    fixture.detectChanges();
    tick(600);
    console.log(input.value); // prints "Term" so value was updated
    expect(taskService.findTasks).toHaveBeenCalledWith({'q': 'Term'});
  }));

never emits a valueChanges Event for the form. When doing it like this:

  iit('should execute a Typeahead-Search', <any> fakeAsync(() => {
    fixture.detectChanges();

    let taskList = fixture.componentInstance,
      element = fixture.nativeElement;
    var spy : Spy = spyOn(taskService, 'findTasks').and.callThrough();
    let input = element.querySelector('#searchField');
    taskList.searchTerm.updateValue("Term", {});
    fixture.detectChanges();
    tick(600);
    expect(taskService.findTasks).toHaveBeenCalledWith({'q': 'Term'});
  }));

the test works.

  • What is the expected behavior?

dispatchEvent should lead to a valueChanges-call in the component

  • What is the motivation / use case for changing the behavior?
  • Please tell us about your environment:
  • Angular version: 2.0.0-beta.8
  • Browser: [Chrome / Karma]
  • Language: TypeScript 1.8.7]
  • Other information (e.g. detailed explanation, stacktraces, related issues, suggestions how to fix, links for us to have context, eg. stackoverflow, gitter, etc)

About this issue

  • Original URL
  • State: open
  • Created 8 years ago
  • Reactions: 10
  • Comments: 21 (7 by maintainers)

Most upvoted comments

I’ve got a similar issue, but I can’t get your working example to work in my case. If I include the debounceTime() call I always get an exception from zone.js like so:

Error: 1 periodic timer(s) still in the queue.

Is there a decent guide on how to do these kinds of tests?

Getting a similar problem. I have a component with an input looking like this :

<input type="text" class="form-control name-input" placeholder="Search" 
       name="name" ngModel #name="ngModel">

In my class I’ve got the following :

export class Example {
   @ViewChild('name') name;

   ngOnInit () {
      const that = this;
      
      this.name.valueChanges
            .debounceTime(300)
            .distinctUntilChanged()
            .subscribe(this.onInputChange.bind(that));
   }

   private onInputChange (search: string) { ... }
}

This code works as expected in my application, however when I try to test this it’s not working. Here is my test :

it('test', async(() => {
   /** Do some async stuff **/
   this.fixture.whenStable().then(() => {
      this.fixture.detectChanges();
      const nameInput = this.fixture.debugElement.query(By.css('input[name="name"]'));
      nameInput.nativeElement.value = 'test';
      nameInput.nativeElement.dispatchEvent(new Event('input'));
   });
}));

At this moment, I expect the onInputChange method to be called with the new input value, but it never happens.

If anyone can help, I would appreciate.

I also struggled with this. In my case I had updateOn=“blur” set. Given a text input called “fieldValueInput”, the correct sequence to produce a valueChanges emission on its form control is then:

        fieldValueInput.value = 'my new value';
        fieldValueInput.dispatchEvent(new Event('input'));
        fieldValueInput.dispatchEvent(new Event('blur'));

can confirm in Angular 10.0.8 under fakeAsync wrap form.valueChanges does not trigger. How do people test their forms if controls are co-dependant?

@Orodan @davinkevin @gabrielalan @choeller

My issue was fixed when focusing on the input before dispatchEvent. so in @Orodan’s example:

nameInput.focus(); nameInput.nativeElement.value = ‘test’; nameInput.nativeElement.dispatchEvent(new Event(‘input’));

@DzmitryShylovich I’m still experiencing the same behaviour using angular 4.1.2