2017-07-15 8 views
1

私は、コードの深いところで解決される多くの内部約束を持つアプリケーションのjasmine/karma/webpack単体テストを書いています。私は、角度の非同期、fixture.detectChangesとfixture.whenStableを使用したいと思います。angular 4.3.0非同期関数を実行した後にfixture.whenStableを呼び出します

概念の証明として、私は以下のシンプルだが非常に非同期のコンポーネントを作った。

import {Component} from "@angular/core"; 
import {Logger} from "../../utils/logger"; 

@Component({ 
    selector: 'unit-test.html', 
    template: `  
    <div class="unit-test"> 
    <h3>Unit Test Component</h3> 
    <h4>p1: {{p1}}</h4> 
    <h4>v1: {{v1}}</h4> 
    <h4>p2: {{p2}}</h4> 
    <h4>v2: {{v2}}</h4> 
    <h4>p3: {{p3}}</h4> 
    <h4>v3: {{v3}}</h4> 
    </div>` 
}) 
export class UnitTestComponent { 
    p1: Promise<string>; 
    v1: string; 
    p2: Promise<string>; 
    v2: string; 
    p3: Promise<string>; 
    v3: string; 

    constructor() { 
    this.p1 = makeTimeoutPromise('value1', 2000); 
    Logger.warn('p1 created'); 
    this.p1.then(data => { 
     this.v1 = data 
    }); 
    } 

    method2() { 
    this.p2 = makeTimeoutPromise('value2', 2000); 
    this.p2.then(data => { 
     this.v2 = data 
    }); 
    Logger.warn('p2 created'); 
    } 

    method3() { 
    this.p3 = makeTimeoutPromise('value3', 2000); 
    this.p3.then(data => { 
     this.v3 = data 
    }); 
    Logger.warn('p2 created'); 
    } 
} 


function makeTimeoutPromise(result: string, timeout: number) { 
    return new Promise<string>((resolve, reject) => { 
    setTimeout(() => { 
     resolve(result); 
     Logger.warn(`resolved '${result}' after '${timeout}' seconds`); 
    }, timeout) 
    }); 
} 

これをテストするには、非同期ブロックでコンポーネントを作成します。これは動作し、itブロックはコンストラクタの約束が解決された後に実行を開始します。

私はcomp.method2()を呼び出すと、2秒後に約束が解決されます。しかし....そして私が得られない部分があります... comp.method2()を呼び出した直後にfixture.isStable()を呼び出すとtrueが返されます。私は偽を期待していただろう。悪い... fixture.whenStable()はすぐに解決します。実際の方法の約束が解決されていないので、私はまだテストしたいという価値がありません。

import {UnitTestComponent} from './unit-test.component'; 
import {async, ComponentFixture, TestBed, tick} from '@angular/core/testing'; 
import {DebugElement} from '@angular/core'; 

describe('UnitTestComponent',() => { 
    let de: DebugElement; 
    let comp: UnitTestComponent; 
    let fixture: ComponentFixture<UnitTestComponent>; 
    let el: HTMLElement; 
    const startTime = Date.now(); 
    beforeEach(async(() => { 
    console.log('time beforeEach.start', Date.now() - startTime); 
    const testbed = TestBed.configureTestingModule({ 
     declarations:[UnitTestComponent], 
     imports: [], 
     providers: [] 
    }); 
    // testbed.compileComponents(); 
    console.log('time beforeEach.initSsmpComponentLibModule', Date.now() - startTime); 
    fixture = TestBed.createComponent(UnitTestComponent); 
    comp = fixture.componentInstance; 
    de = fixture.debugElement; 
    console.log('time beforeEach.end', Date.now() - startTime); 
    })); 

    it('should create the component', async(() => { 
    // const x = new Promise<any>((resolve, reject)=>{ 
    // setTimeout(()=>{ 
    //  console.log('right before exit', comp); 
    //  fixture.detectChanges(); 
    //  resolve(); 
    //  }, 10000); 
    // }); 
    console.log('time it.start', Date.now() - startTime, comp); 
    expect(comp).toBeDefined(); 
    console.log('fixture.isStable() (1)', fixture.isStable()); 
    comp.method2(); 
    console.log('fixture.isStable() (2)', fixture.isStable()); 
    fixture.whenStable() 
     .then(data=>{ 
     fixture.detectChanges(); 
     console.log('time after whenStable(1) resolves', Date.now() - startTime, comp); 
     fixture.detectChanges(); 
     console.log('time after whenStable(1).detect changes completes', Date.now() - startTime, comp); 
     expect(comp.v2).toBe('value2'); 
     comp.method3(); 
     console.log('method3 called', Date.now() - startTime, comp); 
     fixture.detectChanges(); 
     console.log('time after detectChanges (2)', Date.now() - startTime, comp); 
     fixture.whenStable() 
      .then(data=>{ 
      fixture.detectChanges(); 
      console.log('time after whenStable(3).then', Date.now() - startTime, comp); 
      expect(comp.v3).toBe('value3'); 
      }); 
     console.log('time after whenStable(3)', Date.now() - startTime, comp); 

     }); 
    console.log('time after whenStable(2)', Date.now() - startTime, comp); 
    })); 


}); 

