fix(vue): using router.go now shows correct view (#23773)

resolves #22563
This commit is contained in:
Liam DeBeasi
2021-08-17 08:53:55 -04:00
committed by GitHub
parent 6b18a89ac2
commit 621f4faa1a
10 changed files with 403 additions and 42 deletions

View File

@ -15,7 +15,7 @@ describe('Location History', () => {
locationHistory.add({ pathname: '/home' }); locationHistory.add({ pathname: '/home' });
locationHistory.add({ pathname: '/login', routerAction: 'replace' }); locationHistory.add({ pathname: '/login', routerAction: 'replace' });
const current = locationHistory.current(); const current = locationHistory.last();
expect(current.pathname).toEqual('/login'); expect(current.pathname).toEqual('/login');
}); });
@ -23,7 +23,7 @@ describe('Location History', () => {
locationHistory.add({ pathname: '/home' }); locationHistory.add({ pathname: '/home' });
locationHistory.add({ pathname: '/login', routerAction: 'pop' }); locationHistory.add({ pathname: '/login', routerAction: 'pop' });
const current = locationHistory.current(); const current = locationHistory.last();
expect(current.pathname).toEqual('/login'); expect(current.pathname).toEqual('/login');
expect(locationHistory.canGoBack(1)).toEqual(false); expect(locationHistory.canGoBack(1)).toEqual(false);
}); });
@ -33,7 +33,7 @@ describe('Location History', () => {
locationHistory.add({ pathname: '/login' }); locationHistory.add({ pathname: '/login' });
locationHistory.add({ pathname: '/logout', routerDirection: 'root' }); locationHistory.add({ pathname: '/logout', routerDirection: 'root' });
const current = locationHistory.current(); const current = locationHistory.last();
expect(current.pathname).toEqual('/logout'); expect(current.pathname).toEqual('/logout');
expect(locationHistory.canGoBack(1)).toEqual(false); expect(locationHistory.canGoBack(1)).toEqual(false);
}); });
@ -42,12 +42,12 @@ describe('Location History', () => {
locationHistory.add({ id: '1', pathname: '/tabs/tab1', tab: 'tab1' }); locationHistory.add({ id: '1', pathname: '/tabs/tab1', tab: 'tab1' });
locationHistory.add({ id: '2', pathname: '/tabs/tab2' }); locationHistory.add({ id: '2', pathname: '/tabs/tab2' });
const current = { ...locationHistory.current() }; const current = { ...locationHistory.last() };
current.tab = 'tab2'; current.tab = 'tab2';
locationHistory.update(current); locationHistory.update(current);
const getCurrentAgain = locationHistory.current(); const getCurrentAgain = locationHistory.last();
expect(getCurrentAgain.tab).toEqual('tab2'); expect(getCurrentAgain.tab).toEqual('tab2');
}); });
@ -73,7 +73,7 @@ describe('Location History', () => {
locationHistory.add({ pathname: '/home' }); locationHistory.add({ pathname: '/home' });
locationHistory.add({ pathname: '/login' }); locationHistory.add({ pathname: '/login' });
const current = locationHistory.current(); const current = locationHistory.last();
expect(current.pathname).toEqual('/login'); expect(current.pathname).toEqual('/login');
const previous = locationHistory.previous(); const previous = locationHistory.previous();

View File

@ -102,10 +102,39 @@ describe('View Stacks', () => {
const viewItemsAgain = viewStacks.getViewStack(2); const viewItemsAgain = viewStacks.getViewStack(2);
expect(viewItemsAgain).toEqual(undefined); expect(viewItemsAgain).toEqual(undefined);
}) });
it('should unmount orphaned views', () => {
const itemA = createRegisteredViewItem(viewStacks, 1, '/home/1', true);
const itemB = createRegisteredViewItem(viewStacks, 1, '/home/2', true);
const itemC = createRegisteredViewItem(viewStacks, 1, '/home/3', true);
const itemD = createRegisteredViewItem(viewStacks, 1, '/home/4', true);
viewStacks.unmountLeavingViews(1, itemA, itemD);
expect(itemB.mount).toEqual(false);
expect(itemB.ionPageElement).toEqual(undefined);
expect(itemB.ionRoute).toEqual(false);
expect(itemC.mount).toEqual(false);
expect(itemC.ionPageElement).toEqual(undefined);
expect(itemC.ionRoute).toEqual(false);
});
it('should remount intermediary views', () => {
const itemA = createRegisteredViewItem(viewStacks);
const itemB = createRegisteredViewItem(viewStacks);
const itemC = createRegisteredViewItem(viewStacks);
const itemD = createRegisteredViewItem(viewStacks);
viewStacks.mountIntermediaryViews(1, itemD, itemA);
expect(itemB.mount).toEqual(true);
expect(itemC.mount).toEqual(true);
});
}) })
const createRegisteredViewItem = (viewStacks, outletId = '1', route = `/home/${counter++}`) => { const createRegisteredViewItem = (viewStacks, outletId = '1', route = `/home/${counter++}`, mount = false) => {
const item = viewStacks.createViewItem( const item = viewStacks.createViewItem(
outletId, outletId,
() => {}, () => {},
@ -115,10 +144,15 @@ const createRegisteredViewItem = (viewStacks, outletId = '1', route = `/home/${c
viewStacks.add(item); viewStacks.add(item);
const ionPage = document.createElement('div'); if (mount) {
ionPage.classList.add('ion-page'); const ionPage = document.createElement('div');
ionPage.classList.add('ion-page');
viewStacks.registerIonPage(item, ionPage); viewStacks.registerIonPage(item, ionPage);
item.mount = true;
item.ionRoute = true;
}
return item; return item;
} }

View File

@ -102,8 +102,33 @@ export const createLocationHistory = () => {
return history; return history;
} }
const previous = () => locationHistory[locationHistory.length - 2] || current();
const current = () => locationHistory[locationHistory.length - 1]; const size = () => locationHistory.length;
const updateByHistoryPosition = (routeInfo: RouteInfo) => {
const existingRouteIndex = locationHistory.findIndex(r => r.position === routeInfo.position);
if (existingRouteIndex === -1) return;
locationHistory[existingRouteIndex].pathname = routeInfo.pathname;
}
/**
* Finds and returns the location history item
* given the state of browser's history API.
* This is useful when jumping around in browser
* history using router.go.
*/
const current = (initialHistory: number, currentHistory: number) => {
/**
* initialHistory does not always start at 0 if users navigated
* to app from another website, so doing this math lets us
* find the correct index in our locationHistory array.
*/
const index = currentHistory - initialHistory;
return locationHistory[index] || last();
}
const previous = () => locationHistory[locationHistory.length - 2] || last();
const last = () => locationHistory[locationHistory.length - 1];
const canGoBack = (deep: number = 1) => locationHistory.length > deep; const canGoBack = (deep: number = 1) => locationHistory.length > deep;
const getFirstRouteInfoForTab = (tab: string): RouteInfo | undefined => { const getFirstRouteInfoForTab = (tab: string): RouteInfo | undefined => {
@ -122,23 +147,41 @@ export const createLocationHistory = () => {
return undefined; return undefined;
} }
const findLastLocation = (routeInfo: RouteInfo): RouteInfo | undefined => { /**
* Finds and returns the previous view based upon
* what originally pushed it (pushedByRoute).
* When `delta` < -1 then we should just index into
* to array because the previous view that we want is not
* necessarily the view that pushed our current view.
* Additionally, when jumping around in history, we
* do not modify the locationHistory stack so we would
* not update pushedByRoute anyways.
*/
const findLastLocation = (routeInfo: RouteInfo, delta: number = -1): RouteInfo | undefined => {
const routeInfos = getTabsHistory(routeInfo.tab); const routeInfos = getTabsHistory(routeInfo.tab);
if (routeInfos) { if (routeInfos) {
for (let i = routeInfos.length - 2; i >= 0; i--) { if (delta < -1) {
const ri = routeInfos[i]; return routeInfos[routeInfos.length - 1 + delta];
if (ri) { } else {
if (ri.pathname === routeInfo.pushedByRoute) { for (let i = routeInfos.length - 2; i >= 0; i--) {
return ri; const ri = routeInfos[i];
if (ri) {
if (ri.pathname === routeInfo.pushedByRoute) {
return ri;
}
} }
} }
} }
} }
for (let i = locationHistory.length - 2; i >= 0; i--) { if (delta < -1) {
const ri = locationHistory[i]; return locationHistory[locationHistory.length - 1 + delta];
if (ri) { } else {
if (ri.pathname === routeInfo.pushedByRoute) { for (let i = locationHistory.length - 2; i >= 0; i--) {
return ri; const ri = locationHistory[i];
if (ri) {
if (ri.pathname === routeInfo.pushedByRoute) {
return ri;
}
} }
} }
} }
@ -147,6 +190,9 @@ export const createLocationHistory = () => {
return { return {
current, current,
updateByHistoryPosition,
size,
last,
previous, previous,
add, add,
canGoBack, canGoBack,

View File

@ -18,7 +18,7 @@ import {
import { AnimationBuilder } from '@ionic/vue'; import { AnimationBuilder } from '@ionic/vue';
export const createIonRouter = (opts: IonicVueRouterOptions, router: Router) => { export const createIonRouter = (opts: IonicVueRouterOptions, router: Router) => {
let currentNavigationInfo: NavigationInformation = { direction: undefined, action: undefined }; let currentNavigationInfo: NavigationInformation = { direction: undefined, action: undefined, delta: undefined };
/** /**
* Ionic Vue should only react to navigation * Ionic Vue should only react to navigation
@ -32,7 +32,7 @@ export const createIonRouter = (opts: IonicVueRouterOptions, router: Router) =>
router.afterEach((to: RouteLocationNormalized, _: RouteLocationNormalized, failure?: NavigationFailure) => { router.afterEach((to: RouteLocationNormalized, _: RouteLocationNormalized, failure?: NavigationFailure) => {
if (failure) return; if (failure) return;
const { direction, action } = currentNavigationInfo; const { direction, action, delta } = currentNavigationInfo;
/** /**
* When calling router.replace, we are not informed * When calling router.replace, we are not informed
@ -42,13 +42,26 @@ export const createIonRouter = (opts: IonicVueRouterOptions, router: Router) =>
* We need to use opts.history rather than window.history * We need to use opts.history rather than window.history
* because window.history will be undefined when using SSR. * because window.history will be undefined when using SSR.
*/ */
const replaceAction = opts.history.state.replaced ? 'replace' : undefined;
handleHistoryChange(to, action || replaceAction, direction);
currentNavigationInfo = { direction: undefined, action: undefined }; currentHistoryPosition = opts.history.state.position as number;
const replaceAction = opts.history.state.replaced ? 'replace' : undefined;
handleHistoryChange(to, action || replaceAction, direction, delta);
currentNavigationInfo = { direction: undefined, action: undefined, delta: undefined };
}); });
const locationHistory = createLocationHistory(); const locationHistory = createLocationHistory();
/**
* Keeping track of the history position
* allows us to determine if a user is pushing
* new pages or updating history via the forward
* and back browser buttons.
*/
const initialHistoryPosition = opts.history.state.position as number;
let currentHistoryPosition = opts.history.state.position as number;
let currentRouteInfo: RouteInfo; let currentRouteInfo: RouteInfo;
let incomingRouteParams: RouteParams; let incomingRouteParams: RouteParams;
let currentTab: string | undefined; let currentTab: string | undefined;
@ -78,14 +91,21 @@ export const createIonRouter = (opts: IonicVueRouterOptions, router: Router) =>
* router.beforeEach * router.beforeEach
*/ */
currentNavigationInfo = { currentNavigationInfo = {
action: info.type, delta: info.delta,
/**
* Both the browser forward and backward actions
* are considered "pop" actions, but when going forward
* we want to make sure the forward animation is used.
*/
action: (info.type === 'pop' && info.delta >= 1) ? 'push' : info.type,
direction: info.direction === '' ? 'forward' : info.direction direction: info.direction === '' ? 'forward' : info.direction
}; };
}); });
const handleNavigateBack = (defaultHref?: string, routerAnimation?: AnimationBuilder) => { const handleNavigateBack = (defaultHref?: string, routerAnimation?: AnimationBuilder) => {
// todo grab default back button href from config // todo grab default back button href from config
const routeInfo = locationHistory.current(); const routeInfo = locationHistory.current(initialHistoryPosition, currentHistoryPosition);
if (routeInfo && routeInfo.pushedByRoute) { if (routeInfo && routeInfo.pushedByRoute) {
const prevInfo = locationHistory.findLastLocation(routeInfo); const prevInfo = locationHistory.findLastLocation(routeInfo);
if (prevInfo) { if (prevInfo) {
@ -131,16 +151,23 @@ export const createIonRouter = (opts: IonicVueRouterOptions, router: Router) =>
} }
// TODO RouteLocationNormalized // TODO RouteLocationNormalized
const handleHistoryChange = (location: any, action?: RouteAction, direction?: RouteDirection) => { const handleHistoryChange = (
location: any,
action?: RouteAction,
direction?: RouteDirection,
delta?: number
) => {
let leavingLocationInfo: RouteInfo; let leavingLocationInfo: RouteInfo;
if (incomingRouteParams) { if (incomingRouteParams) {
if (incomingRouteParams.routerAction === 'replace') { if (incomingRouteParams.routerAction === 'replace') {
leavingLocationInfo = locationHistory.previous(); leavingLocationInfo = locationHistory.previous();
} else if (incomingRouteParams.routerAction === 'pop') {
leavingLocationInfo = locationHistory.current(initialHistoryPosition, currentHistoryPosition + 1);
} else { } else {
leavingLocationInfo = locationHistory.current(); leavingLocationInfo = locationHistory.current(initialHistoryPosition, currentHistoryPosition - 1);
} }
} else { } else {
leavingLocationInfo = locationHistory.current(); leavingLocationInfo = currentRouteInfo;
} }
if (!leavingLocationInfo) { if (!leavingLocationInfo) {
@ -160,9 +187,10 @@ export const createIonRouter = (opts: IonicVueRouterOptions, router: Router) =>
tab: currentTab tab: currentTab
} }
} else if (action === 'pop') { } else if (action === 'pop') {
const routeInfo = locationHistory.current(); const routeInfo = locationHistory.current(initialHistoryPosition, currentHistoryPosition - delta);
if (routeInfo && routeInfo.pushedByRoute) { if (routeInfo && routeInfo.pushedByRoute) {
const prevRouteInfo = locationHistory.findLastLocation(routeInfo); const prevRouteInfo = locationHistory.findLastLocation(routeInfo, delta);
incomingRouteParams = { incomingRouteParams = {
...prevRouteInfo, ...prevRouteInfo,
routerAction: 'pop', routerAction: 'pop',
@ -191,7 +219,6 @@ export const createIonRouter = (opts: IonicVueRouterOptions, router: Router) =>
...incomingRouteParams, ...incomingRouteParams,
lastPathname: leavingLocationInfo.pathname lastPathname: leavingLocationInfo.pathname
} }
locationHistory.add(routeInfo);
} else { } else {
const isPushed = incomingRouteParams.routerAction === 'push' && incomingRouteParams.routerDirection === 'forward'; const isPushed = incomingRouteParams.routerAction === 'push' && incomingRouteParams.routerDirection === 'forward';
@ -215,7 +242,7 @@ export const createIonRouter = (opts: IonicVueRouterOptions, router: Router) =>
const lastRoute = locationHistory.getCurrentRouteInfoForTab(routeInfo.tab); const lastRoute = locationHistory.getCurrentRouteInfoForTab(routeInfo.tab);
routeInfo.pushedByRoute = lastRoute?.pushedByRoute; routeInfo.pushedByRoute = lastRoute?.pushedByRoute;
} else if (routeInfo.routerAction === 'replace') { } else if (routeInfo.routerAction === 'replace') {
const currentRouteInfo = locationHistory.current(); const currentRouteInfo = locationHistory.last();
/** /**
* If going from /home to /child, then replacing from * If going from /home to /child, then replacing from
@ -232,8 +259,27 @@ export const createIonRouter = (opts: IonicVueRouterOptions, router: Router) =>
routeInfo.prevRouteLastPathname = currentRouteInfo?.lastPathname; routeInfo.prevRouteLastPathname = currentRouteInfo?.lastPathname;
} }
}
routeInfo.position = currentHistoryPosition;
const historySize = locationHistory.size();
const historyDiff = currentHistoryPosition - initialHistoryPosition;
/**
* If the size of location history is greater
* than the difference between the current history
* position and the initial history position
* then we are guaranteed to already have a history
* item for this route. In other words, a user
* is navigating within the history without pushing
* new items within the stack.
*/
if (historySize > historyDiff && routeInfo.tab === undefined) {
locationHistory.updateByHistoryPosition(routeInfo);
} else {
locationHistory.add(routeInfo); locationHistory.add(routeInfo);
} }
currentRouteInfo = routeInfo; currentRouteInfo = routeInfo;
} }
incomingRouteParams = undefined; incomingRouteParams = undefined;
@ -301,7 +347,7 @@ export const createIonRouter = (opts: IonicVueRouterOptions, router: Router) =>
const handleSetCurrentTab = (tab: string) => { const handleSetCurrentTab = (tab: string) => {
currentTab = tab; currentTab = tab;
const ri = { ...locationHistory.current() }; const ri = { ...locationHistory.last() };
if (ri.tab !== tab) { if (ri.tab !== tab) {
ri.tab = tab; ri.tab = tab;
locationHistory.update(ri); locationHistory.update(ri);
@ -313,7 +359,12 @@ export const createIonRouter = (opts: IonicVueRouterOptions, router: Router) =>
historyChangeListeners.push(cb); historyChangeListeners.push(cb);
} }
const getLeavingRouteInfo = () => {
return locationHistory.current(initialHistoryPosition, currentHistoryPosition);
}
return { return {
getLeavingRouteInfo,
handleNavigateBack, handleNavigateBack,
handleSetCurrentTab, handleSetCurrentTab,
getCurrentRouteInfo, getCurrentRouteInfo,

View File

@ -26,6 +26,7 @@ export interface RouteInfo {
params?: { [k: string]: any }; params?: { [k: string]: any };
pushedByRoute?: string; pushedByRoute?: string;
tab?: string; tab?: string;
position?: number;
} }
export interface RouteParams { export interface RouteParams {
@ -68,4 +69,5 @@ export interface ExternalNavigationOptions {
export interface NavigationInformation { export interface NavigationInformation {
action?: RouteAction; action?: RouteAction;
direction?: RouteDirection; direction?: RouteDirection;
delta?: number;
} }

View File

@ -156,7 +156,75 @@ export const createViewStacks = (router: Router) => {
return []; return [];
} }
/**
* Given a view stack and entering/leaving views,
* determine the position of each item in the stack.
* This is useful for removing/adding views in between
* the view items when navigating using router.go.
* Use this method instead of doing an `Array.findIndex`
* for both view items.
*/
const findViewIndex = (viewStack: ViewItem[], enteringViewItem: ViewItem, leavingViewItem: ViewItem) => {
let enteringIndex = -1;
let leavingIndex = -1;
for (let i = 0; i <= viewStack.length - 1; i++) {
const viewItem = viewStack[i];
if (viewItem === enteringViewItem) {
enteringIndex = i;
} else if (viewItem === leavingViewItem) {
leavingIndex = i;
}
if (enteringIndex > -1 && leavingIndex > -1) {
break;
}
}
return { enteringIndex, leavingIndex };
}
/**
* When navigating backwards, we need to clean up and
* leaving pages so that they are re-created if
* we ever navigate back to them. This is especially
* important when using router.go and stepping back
* multiple pages at a time.
*/
const unmountLeavingViews = (outletId: number, enteringViewItem: ViewItem, leavingViewItem: ViewItem) => {
const viewStack = viewStacks[outletId];
if (!viewStack) return;
const { enteringIndex: startIndex, leavingIndex: endIndex } = findViewIndex(viewStack, enteringViewItem, leavingViewItem);
for (let i = startIndex + 1; i < endIndex; i++) {
const viewItem = viewStack[i];
viewItem.mount = false;
viewItem.ionPageElement = undefined;
viewItem.ionRoute = false;
}
}
/**
* When navigating forward it is possible for
* developers to step forward over multiple views.
* The intermediary views need to be remounted so that
* swipe to go back works properly.
*/
const mountIntermediaryViews = (outletId: number, enteringViewItem: ViewItem, leavingViewItem: ViewItem) => {
const viewStack = viewStacks[outletId];
if (!viewStack) return;
const { enteringIndex: endIndex, leavingIndex: startIndex } = findViewIndex(viewStack, enteringViewItem, leavingViewItem);
for (let i = startIndex + 1; i < endIndex; i++) {
viewStack[i].mount = true;
}
}
return { return {
unmountLeavingViews,
mountIntermediaryViews,
clear, clear,
findViewItemByRouteInfo, findViewItemByRouteInfo,
findLeavingViewItemByRouteInfo, findLeavingViewItemByRouteInfo,

View File

@ -97,13 +97,13 @@ export const IonRouterOutlet = defineComponent({
* to respond to this gesture, so check * to respond to this gesture, so check
* to make sure the view is in the outlet we want. * to make sure the view is in the outlet we want.
*/ */
const routeInfo = ionRouter.getCurrentRouteInfo(); const routeInfo = ionRouter.getLeavingRouteInfo();
const enteringViewItem = viewStacks.findViewItemByRouteInfo({ pathname: routeInfo.pushedByRoute || '' }, id, usingDeprecatedRouteSetup); const enteringViewItem = viewStacks.findViewItemByRouteInfo({ pathname: routeInfo.pushedByRoute || '' }, id, usingDeprecatedRouteSetup);
return !!enteringViewItem; return !!enteringViewItem;
} }
const onStart = async () => { const onStart = async () => {
const routeInfo = ionRouter.getCurrentRouteInfo(); const routeInfo = ionRouter.getLeavingRouteInfo();
const { routerAnimation } = routeInfo; const { routerAnimation } = routeInfo;
const enteringViewItem = viewStacks.findViewItemByRouteInfo({ pathname: routeInfo.pushedByRoute || '' }, id, usingDeprecatedRouteSetup); const enteringViewItem = viewStacks.findViewItemByRouteInfo({ pathname: routeInfo.pushedByRoute || '' }, id, usingDeprecatedRouteSetup);
const leavingViewItem = viewStacks.findViewItemByRouteInfo(routeInfo, id, usingDeprecatedRouteSetup); const leavingViewItem = viewStacks.findViewItemByRouteInfo(routeInfo, id, usingDeprecatedRouteSetup);
@ -286,7 +286,10 @@ See https://ionicframework.com/docs/vue/navigation#ionpage for more information.
leavingViewItem.mount = false; leavingViewItem.mount = false;
leavingViewItem.ionPageElement = undefined; leavingViewItem.ionPageElement = undefined;
leavingViewItem.ionRoute = false; leavingViewItem.ionRoute = false;
viewStacks.unmountLeavingViews(id, enteringViewItem, leavingViewItem);
} }
} else {
viewStacks.mountIntermediaryViews(id, enteringViewItem, leavingViewItem);
} }
fireLifecycle(leavingViewItem.vueComponent, leavingViewItem.vueComponentRef, LIFECYCLE_DID_LEAVE); fireLifecycle(leavingViewItem.vueComponent, leavingViewItem.vueComponentRef, LIFECYCLE_DID_LEAVE);

View File

@ -1,5 +1,5 @@
<template> <template>
<ion-page> <ion-page data-pageid="inputs">
<ion-header :translucent="true"> <ion-header :translucent="true">
<ion-toolbar> <ion-toolbar>
<ion-buttons> <ion-buttons>

View File

@ -191,6 +191,131 @@ describe('Routing', () => {
cy.ionBackButtonHidden('home'); cy.ionBackButtonHidden('home');
}); });
it('should select correct view when using router.go()', () => {
cy.visit('http://localhost:8080');
cy.routerPush('/routing');
cy.ionPageVisible('routing');
cy.ionPageHidden('home');
cy.routerPush('/routing/abc');
cy.ionPageVisible('routingparameter');
cy.ionPageHidden('routing');
cy.routerGo(-2);
cy.ionPageVisible('home');
cy.ionPageDoesNotExist('routingparameter');
cy.routerGo(2);
cy.ionPageVisible('routingparameter');
cy.ionPageHidden('home');
cy.ionBackClick('routingparameter');
cy.ionPageDoesNotExist('routingparameter');
cy.ionPageVisible('routing');
})
it('should select correct view when traversing backward and forward through history', () => {
cy.visit('http://localhost:8080');
cy.routerPush('/routing');
cy.ionPageVisible('routing');
cy.ionPageHidden('home');
cy.routerPush('/routing/abc');
cy.ionPageVisible('routingparameter');
cy.ionPageHidden('routing');
cy.routerGo(-2);
cy.ionPageVisible('home');
cy.ionPageDoesNotExist('routingparameter');
cy.routerGo(1);
cy.ionPageHidden('home');
cy.ionPageVisible('routing');
cy.routerGo(1);
cy.ionPageHidden('routing');
cy.ionPageVisible('routingparameter');
cy.routerGo(-1);
cy.ionPageDoesNotExist('routingparameter');
cy.ionPageVisible('routing');
cy.routerGo(-1);
cy.ionPageDoesNotExist('routing');
cy.ionPageVisible('home');
})
it('should create new stack items when going back then pushing pages', () => {
cy.visit('http://localhost:8080');
cy.routerPush('/routing');
cy.ionPageVisible('routing');
cy.ionPageHidden('home');
cy.routerPush('/routing/abc');
cy.ionPageVisible('routingparameter');
cy.ionPageHidden('routing');
cy.routerGo(-2);
cy.ionPageVisible('home');
cy.ionPageDoesNotExist('routingparameter');
cy.routerPush('/inputs');
cy.ionPageHidden('home');
cy.ionPageVisible('inputs');
cy.ionBackClick('inputs');
cy.ionPageVisible('home');
cy.ionPageDoesNotExist('inputs');
})
it('should properly go back using ion-back-button after using router.go()', () => {
cy.visit('http://localhost:8080');
cy.routerPush('/routing');
cy.ionPageVisible('routing');
cy.ionPageHidden('home');
cy.routerPush('/routing/abc');
cy.ionPageVisible('routingparameter');
cy.ionPageHidden('routing');
cy.routerGo(-2);
cy.ionPageVisible('home');
cy.ionPageDoesNotExist('routingparameter');
cy.routerGo(2);
cy.ionPageVisible('routingparameter');
cy.ionPageHidden('home');
cy.ionBackClick('routingparameter');
cy.ionPageDoesNotExist('routingparameter');
cy.ionPageVisible('routing');
cy.ionBackClick('routing');
cy.ionPageDoesNotExist('routing');
cy.ionPageVisible('home');
});
it('should unmount views skipped over by using router.go with a negative value', () => {
cy.visit('http://localhost:8080');
cy.routerPush('/routing');
cy.ionPageVisible('routing');
cy.ionPageHidden('home');
cy.routerPush('/routing/abc');
cy.ionPageVisible('routingparameter');
cy.ionPageHidden('routing');
cy.routerGo(-2);
cy.ionPageVisible('home');
cy.ionPageDoesNotExist('routing');
cy.ionPageDoesNotExist('routingparameter');
})
}); });
describe('Routing - Swipe to Go Back', () => { describe('Routing - Swipe to Go Back', () => {
@ -215,4 +340,30 @@ describe('Routing - Swipe to Go Back', () => {
// TODO: Vue router does not go back in cypress with router.back() // TODO: Vue router does not go back in cypress with router.back()
//cy.ionPageDoesNotExist('navigation'); //cy.ionPageDoesNotExist('navigation');
}); });
it('swipe to go back should work when using router.go()', () => {
cy.visit('http://localhost:8080?ionic:mode=ios');
cy.routerPush('/routing');
cy.ionPageVisible('routing');
cy.ionPageHidden('home');
cy.routerPush('/routing/abc');
cy.ionPageVisible('routingparameter');
cy.ionPageHidden('routing');
cy.routerGo(-2);
cy.ionPageVisible('home');
cy.ionPageDoesNotExist('routingparameter');
cy.routerGo(2);
cy.ionPageVisible('routingparameter');
cy.ionPageHidden('home');
// TODO: This does not work yet
cy.ionSwipeToGoBack(true);
cy.ionPageDoesNotExist('routingparameter');
cy.ionPageVisible('routing');
})
}) })

View File

@ -77,6 +77,12 @@ Cypress.Commands.add('routerReplace', (path) => {
}); });
}); });
Cypress.Commands.add('routerGo', (n) => {
cy.window().then(win => {
win.debugRouter.go(n);
});
});
Cypress.Commands.add('ionBackButtonHidden', (pageId) => { Cypress.Commands.add('ionBackButtonHidden', (pageId) => {
cy.get(`div.ion-page[data-pageid=${pageId}]`) cy.get(`div.ion-page[data-pageid=${pageId}]`)
.should('be.visible', true) .should('be.visible', true)