diff --git a/scripts/gulp/tasks/test.ts b/scripts/gulp/tasks/test.ts
index bba7e5789a..e6c3572763 100644
--- a/scripts/gulp/tasks/test.ts
+++ b/scripts/gulp/tasks/test.ts
@@ -85,6 +85,7 @@ function karmaTest(watch: boolean, done: Function) {
let karmaConfig = {
configFile: join(SCRIPTS_ROOT, 'karma/karma.conf.js'),
+ singleRun: true,
};
if (watch) {
@@ -96,6 +97,9 @@ function karmaTest(watch: boolean, done: Function) {
args: ['--grep', argv.testGrep]
};
}
+ if (typeof argv.debug !== 'undefined') {
+ karmaConfig.singleRun = false;
+ }
new karma.Server(karmaConfig, done).start();
}
diff --git a/scripts/karma/system.config.js b/scripts/karma/system.config.js
index 5801d5cd51..c156fddd1d 100644
--- a/scripts/karma/system.config.js
+++ b/scripts/karma/system.config.js
@@ -4,7 +4,7 @@ jasmine.DEFAULT_TIMEOUT_INTERVAL = 1000;
// disable console debugs/errors/warns from printing out
console.debug = () => {};
-console.error = () => {};
+// console.error = () => {};
console.warn = () => {};
__karma__.loaded = function () {};
diff --git a/src/animations/animation.ts b/src/animations/animation.ts
index 244fb3656c..b04397cd21 100644
--- a/src/animations/animation.ts
+++ b/src/animations/animation.ts
@@ -103,6 +103,13 @@ export class Animation {
return 0;
}
+ /**
+ * Returns if the animation is a root one.
+ */
+ isRoot(): boolean {
+ return !this.parent;
+ }
+
/**
* Set the duration for this animation.
*/
diff --git a/src/components/app/test/app.spec.ts b/src/components/app/test/app.spec.ts
index 143790cd26..8344df8071 100644
--- a/src/components/app/test/app.spec.ts
+++ b/src/components/app/test/app.spec.ts
@@ -167,8 +167,9 @@ describe('App', () => {
expect(plt.exitApp).not.toHaveBeenCalled();
done();
}).catch((err: Error) => {
+ fail(err);
done(err);
- });
+ });
});
it('should pop the second view in the root nav', () => {
diff --git a/src/components/nav/test/basic/pages/first-page/first-page.html b/src/components/nav/test/basic/pages/first-page/first-page.html
index 52ace40630..ff751b61e2 100644
--- a/src/components/nav/test/basic/pages/first-page/first-page.html
+++ b/src/components/nav/test/basic/pages/first-page/first-page.html
@@ -42,7 +42,7 @@
Toggle Can Leave
-
+
diff --git a/src/components/nav/test/nav.spec.ts b/src/components/nav/test/nav.spec.ts
index de2c9ce51e..109aa98e19 100644
--- a/src/components/nav/test/nav.spec.ts
+++ b/src/components/nav/test/nav.spec.ts
@@ -34,6 +34,7 @@ describe('Nav', () => {
expect(nav.setPages).toHaveBeenCalledWith(knownViews, null, null);
done();
}).catch((err: Error) => {
+ fail(err);
done(err);
});
});
@@ -56,6 +57,7 @@ describe('Nav', () => {
expect(nav.setPages).toHaveBeenCalledWith(knownViews, null, null);
done();
}).catch((err: Error) => {
+ fail(err);
done(err);
});
});
@@ -72,7 +74,8 @@ describe('Nav', () => {
promise.then(() => {
expect(nav.push).toHaveBeenCalled();
done();
- }).catch((err: Error) => {
+ }).catch((err: Error) => {
+ fail(err);
done(err);
});
});
diff --git a/src/components/tabs/tab.ts b/src/components/tabs/tab.ts
index 9f81934581..a2e93136a0 100644
--- a/src/components/tabs/tab.ts
+++ b/src/components/tabs/tab.ts
@@ -292,7 +292,7 @@ export class Tab extends NavControllerBase {
/**
* @hidden
*/
- load(opts: NavOptions, done?: Function) {
+ load(opts: NavOptions, done?: () => void) {
if (!this._loaded && this.root) {
this.setElementClass('show-tab', true);
this.push(this.root, this.rootParams, opts, done);
@@ -305,7 +305,7 @@ export class Tab extends NavControllerBase {
this._dom.read(() => {
this.resize();
});
- done(true);
+ done();
}
}
diff --git a/src/components/tabs/test/tabs.spec.ts b/src/components/tabs/test/tabs.spec.ts
index 426c402f50..a26adbce4a 100644
--- a/src/components/tabs/test/tabs.spec.ts
+++ b/src/components/tabs/test/tabs.spec.ts
@@ -162,7 +162,6 @@ describe('Tabs', () => {
it('should get the tab', () => {
var tabs = mockTabs();
var tab0 = mockTab(tabs);
- tab0.setRoot({});
var tab1 = mockTab(tabs);
expect(tabs.getIndex(tab0)).toEqual(0);
diff --git a/src/navigation/nav-controller-base.ts b/src/navigation/nav-controller-base.ts
index ee324bd912..25057eead9 100644
--- a/src/navigation/nav-controller-base.ts
+++ b/src/navigation/nav-controller-base.ts
@@ -3,8 +3,8 @@ import { ComponentRef, Input, ComponentFactoryResolver, ElementRef, EventEmitter
import { AnimationOptions } from '../animations/animation';
import { App } from '../components/app/app';
import { Config } from '../config/config';
-import { convertToView, convertToViews, NavOptions, DIRECTION_BACK, DIRECTION_FORWARD, INIT_ZINDEX,
- TransitionResolveFn, TransitionInstruction, STATE_NEW, STATE_INITIALIZED, STATE_ATTACHED, STATE_DESTROYED } from './nav-util';
+import { convertToViews, NavOptions, NavResult, DIRECTION_BACK, DIRECTION_FORWARD, INIT_ZINDEX,
+ TransitionInstruction, STATE_NEW, STATE_INITIALIZED, STATE_ATTACHED, STATE_DESTROYED } from './nav-util';
import { setZIndex } from './nav-util';
import { DeepLinker } from './deep-linker';
import { DomController } from '../platform/dom-controller';
@@ -80,40 +80,31 @@ export class NavControllerBase extends Ion implements NavController {
this.id = 'n' + (++ctrlIds);
}
- push(page: any, params?: any, opts?: NavOptions, done?: Function): Promise {
- return convertToView(this._linker, page, params).then(viewController => {
- return this._queueTrns({
- insertStart: -1,
- insertViews: [viewController],
- opts: opts,
- }, done);
- }).catch((err: Error) => {
- console.error('Failed to navigate: ', err.message);
- throw err;
- });
+ push(page: any, params?: any, opts?: NavOptions, done?: () => void): Promise {
+ return this._queueTrns({
+ insertStart: -1,
+ insertViews: [{ page: page, params: params }],
+ opts: opts,
+ }, done);
}
- insert(insertIndex: number, page: any, params?: any, opts?: NavOptions, done?: Function): Promise {
- return convertToView(this._linker, page, params).then(viewController => {
- return this._queueTrns({
- insertStart: insertIndex,
- insertViews: [viewController],
- opts: opts,
- }, done);
- });
+ insert(insertIndex: number, page: any, params?: any, opts?: NavOptions, done?: () => void): Promise {
+ return this._queueTrns({
+ insertStart: insertIndex,
+ insertViews: [{ page: page, params: params }],
+ opts: opts,
+ }, done);
}
- insertPages(insertIndex: number, insertPages: any[], opts?: NavOptions, done?: Function): Promise {
- return convertToViews(this._linker, insertPages).then(viewControllers => {
- return this._queueTrns({
- insertStart: insertIndex,
- insertViews: viewControllers,
- opts: opts,
- }, done);
- });
+ insertPages(insertIndex: number, insertPages: any[], opts?: NavOptions, done?: () => void): Promise {
+ return this._queueTrns({
+ insertStart: insertIndex,
+ insertViews: insertPages,
+ opts: opts,
+ }, done);
}
- pop(opts?: NavOptions, done?: Function): Promise {
+ pop(opts?: NavOptions, done?: () => void): Promise {
return this._queueTrns({
removeStart: -1,
removeCount: 1,
@@ -121,7 +112,7 @@ export class NavControllerBase extends Ion implements NavController {
}, done);
}
- popTo(indexOrViewCtrl: any, opts?: NavOptions, done?: Function): Promise {
+ popTo(indexOrViewCtrl: any, opts?: NavOptions, done?: () => void): Promise {
let config: TransitionInstruction = {
removeStart: -1,
removeCount: -1,
@@ -136,7 +127,7 @@ export class NavControllerBase extends Ion implements NavController {
return this._queueTrns(config, done);
}
- popToRoot(opts?: NavOptions, done?: Function): Promise {
+ popToRoot(opts?: NavOptions, done?: () => void): Promise {
return this._queueTrns({
removeStart: 1,
removeCount: -1,
@@ -152,7 +143,7 @@ export class NavControllerBase extends Ion implements NavController {
return Promise.all(promises);
}
- remove(startIndex: number, removeCount: number = 1, opts?: NavOptions, done?: Function): Promise {
+ remove(startIndex: number, removeCount: number = 1, opts?: NavOptions, done?: () => void): Promise {
return this._queueTrns({
removeStart: startIndex,
removeCount: removeCount,
@@ -160,7 +151,7 @@ export class NavControllerBase extends Ion implements NavController {
}, done);
}
- removeView(viewController: ViewController, opts?: NavOptions, done?: Function): Promise {
+ removeView(viewController: ViewController, opts?: NavOptions, done?: () => void): Promise {
return this._queueTrns({
removeView: viewController,
removeStart: 0,
@@ -169,19 +160,12 @@ export class NavControllerBase extends Ion implements NavController {
}, done);
}
- setRoot(pageOrViewCtrl: any, params?: any, opts?: NavOptions, done?: Function): Promise {
- return convertToView(this._linker, pageOrViewCtrl, params).then((viewController) => {
- return this._setPages([viewController], opts, done);
- });
+ setRoot(pageOrViewCtrl: any, params?: any, opts?: NavOptions, done?: () => void): Promise {
+ return this.setPages([{ page: pageOrViewCtrl, params: params }], opts, done);
}
- setPages(pages: any[], opts?: NavOptions, done?: Function): Promise {
- return convertToViews(this._linker, pages).then(viewControllers => {
- return this._setPages(viewControllers, opts, done);
- });
- }
- _setPages(viewControllers: ViewController[], opts?: NavOptions, done?: Function): Promise {
+ setPages(viewControllers: any[], opts?: NavOptions, done?: () => void): Promise {
if (isBlank(opts)) {
opts = {};
}
@@ -208,81 +192,68 @@ export class NavControllerBase extends Ion implements NavController {
// 7. _transitionStart(): called once the transition actually starts, it initializes the Animation underneath.
// 8. _transitionFinish(): called once the transition finishes
// 9. _cleanup(): syncs the navigation internal state with the DOM. For example it removes the pages from the DOM or hides/show them.
- _queueTrns(ti: TransitionInstruction, done: Function): Promise {
- let promise: Promise;
- let resolve: Function = done;
- let reject: Function = done;
+ _queueTrns(ti: TransitionInstruction, done: () => void): Promise {
+ const promise = new Promise((resolve, reject) => {
+ ti.resolve = resolve;
+ ti.reject = reject;
+ });
+ ti.done = done;
- if (done === undefined) {
- // only create a promise if a done callback wasn't provided
- // done can be a null, which avoids any functions
- promise = new Promise((res, rej) => {
- resolve = res;
- reject = rej;
- });
- }
-
- // ti.resolve() is called when the navigation transition is finished successfully
- ti.resolve = (hasCompleted: boolean, isAsync: boolean, enteringName: string, leavingName: string, direction: string) => {
- this._trnsId = null;
- this._init = true;
- resolve && resolve(hasCompleted, isAsync, enteringName, leavingName, direction);
-
- // let's see if there's another to kick off
- this.setTransitioning(false);
- this._swipeBackCheck();
- this._nextTrns();
- };
-
- // ti.reject() is called when the navigation transition fails. ie. it is rejected at some point.
- ti.reject = (rejectReason: any, transition: Transition) => {
- this._trnsId = null;
- this._queue.length = 0;
-
- // walk through the transition views so they are destroyed
- while (transition) {
- var enteringView = transition.enteringView;
- if (enteringView && (enteringView._state === STATE_ATTACHED)) {
- this._destroyView(enteringView);
- }
- if (transition.isRoot()) {
- this._trnsCtrl.destroy(transition.trnsId);
- break;
- }
- transition = transition.parent;
- }
-
- reject && reject(false, false, rejectReason);
-
- // let's see if there's another to kick off
- this.setTransitioning(false);
- this._swipeBackCheck();
- this._nextTrns();
- };
-
- if (ti.insertViews) {
- // ensure we've got good views to insert
- ti.insertViews = ti.insertViews.filter(v => v !== null);
- if (ti.insertViews.length === 0) {
- ti.reject('invalid views to insert');
- return promise;
- }
-
- } else if (isPresent(ti.removeStart) && this._views.length === 0 && !this._isPortal) {
- ti.reject('no views in the stack to be removed');
- return promise;
+ // Normalize empty
+ if (ti.insertViews && ti.insertViews.length === 0) {
+ ti.insertViews = undefined;
}
+ // Enqueue transition instruction
this._queue.push(ti);
// if there isn't a transition already happening
// then this will kick off this transition
this._nextTrns();
- // promise is undefined if a done callbacks was provided
return promise;
}
+ _success(result: NavResult, ti: TransitionInstruction) {
+ this._init = true;
+ this._trnsId = null;
+
+ // let's see if there's another to kick off
+ this.setTransitioning(false);
+ this._swipeBackCheck();
+ this._nextTrns();
+
+ if (ti.done) {
+ ti.done(
+ result.hasCompleted,
+ result.requiresTransition,
+ result.enteringName,
+ result.leavingName,
+ result.direction
+ );
+ }
+ ti.resolve(result.hasCompleted);
+ }
+
+ _failed(rejectReason: any, ti: TransitionInstruction) {
+ this._trnsId = null;
+ this._queue.length = 0;
+
+ // let's see if there's another to kick off
+ this.setTransitioning(false);
+ this._swipeBackCheck();
+ this._nextTrns();
+
+ if (ti.done) {
+ ti.done(false, false, rejectReason);
+ }
+ if (ti.reject) {
+ ti.reject(rejectReason);
+ } else {
+ ti.resolve(false);
+ }
+ }
+
_nextTrns(): boolean {
// this is the framework's bread 'n butta function
// only one transition is allowed at any given time
@@ -292,68 +263,53 @@ export class NavControllerBase extends Ion implements NavController {
// there is no transition happening right now
// get the next instruction
- const ti = this._nextTI();
+ const ti = this._queue.shift();
if (!ti) {
return false;
}
- // ensure any of the inserted view are used
- const insertViews = ti.insertViews;
- if (insertViews) {
- for (var i = 0; i < insertViews.length; i++) {
- var nav = insertViews[i]._nav;
- if (nav && nav !== this || insertViews[i]._state === STATE_DESTROYED) {
- ti.reject('leavingView and enteringView are null. stack is already empty');
- return false;
- }
- }
- }
-
- // get entering and leaving views
- const leavingView = this.getActive();
- const enteringView = this._getEnteringView(ti, leavingView);
-
- if (!leavingView && !enteringView) {
- ti.reject('leavingView and enteringView are null. stack is already empty');
- return false;
- }
-
// set that this nav is actively transitioning
- this.setTransitioning(true);
+ let enteringView: ViewController;
+ let leavingView: ViewController;
- // Initialize enteringView
- if (enteringView && enteringView._state === STATE_NEW) {
- // render the entering view, and all child navs and views
- // ******** DOM WRITE ****************
- this._viewInit(enteringView);
- }
+ this._startTI(ti)
+ .then(() => this._loadLazyLoading(ti))
+ .then(() => {
+ leavingView = this.getActive();
+ enteringView = this._getEnteringView(ti, leavingView);
- // Only test canLeave/canEnter if there is transition
- const requiresTransition = ti.requiresTransition = (ti.enteringRequiresTransition || ti.leavingRequiresTransition) && enteringView !== leavingView;
- if (requiresTransition) {
- // views have been initialized, now let's test
- // to see if the transition is even allowed or not
- return this._viewTest(enteringView, leavingView, ti);
- } else {
- return this._postViewInit(enteringView, leavingView, ti);
- }
+ if (!leavingView && !enteringView) {
+ throw 'no views in the stack to be removed';
+ }
+
+ if (enteringView && enteringView._state === STATE_NEW) {
+ this._viewInit(enteringView);
+ }
+
+ // Needs transition?
+ ti.requiresTransition = (ti.enteringRequiresTransition || ti.leavingRequiresTransition) && enteringView !== leavingView;
+ })
+ .then(() => this._viewTest(enteringView, leavingView, ti))
+ .then(() => this._postViewInit(enteringView, leavingView, ti))
+ .then(() => this._transition(enteringView, leavingView, ti))
+ .then((result) => this._success(result, ti))
+ .catch((rejectReason) => this._failed(rejectReason, ti));
+
+ return true;
}
- _nextTI(): TransitionInstruction {
- const ti = this._queue.shift();
- if (!ti) {
- return null;
- }
+ _startTI(ti: TransitionInstruction): Promise {
const viewsLength = this._views.length;
if (isPresent(ti.removeView)) {
assert(isPresent(ti.removeStart), 'removeView needs removeStart');
assert(isPresent(ti.removeCount), 'removeView needs removeCount');
- var index = this._views.indexOf(ti.removeView);
- if (index >= 0) {
- ti.removeStart += index;
+ const index = this.indexOf(ti.removeView);
+ if (index < 0) {
+ return Promise.reject('removeView was not found');
}
+ ti.removeStart += index;
}
if (isPresent(ti.removeStart)) {
if (ti.removeStart < 0) {
@@ -373,7 +329,35 @@ export class NavControllerBase extends Ion implements NavController {
}
ti.enteringRequiresTransition = (ti.insertStart === viewsLength);
}
- return ti;
+ this.setTransitioning(true);
+ return Promise.resolve();
+ }
+
+ _loadLazyLoading(ti: TransitionInstruction): Promise {
+ const insertViews = ti.insertViews;
+ if (insertViews) {
+ assert(insertViews.length > 0, 'length can not be zero');
+ return convertToViews(this._linker, insertViews).then((viewControllers) => {
+ assert(insertViews.length === viewControllers.length, 'lengths does not match');
+
+ // Check all the inserted view are correct
+ for (var i = 0; i < viewControllers.length; i++) {
+ var view = viewControllers[i];
+ if (!view) {
+ throw 'invalid views to insert';
+ }
+ var nav = view._nav;
+ if (nav && nav !== this) {
+ throw 'inserted view was already inserted';
+ }
+ if (viewControllers[i]._state === STATE_DESTROYED) {
+ throw 'inserted view was already destroyed';
+ }
+ }
+ ti.insertViews = viewControllers;
+ });
+ }
+ return Promise.resolve();
}
_getEnteringView(ti: TransitionInstruction, leavingView: ViewController): ViewController {
@@ -435,10 +419,10 @@ export class NavControllerBase extends Ion implements NavController {
console.warn(`You can't remove all the pages in the navigation stack. nav.pop() is probably called too many times.`,
this, this.getNativeElement());
- ti.reject('navigation stack needs at least one root page');
- return false;
+ throw 'navigation stack needs at least one root page';
}
+ // At this point the transition can not be rejected, any throw should be an error
// there are views to insert
if (insertViews) {
// manually set the new view's id if an id was passed in the options
@@ -479,27 +463,15 @@ export class NavControllerBase extends Ion implements NavController {
}
}
- if (!ti.requiresTransition) {
- // transition is not required, so we are already done!
- // they're inserting/removing the views somewhere in the middle or
- // beginning, so visually nothing needs to animate/transition
- // resolve immediately because there's no animation that's happening
- ti.resolve(true, false);
- return true;
- }
-
// set which animation it should use if it wasn't set yet
- if (!opts.animation) {
+ if (ti.requiresTransition && !opts.animation) {
if (isPresent(ti.removeStart)) {
opts.animation = (leavingView || enteringView).getTransitionName(opts.direction);
} else {
opts.animation = (enteringView || leavingView).getTransitionName(opts.direction);
}
}
-
- // huzzah! let us transition these views
- this._transitionInit(enteringView, leavingView, opts, ti.resolve);
- return true;
+ ti.opts = opts;
}
/**
@@ -509,6 +481,7 @@ export class NavControllerBase extends Ion implements NavController {
assert(enteringView, 'enteringView must be non null');
assert(enteringView._state === STATE_NEW, 'enteringView state must be NEW');
+ // render the entering view, and all child navs and views
// entering view has not been initialized yet
const componentProviders = ReflectiveInjector.resolve([
{ provide: NavController, useValue: this },
@@ -551,52 +524,52 @@ export class NavControllerBase extends Ion implements NavController {
this._zone.run(this._didLoad.bind(this, view));
}
- _viewTest(enteringView: ViewController, leavingView: ViewController, ti: TransitionInstruction): boolean {
+ _viewTest(enteringView: ViewController, leavingView: ViewController, ti: TransitionInstruction): Promise {
+ // Only test canLeave/canEnter if there is transition
+ if (!ti.requiresTransition) {
+ return Promise.resolve();
+ }
+
const promises: Promise[] = [];
if (leavingView) {
- var leavingTestResult = leavingView._lifecycleTest('Leave');
-
- if (leavingTestResult === false) {
- // synchronous reject
- ti.reject((leavingTestResult !== false ? leavingTestResult : `ionViewCanLeave rejected`));
- return false;
- } else if (leavingTestResult instanceof Promise) {
- // async promise
- promises.push(leavingTestResult);
- }
+ promises.push(leavingView._lifecycleTest('Leave'));
}
-
if (enteringView) {
- var enteringTestResult = enteringView._lifecycleTest('Enter');
+ promises.push(enteringView._lifecycleTest('Enter'));
+ }
- if (enteringTestResult === false) {
- // synchronous reject
- ti.reject((enteringTestResult !== false ? enteringTestResult : `ionViewCanEnter rejected`));
- return false;
- } else if (enteringTestResult instanceof Promise) {
- // async promise
- promises.push(enteringTestResult);
+ if (promises.length === 0) {
+ return Promise.resolve();
+ }
+
+ // darn, async promises, gotta wait for them to resolve
+ return Promise.all(promises).then((values: any[]) => {
+ if (values.some(result => result === false)) {
+ throw 'canEnter/Leave returned false';
}
- }
-
- if (promises.length) {
- // darn, async promises, gotta wait for them to resolve
- Promise.all(promises).then((values: any[]) => {
- if (values.some(result => result === false)) {
- ti.reject(`ionViewCanEnter rejected`);
- } else {
- this._postViewInit(enteringView, leavingView, ti);
- }
- }).catch(ti.reject);
- return true;
- } else {
- // synchronous and all tests passed! let's move on already
- return this._postViewInit(enteringView, leavingView, ti);
- }
+ }).catch((reason) => {
+ // Do not
+ ti.reject = null;
+ throw reason;
+ });
}
- _transitionInit(enteringView: ViewController, leavingView: ViewController, opts: NavOptions, resolve: TransitionResolveFn) {
+ _transition(enteringView: ViewController, leavingView: ViewController, ti: TransitionInstruction): Promise {
+
+ if (!ti.requiresTransition) {
+ // transition is not required, so we are already done!
+ // they're inserting/removing the views somewhere in the middle or
+ // beginning, so visually nothing needs to animate/transition
+ // resolve immediately because there's no animation that's happening
+ return Promise.resolve({
+ hasCompleted: true,
+ requiresTransition: false
+ });
+ }
+
+ const opts = ti.opts;
+
// figure out if this transition is the root one or a
// child of a parent nav that has the root transition
this._trnsId = this._trnsCtrl.getRootTrnsId(this);
@@ -630,11 +603,8 @@ export class NavControllerBase extends Ion implements NavController {
}
// transition start has to be registered before attaching the view to the DOM!
- transition.registerStart(() => {
- this._transitionStart(transition, enteringView, leavingView, opts, resolve);
- if (transition.parent) {
- transition.parent.start();
- }
+ const promise = new Promise(resolve => transition.registerStart(resolve)).then(() => {
+ return this._transitionStart(transition, enteringView, leavingView, opts);
});
if (enteringView && (enteringView._state === STATE_INITIALIZED)) {
@@ -645,13 +615,15 @@ export class NavControllerBase extends Ion implements NavController {
this._viewAttachToDOM(enteringView, enteringView._cmp, this._viewport);
}
+
if (!transition.hasChildren) {
// lowest level transition, so kick it off and let it bubble up to start all of them
transition.start();
}
+ return promise;
}
- _transitionStart(transition: Transition, enteringView: ViewController, leavingView: ViewController, opts: NavOptions, resolve: TransitionResolveFn) {
+ _transitionStart(transition: Transition, enteringView: ViewController, leavingView: ViewController, opts: NavOptions): Promise {
assert(this.isTransitioning(), 'isTransitioning() has to be true');
this._trnsId = null;
@@ -689,15 +661,14 @@ export class NavControllerBase extends Ion implements NavController {
// that will fire off the willEnter/Leave lifecycle events at the right time
transition.beforeAddRead(this._viewsWillLifecycles.bind(this, enteringView, leavingView));
- // create a callback for when the animation is done
- transition.onFinish(() => {
- // transition animation has ended
- this._zone.run(this._transitionFinish.bind(this, transition, opts, resolve));
- });
-
// get the set duration of this transition
const duration = transition.getDuration();
+ // create a callback for when the animation is done
+ const promise = new Promise(resolve => {
+ transition.onFinish(resolve);
+ });
+
if (transition.isRoot()) {
// this is the top most, or only active transition, so disable the app
// add XXms to the duration the app is disabled when the keyboard is open
@@ -723,9 +694,14 @@ export class NavControllerBase extends Ion implements NavController {
transition.play();
}
}
+
+ return promise.then(() => this._zone.run(() => {
+ return this._transitionFinish(transition, opts);
+ }));
}
- _transitionFinish(transition: Transition, opts: NavOptions, resolve: TransitionResolveFn) {
+ _transitionFinish(transition: Transition, opts: NavOptions): NavResult {
+
const hasCompleted = transition.hasCompleted;
const enteringView = transition.enteringView;
const leavingView = transition.leavingView;
@@ -774,8 +750,13 @@ export class NavControllerBase extends Ion implements NavController {
}
}
- // congrats, we did it!
- resolve(hasCompleted, true, enteringName, leavingName, opts.direction);
+ return {
+ hasCompleted: hasCompleted,
+ requiresTransition: true,
+ enteringName: enteringName,
+ leavingName: leavingName,
+ direction: opts.direction
+ };
}
_viewsWillLifecycles(enteringView: ViewController, leavingView: ViewController) {
diff --git a/src/navigation/nav-util.ts b/src/navigation/nav-util.ts
index 388c874f06..58fa528a48 100644
--- a/src/navigation/nav-util.ts
+++ b/src/navigation/nav-util.ts
@@ -8,7 +8,7 @@ import { NavControllerBase } from './nav-controller-base';
import { Transition } from '../transitions/transition';
-export function getComponent(linker: DeepLinker, nameOrPageOrView: any, params?: any) {
+export function getComponent(linker: DeepLinker, nameOrPageOrView: any, params?: any): Promise {
if (typeof nameOrPageOrView === 'function') {
return Promise.resolve(
new ViewController(nameOrPageOrView, params)
@@ -24,7 +24,7 @@ export function getComponent(linker: DeepLinker, nameOrPageOrView: any, params?:
return Promise.resolve(null);
}
-export function convertToView(linker: DeepLinker, nameOrPageOrView: any, params: any) {
+export function convertToView(linker: DeepLinker, nameOrPageOrView: any, params: any): Promise {
if (nameOrPageOrView) {
if (isViewController(nameOrPageOrView)) {
// is already a ViewController
@@ -34,11 +34,10 @@ export function convertToView(linker: DeepLinker, nameOrPageOrView: any, params:
return getComponent(linker, nameOrPageOrView, params);
}
- console.error(`invalid page component: ${nameOrPageOrView}`);
return Promise.resolve(null);
}
-export function convertToViews(linker: DeepLinker, pages: any[]) {
+export function convertToViews(linker: DeepLinker, pages: any[]): Promise {
const views: Promise[] = [];
if (isArray(pages)) {
for (var i = 0; i < pages.length; i++) {
@@ -147,6 +146,14 @@ export interface NavLink {
defaultHistory?: any[];
}
+export interface NavResult {
+ hasCompleted: boolean;
+ requiresTransition: boolean;
+ enteringName?: string;
+ leavingName?: string;
+ direction?: string;
+}
+
export interface NavSegment {
id: string;
name: string;
@@ -188,12 +195,13 @@ export interface TransitionRejectFn {
export interface TransitionInstruction {
opts: NavOptions;
insertStart?: number;
- insertViews?: ViewController[];
+ insertViews?: any[];
removeView?: ViewController;
removeStart?: number;
removeCount?: number;
- resolve?: TransitionResolveFn;
- reject?: TransitionRejectFn;
+ resolve?: (hasCompleted: boolean) => void;
+ reject?: (rejectReason: string) => void;
+ done?: Function;
leavingRequiresTransition?: boolean;
enteringRequiresTransition?: boolean;
requiresTransition?: boolean;
diff --git a/src/navigation/test/deep-linker.spec.ts b/src/navigation/test/deep-linker.spec.ts
index 17103bcf05..147074cfdd 100644
--- a/src/navigation/test/deep-linker.spec.ts
+++ b/src/navigation/test/deep-linker.spec.ts
@@ -284,6 +284,7 @@ describe('DeepLinker', () => {
expect(result.length).toEqual(1);
done();
}).catch((err: Error) => {
+ fail(err);
done(err);
});
});
diff --git a/src/navigation/test/nav-controller.spec.ts b/src/navigation/test/nav-controller.spec.ts
index 8b33bcd136..641f6388e9 100644
--- a/src/navigation/test/nav-controller.spec.ts
+++ b/src/navigation/test/nav-controller.spec.ts
@@ -60,7 +60,7 @@ describe('NavController', () => {
expect(nav.getByIndex(2).component).toEqual(MockView3);
expect(nav.getByIndex(3).component).toEqual(MockView4);
// Pop 1
- nav.pop({ animate: false }, pop1Done);
+ return nav.pop({ animate: false }, pop1Done);
}).then(() => {
expect(pop1Done).toHaveBeenCalledWith(
hasCompleted, requiresTransition, 'MockView3', 'MockView4', DIRECTION_BACK
@@ -88,9 +88,10 @@ describe('NavController', () => {
expect(nav.getByIndex(0).component).toEqual(MockView1);
done();
}).catch((err: Error) => {
+ fail(err);
done(err);
});
- });
+ }, 10000);
});
describe('push', () => {
@@ -108,9 +109,10 @@ describe('NavController', () => {
expect(nav.isTransitioning()).toEqual(false);
done();
}).catch((err: Error) => {
+ fail(err);
done(err);
});
- });
+ }, 10000);
it('should push a component as the second view at the end', (done: Function) => {
mockViews(nav, [mockView(MockView1)]);
@@ -128,9 +130,10 @@ describe('NavController', () => {
done();
}).catch((err: Error) => {
+ fail(err);
done(err);
});
- });
+ }, 10000);
it('should push a ViewController as the second view and fire lifecycles', (done: Function) => {
let view1 = mockView();
@@ -169,20 +172,26 @@ describe('NavController', () => {
done();
}).catch((err: Error) => {
+ fail(err);
done(err);
});
- });
+ }, 10000);
});
describe('insert', () => {
- it('should not modify the view id', () => {
+ it('should not modify the view id', (done) => {
let view = mockView(MockView4);
view.id = 'custom_id';
- nav.insert(0, view);
-
+ nav.insert(0, view).then(() => {
+ expect(view.id).toEqual('custom_id');
+ done();
+ }).catch(err => {
+ fail(err);
+ done();
+ });
expect(view.id).toEqual('custom_id');
- });
+ }, 10000);
it('should insert at the begining with no async transition', (done: Function) => {
@@ -213,9 +222,10 @@ describe('NavController', () => {
done();
}).catch((err: Error) => {
+ fail(err);
done(err);
});
- });
+ }, 10000);
it('should insert at the end when given -1', (done: Function) => {
let opts: NavOptions = {};
@@ -231,9 +241,10 @@ describe('NavController', () => {
expect(nav.last().component).toEqual(MockView2);
done();
}).catch((err: Error) => {
+ fail(err);
done(err);
});
- });
+ }, 10000);
it('should insert at the end when given a number greater than actual length', (done: Function) => {
mockViews(nav, [mockView(MockView1)]);
@@ -249,25 +260,28 @@ describe('NavController', () => {
done();
}).catch((err: Error) => {
+ fail(err);
done(err);
});
- });
+ }, 10000);
it('should not insert if null view', (done: Function) => {
mockViews(nav, [mockView(MockView1)]);
nav.insert(-1, null, null, null, trnsDone).then(() => {
+ fail('it should not succeed');
+ done();
+ }).catch((err: Error) => {
let hasCompleted = false;
let requiresTransition = false;
let rejectReason = 'invalid views to insert';
+ expect(err).toEqual(rejectReason);
expect(trnsDone).toHaveBeenCalledWith(hasCompleted, requiresTransition, rejectReason);
expect(nav.length()).toEqual(1);
expect(nav.last().component).toEqual(MockView1);
done();
- }).catch((err: Error) => {
- done(err);
});
- });
+ }, 10000);
it('should not insert any view in the stack if canLeave returns false', (done: Function) => {
let view1 = mockView(MockView1);
@@ -292,12 +306,11 @@ describe('NavController', () => {
}).then(() => {
expect(nav.length()).toEqual(3);
done();
- }).catch((err: Error) => {
- done(err);
- });
- });
+ }).catch(err => fail(err));
- it('should not remove any view from the stack if canLeave returns false', () => {
+ }, 10000);
+
+ it('should not remove any view from the stack if canLeave returns false', (done) => {
let view1 = mockView(MockView1);
let view2 = mockView(MockView2);
mockViews(nav, [view1, view2]);
@@ -310,15 +323,17 @@ describe('NavController', () => {
return (count === 3);
};
- nav.pop();
- expect(nav.length()).toEqual(2);
-
- nav.pop();
- expect(nav.length()).toEqual(2);
-
- nav.pop();
- expect(nav.length()).toEqual(1);
- });
+ nav.pop().then(() => {
+ expect(nav.length()).toEqual(2);
+ return nav.pop();
+ }).then(() => {
+ expect(nav.length()).toEqual(2);
+ return nav.pop();
+ }).then(() => {
+ expect(nav.length()).toEqual(1);
+ done();
+ }).catch(err => fail(err));
+ }, 10000);
});
@@ -356,104 +371,126 @@ describe('NavController', () => {
done();
}).catch((err: Error) => {
+ fail(err);
done(err);
});
- });
+ }, 10000);
});
describe('pop', () => {
- it('should not pop when no views in the stack', () => {
- nav.pop(null, trnsDone);
+ it('should not pop when no views in the stack', (done) => {
+ nav.pop(null, trnsDone).then(() => {
+ fail('it should not succeed');
+ done();
+ }).catch((err) => {
+ let hasCompleted = false;
+ let requiresTransition = false;
+ let rejectReason = 'no views in the stack to be removed';
+ expect(trnsDone).toHaveBeenCalledWith(
+ hasCompleted, requiresTransition, rejectReason
+ );
+ expect(err).toEqual(rejectReason);
+ expect(nav.length()).toEqual(0);
+ expect(nav.isTransitioning()).toEqual(false);
+ done();
+ });
+ }, 10000);
- let hasCompleted = false;
- let requiresTransition = false;
- expect(trnsDone).toHaveBeenCalledWith(
- hasCompleted, requiresTransition, 'no views in the stack to be removed'
- );
- expect(nav.length()).toEqual(0);
- expect(nav.isTransitioning()).toEqual(false);
- });
-
- it('should remove the last view and fire lifecycles', () => {
+ it('should remove the last view and fire lifecycles', (done: Function) => {
let view1 = mockView(MockView1);
let view2 = mockView(MockView2);
mockViews(nav, [view1, view2]);
let instance1 = spyOnLifecycles(view1);
let instance2 = spyOnLifecycles(view2);
- nav.pop(null, trnsDone);
+ nav.pop(null, trnsDone).then(() => {
- expect(instance1.ionViewDidLoad).toHaveBeenCalled();
- expect(instance1.ionViewCanEnter).toHaveBeenCalled();
- expect(instance1.ionViewWillEnter).toHaveBeenCalled();
- expect(instance1.ionViewDidEnter).toHaveBeenCalled();
- expect(instance1.ionViewCanLeave).not.toHaveBeenCalled();
- expect(instance1.ionViewWillLeave).not.toHaveBeenCalled();
- expect(instance1.ionViewDidLeave).not.toHaveBeenCalled();
- expect(instance1.ionViewWillUnload).not.toHaveBeenCalled();
+ expect(instance1.ionViewDidLoad).toHaveBeenCalled();
+ expect(instance1.ionViewCanEnter).toHaveBeenCalled();
+ expect(instance1.ionViewWillEnter).toHaveBeenCalled();
+ expect(instance1.ionViewDidEnter).toHaveBeenCalled();
+ expect(instance1.ionViewCanLeave).not.toHaveBeenCalled();
+ expect(instance1.ionViewWillLeave).not.toHaveBeenCalled();
+ expect(instance1.ionViewDidLeave).not.toHaveBeenCalled();
+ expect(instance1.ionViewWillUnload).not.toHaveBeenCalled();
- expect(instance2.ionViewDidLoad).not.toHaveBeenCalled();
- expect(instance2.ionViewCanEnter).not.toHaveBeenCalled();
- expect(instance2.ionViewWillEnter).not.toHaveBeenCalled();
- expect(instance2.ionViewDidEnter).not.toHaveBeenCalled();
- expect(instance2.ionViewCanLeave).toHaveBeenCalled();
- expect(instance2.ionViewWillLeave).toHaveBeenCalled();
- expect(instance2.ionViewDidLeave).toHaveBeenCalled();
- expect(instance2.ionViewWillUnload).toHaveBeenCalled();
+ expect(instance2.ionViewDidLoad).not.toHaveBeenCalled();
+ expect(instance2.ionViewCanEnter).not.toHaveBeenCalled();
+ expect(instance2.ionViewWillEnter).not.toHaveBeenCalled();
+ expect(instance2.ionViewDidEnter).not.toHaveBeenCalled();
+ expect(instance2.ionViewCanLeave).toHaveBeenCalled();
+ expect(instance2.ionViewWillLeave).toHaveBeenCalled();
+ expect(instance2.ionViewDidLeave).toHaveBeenCalled();
+ expect(instance2.ionViewWillUnload).toHaveBeenCalled();
- let hasCompleted = true;
- let requiresTransition = true;
- expect(trnsDone).toHaveBeenCalledWith(
- hasCompleted, requiresTransition, 'MockView1', 'MockView2', DIRECTION_BACK
- );
- expect(nav.length()).toEqual(1);
- expect(nav.getByIndex(0).component).toEqual(MockView1);
- expect(nav.isTransitioning()).toEqual(false);
- });
+ let hasCompleted = true;
+ let requiresTransition = true;
+ expect(trnsDone).toHaveBeenCalledWith(
+ hasCompleted, requiresTransition, 'MockView1', 'MockView2', DIRECTION_BACK
+ );
+ expect(nav.length()).toEqual(1);
+ expect(nav.getByIndex(0).component).toEqual(MockView1);
+ expect(nav.isTransitioning()).toEqual(false);
+ done();
+ }).catch((err: Error) => {
+ fail(err);
+ done(err);
+ });
+ }, 10000);
});
describe('popTo', () => {
- it('should pop to a view', () => {
+ it('should pop to a view', (done: Function) => {
let view1 = mockView(MockView1);
let view2 = mockView(MockView2);
let view3 = mockView(MockView3);
mockViews(nav, [view1, view2, view3]);
- nav.popTo(view2, null, trnsDone);
+ nav.popTo(view2, null, trnsDone).then(() => {
- let hasCompleted = true;
- let requiresTransition = true;
- expect(trnsDone).toHaveBeenCalledWith(
- hasCompleted, requiresTransition, 'MockView2', 'MockView3', DIRECTION_BACK
- );
- expect(nav.length()).toEqual(2);
- expect(nav.getByIndex(0).component).toEqual(MockView1);
- expect(nav.getByIndex(1).component).toEqual(MockView2);
- });
+ let hasCompleted = true;
+ let requiresTransition = true;
+ expect(trnsDone).toHaveBeenCalledWith(
+ hasCompleted, requiresTransition, 'MockView2', 'MockView3', DIRECTION_BACK
+ );
+ expect(nav.length()).toEqual(2);
+ expect(nav.getByIndex(0).component).toEqual(MockView1);
+ expect(nav.getByIndex(1).component).toEqual(MockView2);
+ done();
+ }).catch((err: Error) => {
+ fail(err);
+ done(err);
+ });
+ }, 10000);
- it('should pop to using an index number', () => {
+ it('should pop to using an index number', (done: Function) => {
let view1 = mockView(MockView1);
let view2 = mockView(MockView2);
let view3 = mockView(MockView3);
let view4 = mockView(MockView4);
mockViews(nav, [view1, view2, view3, view4]);
- nav.popTo(1, null, trnsDone);
+ nav.popTo(1, null, trnsDone).then(() => {
- let hasCompleted = true;
- let requiresTransition = true;
- expect(trnsDone).toHaveBeenCalledWith(
- hasCompleted, requiresTransition, 'MockView2', 'MockView4', DIRECTION_BACK
- );
- expect(nav.length()).toEqual(2);
- expect(nav.getByIndex(0).component).toEqual(MockView1);
- expect(nav.getByIndex(1).component).toEqual(MockView2);
- });
+ let hasCompleted = true;
+ let requiresTransition = true;
+ expect(trnsDone).toHaveBeenCalledWith(
+ hasCompleted, requiresTransition, 'MockView2', 'MockView4', DIRECTION_BACK
+ );
+ expect(nav.length()).toEqual(2);
+ expect(nav.getByIndex(0).component).toEqual(MockView1);
+ expect(nav.getByIndex(1).component).toEqual(MockView2);
+ done();
+ }).catch((err: Error) => {
+ fail(err);
+ done(err);
+ });
+ }, 10000);
- it('should pop to first using an index number', () => {
+ it('should pop to first using an index number', (done: Function) => {
let view1 = mockView(MockView1);
let view2 = mockView(MockView2);
let view3 = mockView(MockView3);
@@ -465,58 +502,63 @@ describe('NavController', () => {
let instance3 = spyOnLifecycles(view3);
let instance4 = spyOnLifecycles(view4);
- nav.popTo(0, null, trnsDone);
+ nav.popTo(0, null, trnsDone).then(() => {
- expect(instance1.ionViewDidLoad).toHaveBeenCalled();
- expect(instance1.ionViewCanEnter).toHaveBeenCalled();
- expect(instance1.ionViewWillEnter).toHaveBeenCalled();
- expect(instance1.ionViewDidEnter).toHaveBeenCalled();
- expect(instance1.ionViewCanLeave).not.toHaveBeenCalled();
- expect(instance1.ionViewWillLeave).not.toHaveBeenCalled();
- expect(instance1.ionViewDidLeave).not.toHaveBeenCalled();
- expect(instance1.ionViewWillUnload).not.toHaveBeenCalled();
+ expect(instance1.ionViewDidLoad).toHaveBeenCalled();
+ expect(instance1.ionViewCanEnter).toHaveBeenCalled();
+ expect(instance1.ionViewWillEnter).toHaveBeenCalled();
+ expect(instance1.ionViewDidEnter).toHaveBeenCalled();
+ expect(instance1.ionViewCanLeave).not.toHaveBeenCalled();
+ expect(instance1.ionViewWillLeave).not.toHaveBeenCalled();
+ expect(instance1.ionViewDidLeave).not.toHaveBeenCalled();
+ expect(instance1.ionViewWillUnload).not.toHaveBeenCalled();
- expect(instance2.ionViewDidLoad).not.toHaveBeenCalled();
- expect(instance2.ionViewCanEnter).not.toHaveBeenCalled();
- expect(instance2.ionViewWillEnter).not.toHaveBeenCalled();
- expect(instance2.ionViewDidEnter).not.toHaveBeenCalled();
- expect(instance2.ionViewCanLeave).not.toHaveBeenCalled();
- expect(instance2.ionViewWillLeave).toHaveBeenCalled();
- expect(instance2.ionViewDidLeave).toHaveBeenCalled();
- expect(instance2.ionViewWillUnload).toHaveBeenCalled();
+ expect(instance2.ionViewDidLoad).not.toHaveBeenCalled();
+ expect(instance2.ionViewCanEnter).not.toHaveBeenCalled();
+ expect(instance2.ionViewWillEnter).not.toHaveBeenCalled();
+ expect(instance2.ionViewDidEnter).not.toHaveBeenCalled();
+ expect(instance2.ionViewCanLeave).not.toHaveBeenCalled();
+ expect(instance2.ionViewWillLeave).toHaveBeenCalled();
+ expect(instance2.ionViewDidLeave).toHaveBeenCalled();
+ expect(instance2.ionViewWillUnload).toHaveBeenCalled();
- expect(instance3.ionViewDidLoad).not.toHaveBeenCalled();
- expect(instance3.ionViewCanEnter).not.toHaveBeenCalled();
- expect(instance3.ionViewWillEnter).not.toHaveBeenCalled();
- expect(instance3.ionViewDidEnter).not.toHaveBeenCalled();
- expect(instance3.ionViewCanLeave).not.toHaveBeenCalled();
- expect(instance3.ionViewWillLeave).toHaveBeenCalled();
- expect(instance3.ionViewDidLeave).toHaveBeenCalled();
- expect(instance3.ionViewWillUnload).toHaveBeenCalled();
+ expect(instance3.ionViewDidLoad).not.toHaveBeenCalled();
+ expect(instance3.ionViewCanEnter).not.toHaveBeenCalled();
+ expect(instance3.ionViewWillEnter).not.toHaveBeenCalled();
+ expect(instance3.ionViewDidEnter).not.toHaveBeenCalled();
+ expect(instance3.ionViewCanLeave).not.toHaveBeenCalled();
+ expect(instance3.ionViewWillLeave).toHaveBeenCalled();
+ expect(instance3.ionViewDidLeave).toHaveBeenCalled();
+ expect(instance3.ionViewWillUnload).toHaveBeenCalled();
- expect(instance4.ionViewDidLoad).not.toHaveBeenCalled();
- expect(instance4.ionViewCanEnter).not.toHaveBeenCalled();
- expect(instance4.ionViewWillEnter).not.toHaveBeenCalled();
- expect(instance4.ionViewDidEnter).not.toHaveBeenCalled();
- expect(instance4.ionViewCanLeave).toHaveBeenCalled();
- expect(instance4.ionViewWillLeave).toHaveBeenCalled();
- expect(instance4.ionViewDidLeave).toHaveBeenCalled();
- expect(instance4.ionViewWillUnload).toHaveBeenCalled();
+ expect(instance4.ionViewDidLoad).not.toHaveBeenCalled();
+ expect(instance4.ionViewCanEnter).not.toHaveBeenCalled();
+ expect(instance4.ionViewWillEnter).not.toHaveBeenCalled();
+ expect(instance4.ionViewDidEnter).not.toHaveBeenCalled();
+ expect(instance4.ionViewCanLeave).toHaveBeenCalled();
+ expect(instance4.ionViewWillLeave).toHaveBeenCalled();
+ expect(instance4.ionViewDidLeave).toHaveBeenCalled();
+ expect(instance4.ionViewWillUnload).toHaveBeenCalled();
- let hasCompleted = true;
- let requiresTransition = true;
- expect(trnsDone).toHaveBeenCalledWith(
- hasCompleted, requiresTransition, 'MockView1', 'MockView4', DIRECTION_BACK
- );
- expect(nav.length()).toEqual(1);
- expect(nav.getByIndex(0).component).toEqual(MockView1);
- });
+ let hasCompleted = true;
+ let requiresTransition = true;
+ expect(trnsDone).toHaveBeenCalledWith(
+ hasCompleted, requiresTransition, 'MockView1', 'MockView4', DIRECTION_BACK
+ );
+ expect(nav.length()).toEqual(1);
+ expect(nav.getByIndex(0).component).toEqual(MockView1);
+ done();
+ }).catch((err: Error) => {
+ fail(err);
+ done(err);
+ });
+ }, 10000);
});
describe('popToRoot', () => {
- it('should pop to the first view', () => {
+ it('should pop to the first view', (done: Function) => {
let view1 = mockView(MockView1);
let view2 = mockView(MockView2);
let view3 = mockView(MockView3);
@@ -528,58 +570,63 @@ describe('NavController', () => {
let instance3 = spyOnLifecycles(view3);
let instance4 = spyOnLifecycles(view4);
- nav.popToRoot(null, trnsDone);
+ nav.popToRoot(null, trnsDone).then(() => {
- expect(instance1.ionViewDidLoad).toHaveBeenCalled();
- expect(instance1.ionViewCanEnter).toHaveBeenCalled();
- expect(instance1.ionViewWillEnter).toHaveBeenCalled();
- expect(instance1.ionViewDidEnter).toHaveBeenCalled();
- expect(instance1.ionViewCanLeave).not.toHaveBeenCalled();
- expect(instance1.ionViewWillLeave).not.toHaveBeenCalled();
- expect(instance1.ionViewDidLeave).not.toHaveBeenCalled();
- expect(instance1.ionViewWillUnload).not.toHaveBeenCalled();
+ expect(instance1.ionViewDidLoad).toHaveBeenCalled();
+ expect(instance1.ionViewCanEnter).toHaveBeenCalled();
+ expect(instance1.ionViewWillEnter).toHaveBeenCalled();
+ expect(instance1.ionViewDidEnter).toHaveBeenCalled();
+ expect(instance1.ionViewCanLeave).not.toHaveBeenCalled();
+ expect(instance1.ionViewWillLeave).not.toHaveBeenCalled();
+ expect(instance1.ionViewDidLeave).not.toHaveBeenCalled();
+ expect(instance1.ionViewWillUnload).not.toHaveBeenCalled();
- expect(instance2.ionViewDidLoad).not.toHaveBeenCalled();
- expect(instance2.ionViewCanEnter).not.toHaveBeenCalled();
- expect(instance2.ionViewWillEnter).not.toHaveBeenCalled();
- expect(instance2.ionViewDidEnter).not.toHaveBeenCalled();
- expect(instance2.ionViewCanLeave).not.toHaveBeenCalled();
- expect(instance2.ionViewWillLeave).toHaveBeenCalled();
- expect(instance2.ionViewDidLeave).toHaveBeenCalled();
- expect(instance2.ionViewWillUnload).toHaveBeenCalled();
+ expect(instance2.ionViewDidLoad).not.toHaveBeenCalled();
+ expect(instance2.ionViewCanEnter).not.toHaveBeenCalled();
+ expect(instance2.ionViewWillEnter).not.toHaveBeenCalled();
+ expect(instance2.ionViewDidEnter).not.toHaveBeenCalled();
+ expect(instance2.ionViewCanLeave).not.toHaveBeenCalled();
+ expect(instance2.ionViewWillLeave).toHaveBeenCalled();
+ expect(instance2.ionViewDidLeave).toHaveBeenCalled();
+ expect(instance2.ionViewWillUnload).toHaveBeenCalled();
- expect(instance3.ionViewDidLoad).not.toHaveBeenCalled();
- expect(instance3.ionViewCanEnter).not.toHaveBeenCalled();
- expect(instance3.ionViewWillEnter).not.toHaveBeenCalled();
- expect(instance3.ionViewDidEnter).not.toHaveBeenCalled();
- expect(instance3.ionViewCanLeave).not.toHaveBeenCalled();
- expect(instance3.ionViewWillLeave).toHaveBeenCalled();
- expect(instance3.ionViewDidLeave).toHaveBeenCalled();
- expect(instance3.ionViewWillUnload).toHaveBeenCalled();
+ expect(instance3.ionViewDidLoad).not.toHaveBeenCalled();
+ expect(instance3.ionViewCanEnter).not.toHaveBeenCalled();
+ expect(instance3.ionViewWillEnter).not.toHaveBeenCalled();
+ expect(instance3.ionViewDidEnter).not.toHaveBeenCalled();
+ expect(instance3.ionViewCanLeave).not.toHaveBeenCalled();
+ expect(instance3.ionViewWillLeave).toHaveBeenCalled();
+ expect(instance3.ionViewDidLeave).toHaveBeenCalled();
+ expect(instance3.ionViewWillUnload).toHaveBeenCalled();
- expect(instance4.ionViewDidLoad).not.toHaveBeenCalled();
- expect(instance4.ionViewCanEnter).not.toHaveBeenCalled();
- expect(instance4.ionViewWillEnter).not.toHaveBeenCalled();
- expect(instance4.ionViewDidEnter).not.toHaveBeenCalled();
- expect(instance4.ionViewCanLeave).toHaveBeenCalled();
- expect(instance4.ionViewWillLeave).toHaveBeenCalled();
- expect(instance4.ionViewDidLeave).toHaveBeenCalled();
- expect(instance4.ionViewWillUnload).toHaveBeenCalled();
+ expect(instance4.ionViewDidLoad).not.toHaveBeenCalled();
+ expect(instance4.ionViewCanEnter).not.toHaveBeenCalled();
+ expect(instance4.ionViewWillEnter).not.toHaveBeenCalled();
+ expect(instance4.ionViewDidEnter).not.toHaveBeenCalled();
+ expect(instance4.ionViewCanLeave).toHaveBeenCalled();
+ expect(instance4.ionViewWillLeave).toHaveBeenCalled();
+ expect(instance4.ionViewDidLeave).toHaveBeenCalled();
+ expect(instance4.ionViewWillUnload).toHaveBeenCalled();
- let hasCompleted = true;
- let requiresTransition = true;
- expect(trnsDone).toHaveBeenCalledWith(
- hasCompleted, requiresTransition, 'MockView1', 'MockView4', DIRECTION_BACK
- );
- expect(nav.length()).toEqual(1);
- expect(nav.getByIndex(0).component).toEqual(MockView1);
- });
+ let hasCompleted = true;
+ let requiresTransition = true;
+ expect(trnsDone).toHaveBeenCalledWith(
+ hasCompleted, requiresTransition, 'MockView1', 'MockView4', DIRECTION_BACK
+ );
+ expect(nav.length()).toEqual(1);
+ expect(nav.getByIndex(0).component).toEqual(MockView1);
+ done();
+ }).catch((err: Error) => {
+ fail(err);
+ done(err);
+ });
+ }, 10000);
});
describe('remove', () => {
- it('should remove the first three views in the beginning, no last view transition', () => {
+ it('should remove the first three views in the beginning, no last view transition', (done: Function) => {
let view1 = mockView(MockView1);
let view2 = mockView(MockView2);
let view3 = mockView(MockView3);
@@ -591,54 +638,59 @@ describe('NavController', () => {
let instance3 = spyOnLifecycles(view3);
let instance4 = spyOnLifecycles(view4);
- nav.remove(0, 3, null, trnsDone);
+ nav.remove(0, 3, null, trnsDone).then(() => {
- expect(instance1.ionViewDidLoad).not.toHaveBeenCalled();
- expect(instance1.ionViewCanEnter).not.toHaveBeenCalled();
- expect(instance1.ionViewWillEnter).not.toHaveBeenCalled();
- expect(instance1.ionViewDidEnter).not.toHaveBeenCalled();
- expect(instance1.ionViewCanLeave).not.toHaveBeenCalled();
- expect(instance1.ionViewWillLeave).toHaveBeenCalled();
- expect(instance1.ionViewDidLeave).toHaveBeenCalled();
- expect(instance1.ionViewWillUnload).toHaveBeenCalled();
+ expect(instance1.ionViewDidLoad).not.toHaveBeenCalled();
+ expect(instance1.ionViewCanEnter).not.toHaveBeenCalled();
+ expect(instance1.ionViewWillEnter).not.toHaveBeenCalled();
+ expect(instance1.ionViewDidEnter).not.toHaveBeenCalled();
+ expect(instance1.ionViewCanLeave).not.toHaveBeenCalled();
+ expect(instance1.ionViewWillLeave).toHaveBeenCalled();
+ expect(instance1.ionViewDidLeave).toHaveBeenCalled();
+ expect(instance1.ionViewWillUnload).toHaveBeenCalled();
- expect(instance2.ionViewDidLoad).not.toHaveBeenCalled();
- expect(instance2.ionViewCanEnter).not.toHaveBeenCalled();
- expect(instance2.ionViewWillEnter).not.toHaveBeenCalled();
- expect(instance2.ionViewDidEnter).not.toHaveBeenCalled();
- expect(instance2.ionViewCanLeave).not.toHaveBeenCalled();
- expect(instance2.ionViewWillLeave).toHaveBeenCalled();
- expect(instance2.ionViewDidLeave).toHaveBeenCalled();
- expect(instance2.ionViewWillUnload).toHaveBeenCalled();
+ expect(instance2.ionViewDidLoad).not.toHaveBeenCalled();
+ expect(instance2.ionViewCanEnter).not.toHaveBeenCalled();
+ expect(instance2.ionViewWillEnter).not.toHaveBeenCalled();
+ expect(instance2.ionViewDidEnter).not.toHaveBeenCalled();
+ expect(instance2.ionViewCanLeave).not.toHaveBeenCalled();
+ expect(instance2.ionViewWillLeave).toHaveBeenCalled();
+ expect(instance2.ionViewDidLeave).toHaveBeenCalled();
+ expect(instance2.ionViewWillUnload).toHaveBeenCalled();
- expect(instance3.ionViewDidLoad).not.toHaveBeenCalled();
- expect(instance3.ionViewCanEnter).not.toHaveBeenCalled();
- expect(instance3.ionViewWillEnter).not.toHaveBeenCalled();
- expect(instance3.ionViewDidEnter).not.toHaveBeenCalled();
- expect(instance3.ionViewCanLeave).not.toHaveBeenCalled();
- expect(instance3.ionViewWillLeave).toHaveBeenCalled();
- expect(instance3.ionViewDidLeave).toHaveBeenCalled();
- expect(instance3.ionViewWillUnload).toHaveBeenCalled();
+ expect(instance3.ionViewDidLoad).not.toHaveBeenCalled();
+ expect(instance3.ionViewCanEnter).not.toHaveBeenCalled();
+ expect(instance3.ionViewWillEnter).not.toHaveBeenCalled();
+ expect(instance3.ionViewDidEnter).not.toHaveBeenCalled();
+ expect(instance3.ionViewCanLeave).not.toHaveBeenCalled();
+ expect(instance3.ionViewWillLeave).toHaveBeenCalled();
+ expect(instance3.ionViewDidLeave).toHaveBeenCalled();
+ expect(instance3.ionViewWillUnload).toHaveBeenCalled();
- expect(instance4.ionViewDidLoad).not.toHaveBeenCalled();
- expect(instance4.ionViewCanEnter).not.toHaveBeenCalled();
- expect(instance4.ionViewWillEnter).not.toHaveBeenCalled();
- expect(instance4.ionViewDidEnter).not.toHaveBeenCalled();
- expect(instance4.ionViewCanLeave).not.toHaveBeenCalled();
- expect(instance4.ionViewWillLeave).not.toHaveBeenCalled();
- expect(instance4.ionViewDidLeave).not.toHaveBeenCalled();
- expect(instance4.ionViewWillUnload).not.toHaveBeenCalled();
+ expect(instance4.ionViewDidLoad).not.toHaveBeenCalled();
+ expect(instance4.ionViewCanEnter).not.toHaveBeenCalled();
+ expect(instance4.ionViewWillEnter).not.toHaveBeenCalled();
+ expect(instance4.ionViewDidEnter).not.toHaveBeenCalled();
+ expect(instance4.ionViewCanLeave).not.toHaveBeenCalled();
+ expect(instance4.ionViewWillLeave).not.toHaveBeenCalled();
+ expect(instance4.ionViewDidLeave).not.toHaveBeenCalled();
+ expect(instance4.ionViewWillUnload).not.toHaveBeenCalled();
- let hasCompleted = true;
- let requiresTransition = false;
- expect(trnsDone).toHaveBeenCalledWith(
- hasCompleted, requiresTransition, undefined, undefined, undefined
- );
- expect(nav.length()).toEqual(1);
- expect(nav.getByIndex(0).component).toEqual(MockView4);
- });
+ let hasCompleted = true;
+ let requiresTransition = false;
+ expect(trnsDone).toHaveBeenCalledWith(
+ hasCompleted, requiresTransition, undefined, undefined, undefined
+ );
+ expect(nav.length()).toEqual(1);
+ expect(nav.getByIndex(0).component).toEqual(MockView4);
+ done();
+ }).catch((err: Error) => {
+ fail(err);
+ done(err);
+ });
+ }, 10000);
- it('should remove two views in the middle', () => {
+ it('should remove two views in the middle', (done: Function) => {
let view1 = mockView(MockView1);
let view2 = mockView(MockView2);
let view3 = mockView(MockView3);
@@ -652,65 +704,70 @@ describe('NavController', () => {
let instance4 = spyOnLifecycles(view4);
let instance5 = spyOnLifecycles(view5);
- nav.remove(2, 2, null, trnsDone);
+ nav.remove(2, 2, null, trnsDone).then(() => {
- expect(instance1.ionViewDidLoad).not.toHaveBeenCalled();
- expect(instance1.ionViewCanEnter).not.toHaveBeenCalled();
- expect(instance1.ionViewWillEnter).not.toHaveBeenCalled();
- expect(instance1.ionViewDidEnter).not.toHaveBeenCalled();
- expect(instance1.ionViewCanLeave).not.toHaveBeenCalled();
- expect(instance1.ionViewWillLeave).not.toHaveBeenCalled();
- expect(instance1.ionViewDidLeave).not.toHaveBeenCalled();
- expect(instance1.ionViewWillUnload).not.toHaveBeenCalled();
+ expect(instance1.ionViewDidLoad).not.toHaveBeenCalled();
+ expect(instance1.ionViewCanEnter).not.toHaveBeenCalled();
+ expect(instance1.ionViewWillEnter).not.toHaveBeenCalled();
+ expect(instance1.ionViewDidEnter).not.toHaveBeenCalled();
+ expect(instance1.ionViewCanLeave).not.toHaveBeenCalled();
+ expect(instance1.ionViewWillLeave).not.toHaveBeenCalled();
+ expect(instance1.ionViewDidLeave).not.toHaveBeenCalled();
+ expect(instance1.ionViewWillUnload).not.toHaveBeenCalled();
- expect(instance2.ionViewDidLoad).not.toHaveBeenCalled();
- expect(instance2.ionViewCanEnter).not.toHaveBeenCalled();
- expect(instance2.ionViewWillEnter).not.toHaveBeenCalled();
- expect(instance2.ionViewDidEnter).not.toHaveBeenCalled();
- expect(instance2.ionViewCanLeave).not.toHaveBeenCalled();
- expect(instance2.ionViewWillLeave).not.toHaveBeenCalled();
- expect(instance2.ionViewDidLeave).not.toHaveBeenCalled();
- expect(instance2.ionViewWillUnload).not.toHaveBeenCalled();
+ expect(instance2.ionViewDidLoad).not.toHaveBeenCalled();
+ expect(instance2.ionViewCanEnter).not.toHaveBeenCalled();
+ expect(instance2.ionViewWillEnter).not.toHaveBeenCalled();
+ expect(instance2.ionViewDidEnter).not.toHaveBeenCalled();
+ expect(instance2.ionViewCanLeave).not.toHaveBeenCalled();
+ expect(instance2.ionViewWillLeave).not.toHaveBeenCalled();
+ expect(instance2.ionViewDidLeave).not.toHaveBeenCalled();
+ expect(instance2.ionViewWillUnload).not.toHaveBeenCalled();
- expect(instance3.ionViewDidLoad).not.toHaveBeenCalled();
- expect(instance3.ionViewCanEnter).not.toHaveBeenCalled();
- expect(instance3.ionViewWillEnter).not.toHaveBeenCalled();
- expect(instance3.ionViewDidEnter).not.toHaveBeenCalled();
- expect(instance3.ionViewCanLeave).not.toHaveBeenCalled();
- expect(instance3.ionViewWillLeave).toHaveBeenCalled();
- expect(instance3.ionViewDidLeave).toHaveBeenCalled();
- expect(instance3.ionViewWillUnload).toHaveBeenCalled();
+ expect(instance3.ionViewDidLoad).not.toHaveBeenCalled();
+ expect(instance3.ionViewCanEnter).not.toHaveBeenCalled();
+ expect(instance3.ionViewWillEnter).not.toHaveBeenCalled();
+ expect(instance3.ionViewDidEnter).not.toHaveBeenCalled();
+ expect(instance3.ionViewCanLeave).not.toHaveBeenCalled();
+ expect(instance3.ionViewWillLeave).toHaveBeenCalled();
+ expect(instance3.ionViewDidLeave).toHaveBeenCalled();
+ expect(instance3.ionViewWillUnload).toHaveBeenCalled();
- expect(instance4.ionViewDidLoad).not.toHaveBeenCalled();
- expect(instance4.ionViewCanEnter).not.toHaveBeenCalled();
- expect(instance4.ionViewWillEnter).not.toHaveBeenCalled();
- expect(instance4.ionViewDidEnter).not.toHaveBeenCalled();
- expect(instance4.ionViewCanLeave).not.toHaveBeenCalled();
- expect(instance4.ionViewWillLeave).toHaveBeenCalled();
- expect(instance4.ionViewDidLeave).toHaveBeenCalled();
- expect(instance4.ionViewWillUnload).toHaveBeenCalled();
+ expect(instance4.ionViewDidLoad).not.toHaveBeenCalled();
+ expect(instance4.ionViewCanEnter).not.toHaveBeenCalled();
+ expect(instance4.ionViewWillEnter).not.toHaveBeenCalled();
+ expect(instance4.ionViewDidEnter).not.toHaveBeenCalled();
+ expect(instance4.ionViewCanLeave).not.toHaveBeenCalled();
+ expect(instance4.ionViewWillLeave).toHaveBeenCalled();
+ expect(instance4.ionViewDidLeave).toHaveBeenCalled();
+ expect(instance4.ionViewWillUnload).toHaveBeenCalled();
- expect(instance5.ionViewDidLoad).not.toHaveBeenCalled();
- expect(instance5.ionViewCanEnter).not.toHaveBeenCalled();
- expect(instance5.ionViewWillEnter).not.toHaveBeenCalled();
- expect(instance5.ionViewDidEnter).not.toHaveBeenCalled();
- expect(instance5.ionViewCanLeave).not.toHaveBeenCalled();
- expect(instance5.ionViewWillLeave).not.toHaveBeenCalled();
- expect(instance5.ionViewDidLeave).not.toHaveBeenCalled();
- expect(instance5.ionViewWillUnload).not.toHaveBeenCalled();
+ expect(instance5.ionViewDidLoad).not.toHaveBeenCalled();
+ expect(instance5.ionViewCanEnter).not.toHaveBeenCalled();
+ expect(instance5.ionViewWillEnter).not.toHaveBeenCalled();
+ expect(instance5.ionViewDidEnter).not.toHaveBeenCalled();
+ expect(instance5.ionViewCanLeave).not.toHaveBeenCalled();
+ expect(instance5.ionViewWillLeave).not.toHaveBeenCalled();
+ expect(instance5.ionViewDidLeave).not.toHaveBeenCalled();
+ expect(instance5.ionViewWillUnload).not.toHaveBeenCalled();
- let hasCompleted = true;
- let requiresTransition = false;
- expect(trnsDone).toHaveBeenCalledWith(
- hasCompleted, requiresTransition, undefined, undefined, undefined
- );
- expect(nav.length()).toEqual(3);
- expect(nav.getByIndex(0).component).toEqual(MockView1);
- expect(nav.getByIndex(1).component).toEqual(MockView2);
- expect(nav.getByIndex(2).component).toEqual(MockView5);
- });
+ let hasCompleted = true;
+ let requiresTransition = false;
+ expect(trnsDone).toHaveBeenCalledWith(
+ hasCompleted, requiresTransition, undefined, undefined, undefined
+ );
+ expect(nav.length()).toEqual(3);
+ expect(nav.getByIndex(0).component).toEqual(MockView1);
+ expect(nav.getByIndex(1).component).toEqual(MockView2);
+ expect(nav.getByIndex(2).component).toEqual(MockView5);
+ done();
+ }).catch((err: Error) => {
+ fail(err);
+ done(err);
+ });
+ }, 10000);
- it('should remove the last two views at the end', () => {
+ it('should remove the last two views at the end', (done: Function) => {
let view1 = mockView(MockView1);
let view2 = mockView(MockView2);
let view3 = mockView(MockView3);
@@ -722,53 +779,58 @@ describe('NavController', () => {
let instance3 = spyOnLifecycles(view3);
let instance4 = spyOnLifecycles(view4);
- nav.remove(2, 2, null, trnsDone);
+ nav.remove(2, 2, null, trnsDone).then(() => {
- expect(instance1.ionViewDidLoad).not.toHaveBeenCalled();
- expect(instance1.ionViewCanEnter).not.toHaveBeenCalled();
- expect(instance1.ionViewWillEnter).not.toHaveBeenCalled();
- expect(instance1.ionViewDidEnter).not.toHaveBeenCalled();
- expect(instance1.ionViewCanLeave).not.toHaveBeenCalled();
- expect(instance1.ionViewWillLeave).not.toHaveBeenCalled();
- expect(instance1.ionViewDidLeave).not.toHaveBeenCalled();
- expect(instance1.ionViewWillUnload).not.toHaveBeenCalled();
+ expect(instance1.ionViewDidLoad).not.toHaveBeenCalled();
+ expect(instance1.ionViewCanEnter).not.toHaveBeenCalled();
+ expect(instance1.ionViewWillEnter).not.toHaveBeenCalled();
+ expect(instance1.ionViewDidEnter).not.toHaveBeenCalled();
+ expect(instance1.ionViewCanLeave).not.toHaveBeenCalled();
+ expect(instance1.ionViewWillLeave).not.toHaveBeenCalled();
+ expect(instance1.ionViewDidLeave).not.toHaveBeenCalled();
+ expect(instance1.ionViewWillUnload).not.toHaveBeenCalled();
- expect(instance2.ionViewDidLoad).toHaveBeenCalled();
- expect(instance2.ionViewCanEnter).toHaveBeenCalled();
- expect(instance2.ionViewWillEnter).toHaveBeenCalled();
- expect(instance2.ionViewDidEnter).toHaveBeenCalled();
- expect(instance2.ionViewCanLeave).not.toHaveBeenCalled();
- expect(instance2.ionViewWillLeave).not.toHaveBeenCalled();
- expect(instance2.ionViewDidLeave).not.toHaveBeenCalled();
- expect(instance2.ionViewWillUnload).not.toHaveBeenCalled();
+ expect(instance2.ionViewDidLoad).toHaveBeenCalled();
+ expect(instance2.ionViewCanEnter).toHaveBeenCalled();
+ expect(instance2.ionViewWillEnter).toHaveBeenCalled();
+ expect(instance2.ionViewDidEnter).toHaveBeenCalled();
+ expect(instance2.ionViewCanLeave).not.toHaveBeenCalled();
+ expect(instance2.ionViewWillLeave).not.toHaveBeenCalled();
+ expect(instance2.ionViewDidLeave).not.toHaveBeenCalled();
+ expect(instance2.ionViewWillUnload).not.toHaveBeenCalled();
- expect(instance3.ionViewDidLoad).not.toHaveBeenCalled();
- expect(instance3.ionViewCanEnter).not.toHaveBeenCalled();
- expect(instance3.ionViewWillEnter).not.toHaveBeenCalled();
- expect(instance3.ionViewDidEnter).not.toHaveBeenCalled();
- expect(instance3.ionViewCanLeave).not.toHaveBeenCalled();
- expect(instance3.ionViewWillLeave).toHaveBeenCalled();
- expect(instance3.ionViewDidLeave).toHaveBeenCalled();
- expect(instance3.ionViewWillUnload).toHaveBeenCalled();
+ expect(instance3.ionViewDidLoad).not.toHaveBeenCalled();
+ expect(instance3.ionViewCanEnter).not.toHaveBeenCalled();
+ expect(instance3.ionViewWillEnter).not.toHaveBeenCalled();
+ expect(instance3.ionViewDidEnter).not.toHaveBeenCalled();
+ expect(instance3.ionViewCanLeave).not.toHaveBeenCalled();
+ expect(instance3.ionViewWillLeave).toHaveBeenCalled();
+ expect(instance3.ionViewDidLeave).toHaveBeenCalled();
+ expect(instance3.ionViewWillUnload).toHaveBeenCalled();
- expect(instance4.ionViewDidLoad).not.toHaveBeenCalled();
- expect(instance4.ionViewCanEnter).not.toHaveBeenCalled();
- expect(instance4.ionViewWillEnter).not.toHaveBeenCalled();
- expect(instance4.ionViewDidEnter).not.toHaveBeenCalled();
- expect(instance4.ionViewCanLeave).toHaveBeenCalled();
- expect(instance4.ionViewWillLeave).toHaveBeenCalled();
- expect(instance4.ionViewDidLeave).toHaveBeenCalled();
- expect(instance4.ionViewWillUnload).toHaveBeenCalled();
+ expect(instance4.ionViewDidLoad).not.toHaveBeenCalled();
+ expect(instance4.ionViewCanEnter).not.toHaveBeenCalled();
+ expect(instance4.ionViewWillEnter).not.toHaveBeenCalled();
+ expect(instance4.ionViewDidEnter).not.toHaveBeenCalled();
+ expect(instance4.ionViewCanLeave).toHaveBeenCalled();
+ expect(instance4.ionViewWillLeave).toHaveBeenCalled();
+ expect(instance4.ionViewDidLeave).toHaveBeenCalled();
+ expect(instance4.ionViewWillUnload).toHaveBeenCalled();
- let hasCompleted = true;
- let requiresTransition = true;
- expect(trnsDone).toHaveBeenCalledWith(
- hasCompleted, requiresTransition, 'MockView2', 'MockView4', DIRECTION_BACK
- );
- expect(nav.length()).toEqual(2);
- expect(nav.getByIndex(0).component).toEqual(MockView1);
- expect(nav.getByIndex(1).component).toEqual(MockView2);
- });
+ let hasCompleted = true;
+ let requiresTransition = true;
+ expect(trnsDone).toHaveBeenCalledWith(
+ hasCompleted, requiresTransition, 'MockView2', 'MockView4', DIRECTION_BACK
+ );
+ expect(nav.length()).toEqual(2);
+ expect(nav.getByIndex(0).component).toEqual(MockView1);
+ expect(nav.getByIndex(1).component).toEqual(MockView2);
+ done();
+ }).catch((err: Error) => {
+ fail(err);
+ done(err);
+ });
+ }, 10000);
});
@@ -821,9 +883,10 @@ describe('NavController', () => {
expect(nav.getByIndex(0).component).toEqual(MockView3);
done();
}).catch((err: Error) => {
+ fail(err);
done(err);
});
- });
+ }, 10000);
it('should set a ViewController as the root when its the middle view, with transition', (done: Function) => {
let view1 = mockView(MockView1);
@@ -873,9 +936,10 @@ describe('NavController', () => {
done();
}).catch((err: Error) => {
+ fail(err);
done(err);
});
- });
+ }, 10000);
it('should set a ViewController as the root when its the first view, with transition', (done: Function) => {
let view1 = mockView(MockView1);
@@ -925,9 +989,10 @@ describe('NavController', () => {
done();
}).catch((err: Error) => {
+ fail(err);
done(err);
});
- });
+ }, 10000);
it('should set a page component as the root, with transition', (done: Function) => {
let view1 = mockView(MockView1);
@@ -953,9 +1018,10 @@ describe('NavController', () => {
expect(nav.getByIndex(0).component).toEqual(MockView4);
done();
}).catch((err: Error) => {
+ fail(err);
done(err);
});
- });
+ }, 10000);
});
describe('setPages', () => {
@@ -982,9 +1048,10 @@ describe('NavController', () => {
expect(nav.getByIndex(1).component).toEqual(MockView5);
done();
}).catch((err: Error) => {
+ fail(err);
done(err);
});
- });
+ }, 10000);
});
diff --git a/src/navigation/test/overlay-proxy.spec.ts b/src/navigation/test/overlay-proxy.spec.ts
index 16693e5c7c..79b899ffa4 100644
--- a/src/navigation/test/overlay-proxy.spec.ts
+++ b/src/navigation/test/overlay-proxy.spec.ts
@@ -16,6 +16,7 @@ describe('Overlay Proxy', () => {
expect(instance.overlay.dismiss).toHaveBeenCalled();
done();
}).catch((err: Error) => {
+ fail(err);
done(err);
});
});
@@ -69,6 +70,7 @@ describe('Overlay Proxy', () => {
expect(knownOverlay.onWillDismiss).toHaveBeenCalledWith(handler);
done();
}).catch((err: Error) => {
+ fail(err);
done(err);
});
});
@@ -91,6 +93,7 @@ describe('Overlay Proxy', () => {
expect(deepLinker.getComponentFromName).not.toHaveBeenCalled();
done();
}).catch((err: Error) => {
+ fail(err);
done(err);
});
});
@@ -112,6 +115,7 @@ describe('Overlay Proxy', () => {
expect(deepLinker.getComponentFromName).toHaveBeenCalledWith(componentName);
done();
}).catch((err: Error) => {
+ fail(err);
done(err);
});
});
diff --git a/src/navigation/view-controller.ts b/src/navigation/view-controller.ts
index b5591f5557..4996028c93 100644
--- a/src/navigation/view-controller.ts
+++ b/src/navigation/view-controller.ts
@@ -541,26 +541,24 @@ export class ViewController {
/**
* @hidden
*/
- _lifecycleTest(lifecycle: string): boolean | Promise {
+ _lifecycleTest(lifecycle: string): Promise {
const instance = this.instance;
const methodName = 'ionViewCan' + lifecycle;
if (instance && instance[methodName]) {
try {
var result = instance[methodName]();
- if (result === false) {
- return false;
- } else if (result instanceof Promise) {
+ if (result instanceof Promise) {
return result;
} else {
- return true;
+ // Any value but explitic false, should be true
+ return Promise.resolve(result !== false);
}
} catch (e) {
- console.error(`${this.name} ${methodName} error: ${e.message}`);
- return false;
+ return Promise.reject(`${this.name} ${methodName} error: ${e.message}`);
}
}
- return true;
+ return Promise.resolve(true);
}
_lifecycle(lifecycle: string) {
diff --git a/src/transitions/transition-controller.ts b/src/transitions/transition-controller.ts
index cc7ba3468f..93004f2938 100644
--- a/src/transitions/transition-controller.ts
+++ b/src/transitions/transition-controller.ts
@@ -20,12 +20,12 @@ export class TransitionController {
constructor(public plt: Platform, private _config: Config) {}
getRootTrnsId(nav: NavControllerBase): number {
- let parent = nav.parent;
- while (parent) {
- if (isPresent(parent._trnsId)) {
- return parent._trnsId;
+ nav = nav.parent;
+ while (nav) {
+ if (isPresent(nav._trnsId)) {
+ return nav._trnsId;
}
- parent = parent.parent;
+ nav = nav.parent;
}
return null;
}
diff --git a/src/transitions/transition.ts b/src/transitions/transition.ts
index 0847b970b8..fad72a7141 100644
--- a/src/transitions/transition.ts
+++ b/src/transitions/transition.ts
@@ -24,7 +24,12 @@ export class Transition extends Animation {
parent: Transition;
trnsId: number;
- constructor(plt: Platform, public enteringView: ViewController, public leavingView: ViewController, opts: AnimationOptions) {
+ constructor(
+ plt: Platform,
+ public enteringView: ViewController,
+ public leavingView: ViewController,
+ opts: AnimationOptions
+ ) {
super(plt, null, opts);
}
@@ -34,13 +39,12 @@ export class Transition extends Animation {
this._trnsStart = trnsStart;
}
- isRoot(): boolean {
- return !this.parent;
- }
-
start() {
this._trnsStart && this._trnsStart();
this._trnsStart = null;
+
+ // bubble up start
+ this.parent && this.parent.start();
}
destroy() {
diff --git a/src/util/test/module-loader.spec.ts b/src/util/test/module-loader.spec.ts
index b53c3465ff..32ecc0bdf6 100644
--- a/src/util/test/module-loader.spec.ts
+++ b/src/util/test/module-loader.spec.ts
@@ -19,7 +19,8 @@ describe('module-loader', () => {
promise.then((response) => {
expect(ngModuleLoader.load).toHaveBeenCalledWith(pathPrefix, exportSuffix);
}).catch((err: Error) => {
- done(err);
+ fail(err);
+ done(err);
});
});