masterach
masterach

Reputation: 447

How to properly implement detectChanges() in Angular2?

I have the following code in jasmine:

    it('should pass on writing secondvalue in the input', async(() => {

      const fixture=TestBed.createComponent(AppComponent);
      const app=fixture.debugElement.nativeElement.querySelector("input").getAttribute("value");
      expect(app).toContain("firstvalue");
      fixture.detectChanges();
      expect(app).toContain("secondvalue");

      }));

The problem is that as soon as I run the test, the test fails. I expect it to wait because of the detectChanges() but it doesn't.

How do I properly implement: Waiting for the second value input for the input and check if the value will be "secondvalue".

Shouldn't the fixture.detectChanges() act like a even-blocker, for instance that it waits for the input to be triggered when someone starts writing on it?

Upvotes: 3

Views: 2700

Answers (1)

Marian
Marian

Reputation: 4079

When you make a change to your component state, you run detectChanges so that the changes propagate.

For example,

pageTitle: string;
ngOnInit() {
    this.pageTitle = 'first title';
}

And in the template:

<h4>{{pageTitle}}</h4>

In the test:

const fixture = TestBed.createComponent(AppComponent);
const h4 = fixture.debugElement.query(By.css('h4'));

console.log(component.pageTitle); // 'first title'
console.log(h4.nativeElement.textContent); // ''
fixture.detectChanges(); // Propagates ngOnInit changes
console.log(h4.nativeElement.textContent); // 'first title'

component.pageTitle = 'second title'; // Here we change state
console.log(component.pageTitle); // 'second title'
console.log(h4.nativeElement.textContent); // 'first title'
fixture.detectChanges(); // Propagate changes
console.log(h4.nativeElement.textContent); // 'second title'

A typical use case is checking things that depend on state, like having in template:

<div id="xxx" *ngIf="over18">Restricted content</div>

in component:

over18: boolean = false;

in test:

it('should show restricted content if over 18', () => {
    component.over18 = true; // change state from the default one
    fixture.detectChanges(); // propagate changes to view

    // now we can actually test
    const divElem = fixture.debugElement.query(By.css('div#xxx')); // would be null if not shown in DOM
    expect(divElem).toBeTruthy();
});

Note that I'm testing component logic. Checking that if I type "asdf" into input its value is going to update is, in my opinion, out of unit testing scope- this functionality is provided by HTML standard/ Angular team.

Upvotes: 3

Related Questions