mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-08-19 19:57:22 +08:00
fix(navcontroller): lazy loading is queued
This commit is contained in:
@ -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();
|
||||
}
|
||||
|
@ -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 () {};
|
||||
|
@ -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.
|
||||
*/
|
||||
|
@ -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', () => {
|
||||
|
@ -42,7 +42,7 @@
|
||||
</ion-item>
|
||||
<ion-item>
|
||||
<ion-label>Toggle Can Leave</ion-label>
|
||||
<ion-toggle (click)="canLeave = !canLeave"></ion-toggle>
|
||||
<ion-toggle [(ngModel)]="canLeave"></ion-toggle>
|
||||
</ion-item>
|
||||
<button ion-item (click)="viewDismiss()">View Dismiss</button>
|
||||
<button ion-item (click)="quickPush()">New push during transition</button>
|
||||
|
@ -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);
|
||||
});
|
||||
});
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -162,7 +162,6 @@ describe('Tabs', () => {
|
||||
it('should get the tab', () => {
|
||||
var tabs = mockTabs();
|
||||
var tab0 = mockTab(tabs);
|
||||
tab0.setRoot(<any>{});
|
||||
var tab1 = mockTab(tabs);
|
||||
|
||||
expect(tabs.getIndex(tab0)).toEqual(0);
|
||||
|
@ -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<any> {
|
||||
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<any> {
|
||||
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<any> {
|
||||
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<any> {
|
||||
return this._queueTrns({
|
||||
insertStart: insertIndex,
|
||||
insertViews: [{ page: page, params: params }],
|
||||
opts: opts,
|
||||
}, done);
|
||||
}
|
||||
|
||||
insertPages(insertIndex: number, insertPages: any[], opts?: NavOptions, done?: Function): Promise<any> {
|
||||
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<any> {
|
||||
return this._queueTrns({
|
||||
insertStart: insertIndex,
|
||||
insertViews: insertPages,
|
||||
opts: opts,
|
||||
}, done);
|
||||
}
|
||||
|
||||
pop(opts?: NavOptions, done?: Function): Promise<any> {
|
||||
pop(opts?: NavOptions, done?: () => void): Promise<any> {
|
||||
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<any> {
|
||||
popTo(indexOrViewCtrl: any, opts?: NavOptions, done?: () => void): Promise<any> {
|
||||
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<any> {
|
||||
popToRoot(opts?: NavOptions, done?: () => void): Promise<any> {
|
||||
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<any> {
|
||||
remove(startIndex: number, removeCount: number = 1, opts?: NavOptions, done?: () => void): Promise<any> {
|
||||
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<any> {
|
||||
removeView(viewController: ViewController, opts?: NavOptions, done?: () => void): Promise<any> {
|
||||
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<any> {
|
||||
return convertToView(this._linker, pageOrViewCtrl, params).then((viewController) => {
|
||||
return this._setPages([viewController], opts, done);
|
||||
});
|
||||
setRoot(pageOrViewCtrl: any, params?: any, opts?: NavOptions, done?: () => void): Promise<any> {
|
||||
return this.setPages([{ page: pageOrViewCtrl, params: params }], opts, done);
|
||||
}
|
||||
|
||||
setPages(pages: any[], opts?: NavOptions, done?: Function): Promise<any> {
|
||||
return convertToViews(this._linker, pages).then(viewControllers => {
|
||||
return this._setPages(viewControllers, opts, done);
|
||||
});
|
||||
}
|
||||
|
||||
_setPages(viewControllers: ViewController[], opts?: NavOptions, done?: Function): Promise<any> {
|
||||
setPages(viewControllers: any[], opts?: NavOptions, done?: () => void): Promise<any> {
|
||||
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<any> {
|
||||
let promise: Promise<any>;
|
||||
let resolve: Function = done;
|
||||
let reject: Function = done;
|
||||
_queueTrns(ti: TransitionInstruction, done: () => void): Promise<boolean> {
|
||||
const promise = new Promise<boolean>((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<void> {
|
||||
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<void> {
|
||||
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<void> {
|
||||
// Only test canLeave/canEnter if there is transition
|
||||
if (!ti.requiresTransition) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
const promises: Promise<any>[] = [];
|
||||
|
||||
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<NavResult> {
|
||||
|
||||
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<void>(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<NavResult> {
|
||||
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) {
|
||||
|
@ -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<ViewController> {
|
||||
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<ViewController> {
|
||||
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<ViewController[]> {
|
||||
const views: Promise<ViewController>[] = [];
|
||||
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;
|
||||
|
@ -284,6 +284,7 @@ describe('DeepLinker', () => {
|
||||
expect(result.length).toEqual(1);
|
||||
done();
|
||||
}).catch((err: Error) => {
|
||||
fail(err);
|
||||
done(err);
|
||||
});
|
||||
});
|
||||
|
@ -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);
|
||||
|
||||
});
|
||||
|
||||
|
@ -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);
|
||||
});
|
||||
});
|
||||
|
@ -541,26 +541,24 @@ export class ViewController {
|
||||
/**
|
||||
* @hidden
|
||||
*/
|
||||
_lifecycleTest(lifecycle: string): boolean | Promise<any> {
|
||||
_lifecycleTest(lifecycle: string): Promise<any> {
|
||||
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) {
|
||||
|
@ -20,12 +20,12 @@ export class TransitionController {
|
||||
constructor(public plt: Platform, private _config: Config) {}
|
||||
|
||||
getRootTrnsId(nav: NavControllerBase): number {
|
||||
let parent = <NavControllerBase>nav.parent;
|
||||
while (parent) {
|
||||
if (isPresent(parent._trnsId)) {
|
||||
return parent._trnsId;
|
||||
nav = <NavControllerBase>nav.parent;
|
||||
while (nav) {
|
||||
if (isPresent(nav._trnsId)) {
|
||||
return nav._trnsId;
|
||||
}
|
||||
parent = parent.parent;
|
||||
nav = nav.parent;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
@ -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() {
|
||||
|
@ -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);
|
||||
});
|
||||
});
|
||||
|
||||
|
Reference in New Issue
Block a user