コンソールログの出力は以下のとおりです。私は

fixture.isStable() (2) false 
time after whenStable(2) >=4386 UnitTestComponent {p1: ZoneAwarePromise, v1: "value1", p2: ZoneAwarePromise} 

を期待していたが)(comp.method2の明示的な知識なしの内部を

fixture.isStable() (2) true 
time after whenStable(2) 2390 UnitTestComponent {p1: ZoneAwarePromise, v1: "value1", p2: ZoneAwarePromise} 

time beforeEach.start 363 
time beforeEach.initSsmpComponentLibModule 363 
time beforeEach.end 387 
time it.start 2386 UnitTestComponent {p1: ZoneAwarePromise, v1: "value1"} 
fixture.isStable() (1) true 
fixture.isStable() (2) true 
time after whenStable(2) 2390 UnitTestComponent {p1: ZoneAwarePromise, v1: "value1", p2: ZoneAwarePromise} 
time after whenStable(1) resolves 2393 time beforeEach.start 363 

を得た、どのように私はすべての約束はメソッドから解決までの角度待ち時間を持つことができますit()メソッドの中で呼び出されますか?私はこれがfixture.whenStableの明白な役割だと思った。

答えて

0

私自身の質問に答える。もちろん!私はゾーンで走っていなかった。したがって、これを修正するには2つの方法があります。 (私は両方を証明した)。

解決策1:ブラウザイベントをテストする場合は、ネイティブ要素を取得してクリックします。 (だから私は)

<button id='unit-test-method-2-button'(click)="method2()">Method 2</button> 

、その後、法2(と呼ばを追加私のニーズのためにも、よりよい解決策は、単にNgZoneを注入することでした

const button = de.query(By.css('#unit-test-method-2-button')); 
expect(button).toBeDefined(); 
button.nativeElement.click(); 

を使用して。これは、(私がfixture.whenStableにネストされた呼び出しを行うことを許可)。

は、このように私は

beforeEach(inject([NgZone], (injectedNgZone: NgZone) => { 
    ngZone = injectedNgZone; 
})); 

を追加し、これは、私が非同期法2を呼び出すことが許さ次に非同期メソッド3を使用し、fixture.whenStableを使用します。

it('should create the component', async(() => { 
    ngZone.run(() => { 
    console.log('time it.start', Date.now() - startTime, comp); 
    expect(comp).toBeDefined(); 
    expect(fixture.isStable()).toBe(true, 'expect fixture to be stable'); 
    comp.method2(); 
    expect(fixture.isStable()).toBe(false, 'expect fixture not to be stable'); 
    fixture.whenStable() 
     .then(data => { 
     fixture.detectChanges(); 
     expect(comp.v2).toBe('value2'); 
     comp.method3(); 
     fixture.whenStable() 
      .then(data => { 
      fixture.detectChanges(); 
      expect(comp.v3).toBe('value3'); 
      }); 
     }); 
    }); 
})); 
関連する問題