From 1c575a2df5e92fcf9ee7ddf17a35ba8e19ad7981 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Mon, 19 Nov 2018 09:25:28 +0100 Subject: [PATCH] use native promises in Tree related to #62716 --- src/vs/base/parts/tree/browser/treeModel.ts | 115 +++-- .../parts/tree/test/browser/treeModel.test.ts | 429 ++++++++---------- 2 files changed, 259 insertions(+), 285 deletions(-) diff --git a/src/vs/base/parts/tree/browser/treeModel.ts b/src/vs/base/parts/tree/browser/treeModel.ts index 9b4049178bb..ecfbe852b10 100644 --- a/src/vs/base/parts/tree/browser/treeModel.ts +++ b/src/vs/base/parts/tree/browser/treeModel.ts @@ -8,7 +8,6 @@ import { onUnexpectedError } from 'vs/base/common/errors'; import { IDisposable, combinedDisposable } from 'vs/base/common/lifecycle'; import * as arrays from 'vs/base/common/arrays'; import { INavigator } from 'vs/base/common/iterator'; -import * as WinJS from 'vs/base/common/winjs.base'; import * as _ from './tree'; import { Event, Emitter, once, EventMultiplexer, Relay } from 'vs/base/common/event'; @@ -79,20 +78,20 @@ export class Lock { return !!this.locks[item.id]; } - public run(item: Item, fn: () => WinJS.Promise): WinJS.Promise { + public run(item: Item, fn: () => Thenable): Thenable { var lock = this.getLock(item); if (lock) { - return new WinJS.TPromise((c, e) => { + return new Promise((c, e) => { once(lock.onDispose)(() => { return this.run(item, fn).then(c, e); }); }); } - var result: WinJS.Promise; + var result: Thenable; - return new WinJS.TPromise((c, e) => { + return new Promise((c, e) => { if (item.isDisposed()) { return e(new Error('Item is disposed.')); @@ -351,24 +350,24 @@ export class Item { this._onDidReveal.fire(eventData); } - public expand(): WinJS.Promise { + public expand(): Thenable { if (this.isExpanded() || !this.doesHaveChildren || this.lock.isLocked(this)) { - return WinJS.TPromise.as(false); + return Promise.resolve(false); } var result = this.lock.run(this, () => { if (this.isExpanded() || !this.doesHaveChildren) { - return WinJS.TPromise.as(false); + return Promise.resolve(false); } var eventData: IItemExpandEvent = { item: this }; - var result: WinJS.Promise; + var result: Thenable; this._onExpand.fire(eventData); if (this.needsChildrenRefresh) { result = this.refreshChildren(false, true, true); } else { - result = WinJS.TPromise.as(null); + result = Promise.resolve(null); } return result.then(() => { @@ -392,9 +391,9 @@ export class Item { }); } - public collapse(recursive: boolean = false): WinJS.Promise { + public collapse(recursive: boolean = false): Thenable { if (recursive) { - var collapseChildrenPromise = WinJS.TPromise.as(null); + var collapseChildrenPromise = Promise.resolve(null); this.forEachChild((child) => { collapseChildrenPromise = collapseChildrenPromise.then(() => child.collapse(true)); }); @@ -403,7 +402,7 @@ export class Item { }); } else { if (!this.isExpanded() || this.lock.isLocked(this)) { - return WinJS.TPromise.as(false); + return Promise.resolve(false); } return this.lock.run(this, () => { @@ -412,7 +411,7 @@ export class Item { this._setExpanded(false); this._onDidCollapse.fire(eventData); - return WinJS.TPromise.as(true); + return Promise.resolve(true); }); } } @@ -448,7 +447,7 @@ export class Item { return this.height; } - private refreshChildren(recursive: boolean, safe: boolean = false, force: boolean = false): WinJS.Promise { + private refreshChildren(recursive: boolean, safe: boolean = false, force: boolean = false): Thenable { if (!force && !this.isExpanded()) { const setNeedsChildrenRefresh = (item: Item) => { item.needsChildrenRefresh = true; @@ -457,7 +456,7 @@ export class Item { setNeedsChildrenRefresh(this); - return WinJS.TPromise.as(this); + return Promise.resolve(this); } this.needsChildrenRefresh = false; @@ -466,20 +465,20 @@ export class Item { var eventData: IItemChildrenRefreshEvent = { item: this, isNested: safe }; this._onRefreshChildren.fire(eventData); - var childrenPromise: WinJS.Promise; + var childrenPromise: Thenable; if (this.doesHaveChildren) { childrenPromise = this.context.dataSource.getChildren(this.context.tree, this.element); } else { - childrenPromise = WinJS.TPromise.as([]); + childrenPromise = Promise.resolve([]); } const result = childrenPromise.then((elements: any[]) => { if (this.isDisposed() || this.registry.isDisposed()) { - return WinJS.TPromise.as(null); + return Promise.resolve(null); } if (!Array.isArray(elements)) { - return WinJS.TPromise.wrapError(new Error('Please return an array of children.')); + return Promise.reject(new Error('Please return an array of children.')); } elements = !elements ? [] : elements.slice(0); @@ -510,16 +509,16 @@ export class Item { } if (recursive) { - return WinJS.Promise.join(this.mapEachChild((child) => { + return Promise.all(this.mapEachChild((child) => { return child.doRefresh(recursive, true); })); } else { - return WinJS.Promise.join(this.mapEachChild((child) => { + return Promise.all(this.mapEachChild((child) => { if (child.isExpanded() && child.needsChildrenRefresh) { return child.doRefresh(recursive, true); } else { child.updateVisibility(); - return WinJS.TPromise.as(null); + return Promise.resolve(null); } })); } @@ -533,7 +532,7 @@ export class Item { return safe ? doRefresh() : this.lock.run(this, doRefresh); } - private doRefresh(recursive: boolean, safe: boolean = false): WinJS.Promise { + private doRefresh(recursive: boolean, safe: boolean = false): Thenable { this.doesHaveChildren = this.context.dataSource.hasChildren(this.context.tree, this.element); this.height = this._getHeight(); this.updateVisibility(); @@ -547,7 +546,7 @@ export class Item { this.setVisible(this._isVisible()); } - public refresh(recursive: boolean): WinJS.Promise { + public refresh(recursive: boolean): Thenable { return this.doRefresh(recursive); } @@ -930,7 +929,7 @@ export class TreeModel { this.traitsToItems = {}; } - public setInput(element: any): WinJS.Promise { + public setInput(element: any): Thenable { var eventData: IInputEvent = { item: this.input }; this._onSetInput.fire(eventData); @@ -977,11 +976,11 @@ export class TreeModel { return this.input ? this.input.getElement() : null; } - public refresh(element: any = null, recursive: boolean = true): WinJS.Promise { + public refresh(element: any = null, recursive: boolean = true): Thenable { var item = this.getItem(element); if (!item) { - return WinJS.TPromise.as(null); + return Promise.resolve(null); } var eventData: IRefreshEvent = { item: item, recursive: recursive }; @@ -991,17 +990,17 @@ export class TreeModel { }); } - public expand(element: any): WinJS.Promise { + public expand(element: any): Thenable { var item = this.getItem(element); if (!item) { - return WinJS.TPromise.as(false); + return Promise.resolve(false); } return item.expand(); } - public expandAll(elements?: any[]): WinJS.Promise { + public expandAll(elements?: any[]): Thenable { if (!elements) { elements = []; @@ -1013,24 +1012,54 @@ export class TreeModel { } } + return this._expandAll(elements); + } + + private _expandAll(elements: any[]): Thenable { + if (elements.length === 0) { + return Promise.resolve(null); + } + + const elementsToExpand: any[] = []; + const elementsToDelay: any[] = []; + + for (const element of elements) { + var item = this.getItem(element); + + if (item) { + elementsToExpand.push(element); + } else { + elementsToDelay.push(element); + } + } + + if (elementsToExpand.length === 0) { + return Promise.resolve(null); + } + + return this.__expandAll(elementsToExpand) + .then(() => this._expandAll(elementsToDelay)); + } + + private __expandAll(elements: any[]): Thenable { var promises = []; for (var i = 0, len = elements.length; i < len; i++) { promises.push(this.expand(elements[i])); } - return WinJS.Promise.join(promises); + return Promise.all(promises); } - public collapse(element: any, recursive: boolean = false): WinJS.Promise { + public collapse(element: any, recursive: boolean = false): Thenable { var item = this.getItem(element); if (!item) { - return WinJS.TPromise.as(false); + return Promise.resolve(false); } return item.collapse(recursive); } - public collapseAll(elements: any[] | null = null, recursive: boolean = false): WinJS.Promise { + public collapseAll(elements: any[] | null = null, recursive: boolean = false): Thenable { if (!elements) { elements = [this.input]; recursive = true; @@ -1039,19 +1068,19 @@ export class TreeModel { for (var i = 0, len = elements.length; i < len; i++) { promises.push(this.collapse(elements[i], recursive)); } - return WinJS.Promise.join(promises); + return Promise.all(promises); } - public toggleExpansion(element: any, recursive: boolean = false): WinJS.Promise { + public toggleExpansion(element: any, recursive: boolean = false): Thenable { return this.isExpanded(element) ? this.collapse(element, recursive) : this.expand(element); } - public toggleExpansionAll(elements: any[]): WinJS.Promise { + public toggleExpansionAll(elements: any[]): Thenable { var promises = []; for (var i = 0, len = elements.length; i < len; i++) { promises.push(this.toggleExpansion(elements[i])); } - return WinJS.Promise.join(promises); + return Promise.all(promises); } public isExpanded(element: any): boolean { @@ -1078,9 +1107,9 @@ export class TreeModel { return result; } - public reveal(element: any, relativeTop: number | null = null): WinJS.Promise { + public reveal(element: any, relativeTop: number | null = null): Thenable { return this.resolveUnknownParentChain(element).then((chain: any[]) => { - var result = WinJS.TPromise.as(null); + var result = Promise.resolve(null); chain.forEach((e) => { result = result.then(() => this.expand(e)); @@ -1096,10 +1125,10 @@ export class TreeModel { }); } - private resolveUnknownParentChain(element: any): WinJS.Promise { + private resolveUnknownParentChain(element: any): Thenable { return this.context.dataSource.getParent(this.context.tree, element).then((parent) => { if (!parent) { - return WinJS.TPromise.as([]); + return Promise.resolve([]); } return this.resolveUnknownParentChain(parent).then((result) => { diff --git a/src/vs/base/parts/tree/test/browser/treeModel.test.ts b/src/vs/base/parts/tree/test/browser/treeModel.test.ts index 6a06ade8338..6bdc99dfc77 100644 --- a/src/vs/base/parts/tree/test/browser/treeModel.test.ts +++ b/src/vs/base/parts/tree/test/browser/treeModel.test.ts @@ -6,7 +6,6 @@ import * as assert from 'assert'; import * as lifecycle from 'vs/base/common/lifecycle'; import * as _ from 'vs/base/parts/tree/browser/tree'; -import * as WinJS from 'vs/base/common/winjs.base'; import * as model from 'vs/base/parts/tree/browser/treeModel'; import * as TreeDefaults from 'vs/base/parts/tree/browser/treeDefaults'; import { Event, Emitter } from 'vs/base/common/event'; @@ -170,11 +169,11 @@ class TestDataSource implements _.IDataSource { return !!element.children; } - public getChildren(tree, element): WinJS.Promise { - return WinJS.TPromise.as(element.children); + public getChildren(tree, element): Thenable { + return Promise.resolve(element.children); } - public getParent(tree, element): WinJS.Promise { + public getParent(tree, element): Thenable { throw new Error('Not implemented'); } } @@ -254,14 +253,14 @@ suite('TreeModel', () => { test('refresh(expanded element) refreshes the element and descendants', () => { return model.setInput(SAMPLE.AB).then(() => { - model.expand(SAMPLE.AB.children[0]); - - counter.listen(model.onRefresh); // 1 - counter.listen(model.onDidRefresh); // 1 - counter.listen(model.onDidRefreshItem); // 3 - counter.listen(model.onRefreshItemChildren); // 1 - counter.listen(model.onDidRefreshItemChildren); // 1 - return model.refresh(SAMPLE.AB.children[0]); + return model.expand(SAMPLE.AB.children[0]).then(() => { + counter.listen(model.onRefresh); // 1 + counter.listen(model.onDidRefresh); // 1 + counter.listen(model.onDidRefreshItem); // 3 + counter.listen(model.onRefreshItemChildren); // 1 + counter.listen(model.onDidRefreshItemChildren); // 1 + return model.refresh(SAMPLE.AB.children[0]); + }); }).then(() => { assert.equal(counter.count, 7); }); @@ -269,17 +268,17 @@ suite('TreeModel', () => { test('refresh(element, false) refreshes the element', () => { return model.setInput(SAMPLE.AB).then(() => { - model.expand(SAMPLE.AB.children[0]); - - counter.listen(model.onRefresh); // 1 - counter.listen(model.onDidRefresh); // 1 - counter.listen(model.onDidRefreshItem, item => { // 1 - assert.equal(item.id, 'a'); - counter.up(); + return model.expand(SAMPLE.AB.children[0]).then(() => { + counter.listen(model.onRefresh); // 1 + counter.listen(model.onDidRefresh); // 1 + counter.listen(model.onDidRefreshItem, item => { // 1 + assert.equal(item.id, 'a'); + counter.up(); + }); + counter.listen(model.onRefreshItemChildren); // 1 + counter.listen(model.onDidRefreshItemChildren); // 1 + return model.refresh(SAMPLE.AB.children[0], false); }); - counter.listen(model.onRefreshItemChildren); // 1 - counter.listen(model.onDidRefreshItemChildren); // 1 - return model.refresh(SAMPLE.AB.children[0], false); }).then(() => { assert.equal(counter.count, 6); }); @@ -680,11 +679,11 @@ suite('TreeModel - Expansion', () => { getId: (_, e) => e, hasChildren: (_, e) => true, getChildren: (_, e) => { - if (e === 'root') { return WinJS.TPromise.wrap(['a', 'b', 'c']); } - if (e === 'b') { return WinJS.TPromise.wrap(['b1']); } - return WinJS.TPromise.as([]); + if (e === 'root') { return Promise.resolve(['a', 'b', 'c']); } + if (e === 'b') { return Promise.resolve(['b1']); } + return Promise.resolve([]); }, - getParent: (_, e): WinJS.Promise => { throw new Error('not implemented'); }, + getParent: (_, e): Thenable => { throw new Error('not implemented'); }, shouldAutoexpand: (_, e) => e === 'b' } }); @@ -1080,7 +1079,7 @@ suite('TreeModel - Traits', () => { class DynamicModel implements _.IDataSource { private data: any; - public promiseFactory: { (): WinJS.Promise; }; + public promiseFactory: { (): Thenable; }; private _onGetChildren = new Emitter(); readonly onGetChildren: Event = this._onGetChildren.event; @@ -1125,16 +1124,16 @@ class DynamicModel implements _.IDataSource { return !!this.data[element]; } - public getChildren(tree, element): WinJS.Promise { + public getChildren(tree, element): Thenable { this._onGetChildren.fire(element); - var result = this.promiseFactory ? this.promiseFactory() : WinJS.TPromise.as(null); + var result = this.promiseFactory ? this.promiseFactory() : Promise.resolve(null); return result.then(() => { this._onDidGetChildren.fire(element); - return WinJS.TPromise.as(this.data[element]); + return Promise.resolve(this.data[element]); }); } - public getParent(tree, element): WinJS.Promise { + public getParent(tree, element): Thenable { throw new Error('Not implemented'); } } @@ -1273,27 +1272,28 @@ suite('TreeModel - Dynamic data model', () => { dataModel.addChild('father', 'son'); return model.setInput('root').then(() => { - model.expand('grandfather'); - model.collapse('father'); - - var times = 0; - var listener = dataModel.onGetChildren((element) => { - times++; - assert.equal(element, 'grandfather'); - }); + return model.expand('grandfather').then(() => { + return model.collapse('father').then(() => { + var times = 0; + var listener = dataModel.onGetChildren((element) => { + times++; + assert.equal(element, 'grandfather'); + }); - return model.refresh('grandfather').then(() => { - assert.equal(times, 1); - listener.dispose(); + return model.refresh('grandfather').then(() => { + assert.equal(times, 1); + listener.dispose(); - listener = dataModel.onGetChildren((element) => { - times++; - assert.equal(element, 'father'); - }); + listener = dataModel.onGetChildren((element) => { + times++; + assert.equal(element, 'father'); + }); - return model.expand('father').then(() => { - assert.equal(times, 2); - listener.dispose(); + return model.expand('father').then(() => { + assert.equal(times, 2); + listener.dispose(); + }); + }); }); }); }); @@ -1306,49 +1306,51 @@ suite('TreeModel - Dynamic data model', () => { dataModel.addChild('mother', 'daughter'); return model.setInput('root').then(() => { - model.expand('father'); - model.expand('mother'); - - var nav = model.getNavigator(); - assert.equal(nav.next().id, 'father'); - assert.equal(nav.next().id, 'son'); - assert.equal(nav.next().id, 'mother'); - assert.equal(nav.next().id, 'daughter'); - assert.equal(nav.next() && false, null); + return model.expand('father').then(() => { + return model.expand('mother').then(() => { + + var nav = model.getNavigator(); + assert.equal(nav.next().id, 'father'); + assert.equal(nav.next().id, 'son'); + assert.equal(nav.next().id, 'mother'); + assert.equal(nav.next().id, 'daughter'); + assert.equal(nav.next() && false, null); - dataModel.removeChild('father', 'son'); - dataModel.removeChild('mother', 'daughter'); - dataModel.addChild('father', 'brother'); - dataModel.addChild('mother', 'sister'); + dataModel.removeChild('father', 'son'); + dataModel.removeChild('mother', 'daughter'); + dataModel.addChild('father', 'brother'); + dataModel.addChild('mother', 'sister'); - dataModel.promiseFactory = () => { return WinJS.TPromise.wrap(timeout(0)); }; + dataModel.promiseFactory = () => { return timeout(0); }; - var getTimes = 0; - var gotTimes = 0; - var getListener = dataModel.onGetChildren((element) => { getTimes++; }); - var gotListener = dataModel.onDidGetChildren((element) => { gotTimes++; }); + var getTimes = 0; + var gotTimes = 0; + var getListener = dataModel.onGetChildren((element) => { getTimes++; }); + var gotListener = dataModel.onDidGetChildren((element) => { gotTimes++; }); - var p1 = model.refresh('father'); - assert.equal(getTimes, 1); - assert.equal(gotTimes, 0); + var p1 = model.refresh('father'); + assert.equal(getTimes, 1); + assert.equal(gotTimes, 0); - var p2 = model.refresh('mother'); - assert.equal(getTimes, 2); - assert.equal(gotTimes, 0); + var p2 = model.refresh('mother'); + assert.equal(getTimes, 2); + assert.equal(gotTimes, 0); - return WinJS.Promise.join([p1, p2]).then(() => { - assert.equal(getTimes, 2); - assert.equal(gotTimes, 2); + return Promise.all([p1, p2]).then(() => { + assert.equal(getTimes, 2); + assert.equal(gotTimes, 2); - nav = model.getNavigator(); - assert.equal(nav.next().id, 'father'); - assert.equal(nav.next().id, 'brother'); - assert.equal(nav.next().id, 'mother'); - assert.equal(nav.next().id, 'sister'); - assert.equal(nav.next() && false, null); + nav = model.getNavigator(); + assert.equal(nav.next().id, 'father'); + assert.equal(nav.next().id, 'brother'); + assert.equal(nav.next().id, 'mother'); + assert.equal(nav.next().id, 'sister'); + assert.equal(nav.next() && false, null); - getListener.dispose(); - gotListener.dispose(); + getListener.dispose(); + gotListener.dispose(); + }); + }); }); }); }); @@ -1359,139 +1361,76 @@ suite('TreeModel - Dynamic data model', () => { dataModel.addChild('father', 'son'); return model.setInput('root').then(() => { - model.expand('grandfather'); - model.expand('father'); - - var nav = model.getNavigator(); - assert.equal(nav.next().id, 'grandfather'); - assert.equal(nav.next().id, 'father'); - assert.equal(nav.next().id, 'son'); - assert.equal(nav.next() && false, null); - - var refreshTimes = 0; - counter.listen(model.onDidRefreshItem, (e) => { refreshTimes++; }); - - var getTimes = 0; - var getListener = dataModel.onGetChildren((element) => { getTimes++; }); - - var gotTimes = 0; - var gotListener = dataModel.onDidGetChildren((element) => { gotTimes++; }); - - var p1Completes = []; - dataModel.promiseFactory = () => { return new WinJS.TPromise((c) => { p1Completes.push(c); }); }; - - model.refresh('grandfather'); - - // just a single get - assert.equal(refreshTimes, 1); // (+1) grandfather - assert.equal(getTimes, 1); - assert.equal(gotTimes, 0); - - // unblock the first get - p1Completes.shift()(); - - // once the first get is unblocked, the second get should appear - assert.equal(refreshTimes, 2); // (+1) first father refresh - assert.equal(getTimes, 2); - assert.equal(gotTimes, 1); - - var p2Complete; - dataModel.promiseFactory = () => { return new WinJS.TPromise((c) => { p2Complete = c; }); }; - var p2 = model.refresh('father'); - - // same situation still - assert.equal(refreshTimes, 3); // (+1) second father refresh - assert.equal(getTimes, 2); - assert.equal(gotTimes, 1); - - // unblock the second get - p1Completes.shift()(); - - // the third get should have appeared, it should've been waiting for the second one - assert.equal(refreshTimes, 4); // (+1) first son request - assert.equal(getTimes, 3); - assert.equal(gotTimes, 2); - - p2Complete(); - - // all good - assert.equal(refreshTimes, 5); // (+1) second son request - assert.equal(getTimes, 3); - assert.equal(gotTimes, 3); - - return p2.then(() => { - nav = model.getNavigator(); - assert.equal(nav.next().id, 'grandfather'); - assert.equal(nav.next().id, 'father'); - assert.equal(nav.next().id, 'son'); - assert.equal(nav.next() && false, null); - - getListener.dispose(); - gotListener.dispose(); - }); - }); - }); + return model.expand('grandfather').then(() => { + return model.expand('father').then(() => { + var nav = model.getNavigator(); + assert.equal(nav.next().id, 'grandfather'); + assert.equal(nav.next().id, 'father'); + assert.equal(nav.next().id, 'son'); + assert.equal(nav.next() && false, null); - test('simultaneously recursively refreshing two intersecting elements should concatenate the refreshes - ancestor second', () => { - dataModel.addChild('root', 'grandfather'); - dataModel.addChild('grandfather', 'father'); - dataModel.addChild('father', 'son'); + var refreshTimes = 0; + counter.listen(model.onDidRefreshItem, (e) => { refreshTimes++; }); - return model.setInput('root').then(() => { - model.expand('grandfather'); - model.expand('father'); + var getTimes = 0; + var getListener = dataModel.onGetChildren((element) => { getTimes++; }); - var nav = model.getNavigator(); - assert.equal(nav.next().id, 'grandfather'); - assert.equal(nav.next().id, 'father'); - assert.equal(nav.next().id, 'son'); - assert.equal(nav.next() && false, null); - - var getTimes = 0; - var gotTimes = 0; - var getListener = dataModel.onGetChildren((element) => { getTimes++; }); - var gotListener = dataModel.onDidGetChildren((element) => { gotTimes++; }); - var p2; + var gotTimes = 0; + var gotListener = dataModel.onDidGetChildren((element) => { gotTimes++; }); - var p1Complete; - dataModel.promiseFactory = () => { return new WinJS.TPromise((c) => { p1Complete = c; }); }; + var p1Completes = []; + dataModel.promiseFactory = () => { return new Promise((c) => { p1Completes.push(c); }); }; - model.refresh('father'); + model.refresh('grandfather').then(() => { + // just a single get + assert.equal(refreshTimes, 1); // (+1) grandfather + assert.equal(getTimes, 1); + assert.equal(gotTimes, 0); - assert.equal(getTimes, 1); - assert.equal(gotTimes, 0); + // unblock the first get + p1Completes.shift()(); - var p2Completes = []; - dataModel.promiseFactory = () => { return new WinJS.TPromise((c) => { p2Completes.push(c); }); }; - p2 = model.refresh('grandfather'); + // once the first get is unblocked, the second get should appear + assert.equal(refreshTimes, 2); // (+1) first father refresh + assert.equal(getTimes, 2); + assert.equal(gotTimes, 1); - assert.equal(getTimes, 1); - assert.equal(gotTimes, 0); + var p2Complete; + dataModel.promiseFactory = () => { return new Promise((c) => { p2Complete = c; }); }; + var p2 = model.refresh('father'); - p1Complete(); + // same situation still + assert.equal(refreshTimes, 3); // (+1) second father refresh + assert.equal(getTimes, 2); + assert.equal(gotTimes, 1); - assert.equal(getTimes, 2); - assert.equal(gotTimes, 1); + // unblock the second get + p1Completes.shift()(); - p2Completes.shift()(); + // the third get should have appeared, it should've been waiting for the second one + assert.equal(refreshTimes, 4); // (+1) first son request + assert.equal(getTimes, 3); + assert.equal(gotTimes, 2); - assert.equal(getTimes, 3); - assert.equal(gotTimes, 2); + p2Complete(); - p2Completes.shift()(); + // all good + assert.equal(refreshTimes, 5); // (+1) second son request + assert.equal(getTimes, 3); + assert.equal(gotTimes, 3); - assert.equal(getTimes, 3); - assert.equal(gotTimes, 3); + return p2.then(() => { + nav = model.getNavigator(); + assert.equal(nav.next().id, 'grandfather'); + assert.equal(nav.next().id, 'father'); + assert.equal(nav.next().id, 'son'); + assert.equal(nav.next() && false, null); - return p2.then(() => { - nav = model.getNavigator(); - assert.equal(nav.next().id, 'grandfather'); - assert.equal(nav.next().id, 'father'); - assert.equal(nav.next().id, 'son'); - assert.equal(nav.next() && false, null); - - getListener.dispose(); - gotListener.dispose(); + getListener.dispose(); + gotListener.dispose(); + }); + }); + }); }); }); }); @@ -1501,15 +1440,16 @@ suite('TreeModel - Dynamic data model', () => { dataModel.addChild('grandfather', 'father'); return model.setInput('root').then(() => { - model.expand('grandfather'); - model.expand('father'); - - assert(!model.isExpanded('father')); + return model.expand('grandfather').then(() => { + return model.expand('father').then(() => { + assert(!model.isExpanded('father')); - dataModel.addChild('father', 'son'); + dataModel.addChild('father', 'son'); - return model.refresh('father').then(() => { - assert(!model.isExpanded('father')); + return model.refresh('father').then(() => { + assert(!model.isExpanded('father')); + }); + }); }); }); }); @@ -1520,16 +1460,18 @@ suite('TreeModel - Dynamic data model', () => { dataModel.addChild('father', 'son'); return model.setInput('root').then(() => { - model.expand('grandfather'); - model.expand('father'); - model.collapse('father'); - - assert(!model.isExpanded('father')); + return model.expand('grandfather').then(() => { + return model.expand('father').then(() => { + return model.collapse('father').then(() => { + assert(!model.isExpanded('father')); - dataModel.addChild('father', 'daughter'); + dataModel.addChild('father', 'daughter'); - return model.refresh('father').then(() => { - assert(!model.isExpanded('father')); + return model.refresh('father').then(() => { + assert(!model.isExpanded('father')); + }); + }); + }); }); }); }); @@ -1540,15 +1482,16 @@ suite('TreeModel - Dynamic data model', () => { dataModel.addChild('father', 'son'); return model.setInput('root').then(() => { - model.expand('grandfather'); - model.expand('father'); - - assert(model.isExpanded('grandfather')); - assert(model.isExpanded('father')); + return model.expand('grandfather').then(() => { + return model.expand('father').then(() => { + assert(model.isExpanded('grandfather')); + assert(model.isExpanded('father')); - return model.refresh('grandfather').then(() => { - assert(model.isExpanded('grandfather')); - assert(model.isExpanded('father')); + return model.refresh('grandfather').then(() => { + assert(model.isExpanded('grandfather')); + assert(model.isExpanded('father')); + }); + }); }); }); }); @@ -1559,16 +1502,18 @@ suite('TreeModel - Dynamic data model', () => { dataModel.addChild('father', 'son'); return model.setInput('root').then(() => { - model.expand('grandfather'); - model.expand('father'); - model.collapse('father'); - - assert(model.isExpanded('grandfather')); - assert(!model.isExpanded('father')); + return model.expand('grandfather').then(() => { + return model.expand('father').then(() => { + return model.collapse('father').then(() => { + assert(model.isExpanded('grandfather')); + assert(!model.isExpanded('father')); - return model.refresh('grandfather').then(() => { - assert(model.isExpanded('grandfather')); - assert(!model.isExpanded('father')); + return model.refresh('grandfather').then(() => { + assert(model.isExpanded('grandfather')); + assert(!model.isExpanded('father')); + }); + }); + }); }); }); }); @@ -1582,9 +1527,9 @@ suite('TreeModel - Dynamic data model', () => { return model.setInput('root').then(() => { // delay expansions and refreshes - dataModel.promiseFactory = () => { return WinJS.TPromise.wrap(timeout(0)); }; + dataModel.promiseFactory = () => { return timeout(0); }; - var promises: WinJS.Promise[] = []; + var promises: Thenable[] = []; promises.push(model.expand('father')); dataModel.removeChild('root', 'father'); @@ -1594,7 +1539,7 @@ suite('TreeModel - Dynamic data model', () => { dataModel.removeChild('root', 'mother'); promises.push(model.refresh('root')); - return WinJS.Promise.join(promises).then(() => { + return Promise.all(promises).then(() => { assert(true, 'all good'); }, (errs) => { assert(false, 'should not fail'); @@ -1626,18 +1571,18 @@ suite('TreeModel - bugs', () => { getChildren: (_, e) => { if (e === 'root') { return getRootChildren(); } if (e === 'bart') { return getBartChildren(); } - return WinJS.TPromise.as([]); + return Promise.resolve([]); }, - getParent: (_, e): WinJS.Promise => { throw new Error('not implemented'); }, + getParent: (_, e): Thenable => { throw new Error('not implemented'); }, } }); let listeners = []; // helpers - var getGetRootChildren = (children: string[], millis = 0) => () => WinJS.TPromise.wrap(timeout(millis)).then(() => children); + var getGetRootChildren = (children: string[], millis = 0) => () => timeout(millis).then(() => children); var getRootChildren = getGetRootChildren(['homer', 'bart', 'lisa', 'marge', 'maggie'], 0); - var getGetBartChildren = (millis = 0) => () => WinJS.TPromise.wrap(timeout(millis)).then(() => ['milhouse', 'nelson']); + var getGetBartChildren = (millis = 0) => () => timeout(millis).then(() => ['milhouse', 'nelson']); var getBartChildren = getGetBartChildren(0); // item expanding should not exist! @@ -1664,7 +1609,7 @@ suite('TreeModel - bugs', () => { }); // what now? - return WinJS.Promise.join([p1, p2]); + return Promise.all([p1, p2]); }).then(() => { -- GitLab