1 of 18

Some new features of async test in angular

@JiaLiPassion

2 of 18

自己紹介

  • 名前: 李嘉
  • 会社: 利達ソフト
  • Zone.js: Collaborator
  • Angular: Contributor
  • Twitter: @jialipassion
  • Github: JiaLiPassion

3 of 18

Agenda

  • Proxy/Async/fakeAsync
  • FakeAsync
    • Date.now()
    • jasmine.clock()
    • Rxjs.scheduler (delay/asap/async)
  • Async
    • Pending Non Resolved Promiseを待つ
    • async beforeEach + async itをサポート(Bug改修)
  • 全体
    • Jasmine 2.9 & 3.x サポート
    • Mocha 5.x サポート
  • そのた

4 of 18

Describe/beforeEach/it -> ProxyZone

import ‘zone.js/dist/zone-testing’; // angular-cli の場合、すでにImport済み

describe(‘test’, () => { // ProxyZone(SyncTestZone)

beforeEach(() => {}); // ProxyZone

it(() => {}); // ProxyZone

});

5 of 18

async

it('(async)', async(() => { // ProxyZone(AsyncTestZone)� asyncOpertion(); �� fixture.whenStable().then(() => {// all async tasks finished� expect(quoteEl.textContent).toBe(testQuote);});}));

6 of 18

fakeAsync: setTimeout/Interval/requestAnimationFrame/Promise

it('(fakeAsync)', fakeAsync(() => {// ProxyZone(FakeAsyncZone)� setTimeout(() => {finish = true;}, 1000);� tick(1000);� expect(finish).toBe(true);�}));

7 of 18

fakeAsync: Date.now()

it('should show quote after getQuote (fakeAsync)', fakeAsync(() => { const start = Date.now();� tick(100);� const end = Date.now();� expect(end - start).toBe(100);}));

8 of 18

FakeAsync: jasmine.clock() -> auto fakeAsync

beforeEach(() => {� jasmine.clock().install();� });� afterEach(() => {� jasmine.clock().uninstall();� });� it('should get date diff correctly', () => { // we don't need fakeAsync here.// automatically run into fake async zone, because jasmine.clock() is installed.const start = Date.now();� jasmine.clock().tick(100);� const end = Date.now();� expect(end - start).toBe(100);� });

9 of 18

FakeAsync: rxjs scheduler(async/delay/asap)

it('should show quote after getQuote (fakeAsync)', fakeAsync(() => { observable.delay(1000).subscribe(v => {� result = v;� });� expect(result).toBeNull();� testZoneSpec.tick(1000);� expect(result).toBe('hello');}));

10 of 18

Async: Pending non resolved promise.then

it('should fail', async(() => {� const promise = new Promise((res, rej) => {

jsonp(url, res); // where jsonp is not zone aware

});� promise.then(() => {� expect(false).toBe(true);� });�}));

11 of 18

Async:async beforeEach + async it

beforeEach(async(() => {� TestBed.configureTestingModule({� declarations: [� AppComponent� ],� }).compileComponents();�}));�it('simple timeout', async(() => {� setTimeout(() => {� expect(true).toBe(true);� }, 200);� }));

12 of 18

Jasmine 2.9 ~ 3.x, mocha 5.x support

今のバージョンでエラーになる

13 of 18

fakeAsync: support more async operations

// tell fakeAsync should support HTMLCanvasElement.toBlobwindow['__zone_symbol__FakeAsyncTestMacroTask'] = [{� source: 'HTMLCanvasElement.toBlob',� callbackArgs: [{size: 100}] // the test blob data which will be passed back to callback�}];�

14 of 18

Zone.js 0.8.21(Release date unknown..)

15 of 18

Don’t call done in async/fakeAsync

it('should show quote after getQuote (async)', async((done: DoneFn) => {� asyncOpertion(() => {

doneFn(); // doneFn is undefined

}); �}));

16 of 18

Don’t return promise in async

it('should show quote after getQuote (async)', async((done: DoneFn) => {� return new Promise((res, rej) => {

asyncOperation(res);

});�}));

17 of 18

Sync operation in async

it('sync', async() => {� const a = 1 + 1;�}));

it('sync', async() => {� btn.addEventListener(‘click’, listener);�}));

18 of 18

Next...

  1. Rename async -> ?
  2. async should wait for pending observable.
  3. fixture.detectChange できるだけ自動実行?
  4. fakeAsync support MockBackend?
  5. Better timeout message

Error: Timeout - Async callback was not invoked within timeout specified by jasmine.DEFAULT_TIMEOUT_INTERVAL.�--Pendng async tasks are: [type: macroTask, source: setTimeout, args: {handleId:3,isPeriodic:false,delay:10000,args:[]}