diff --git a/core/src/components/nav/test/nav-controller.spec.ts b/core/src/components/nav/test/nav-controller.spec.ts index e59566aa60..6687e1512b 100644 --- a/core/src/components/nav/test/nav-controller.spec.ts +++ b/core/src/components/nav/test/nav-controller.spec.ts @@ -4,12 +4,7 @@ import { ViewController } from '../view-controller'; import { AnimationControllerImpl } from '../../animation-controller/animation-controller'; import { createConfigController } from '../../../global/config-controller'; -import { - DIRECTION_BACK, - DIRECTION_FORWARD, - NavOptions, - STATE_INITIALIZED, -} from '../nav-util'; +import { NavDirection, NavOptions, ViewState } from '../nav-util'; describe('NavController', () => { @@ -31,7 +26,7 @@ describe('NavController', () => { const hasCompleted = true; const requiresTransition = true; expect(push1Done).toHaveBeenCalledWith( - hasCompleted, requiresTransition, 'mock-view1', undefined, DIRECTION_FORWARD + hasCompleted, requiresTransition, 'mock-view1', undefined, NavDirection.forward ); expect(nav.length()).toEqual(1); expect(nav.getByIndex(0).component).toEqual(MockView1); @@ -40,7 +35,7 @@ describe('NavController', () => { await nav.push(mockView(MockView2), null, {animate: false}, push2Done); expect(push2Done).toHaveBeenCalledWith( - hasCompleted, requiresTransition, 'mock-view2', 'mock-view1', DIRECTION_FORWARD + hasCompleted, requiresTransition, 'mock-view2', 'mock-view1', NavDirection.forward ); expect(nav.length()).toEqual(2); @@ -51,7 +46,7 @@ describe('NavController', () => { await nav.push(mockView(MockView3), null, {animate: false}, push3Done); expect(push3Done).toHaveBeenCalledWith( - hasCompleted, requiresTransition, 'mock-view3', 'mock-view2', DIRECTION_FORWARD + hasCompleted, requiresTransition, 'mock-view3', 'mock-view2', NavDirection.forward ); expect(nav.length()).toEqual(3); expect(nav.getByIndex(0).component).toEqual(MockView1); @@ -61,7 +56,7 @@ describe('NavController', () => { // Push 4 await nav.push(mockView(MockView4), null, {animate: false}, push4Done); expect(push4Done).toHaveBeenCalledWith( - hasCompleted, requiresTransition, 'mock-view4', 'mock-view3', DIRECTION_FORWARD + hasCompleted, requiresTransition, 'mock-view4', 'mock-view3', NavDirection.forward ); expect(nav.length()).toEqual(4); expect(nav.getByIndex(0).component).toEqual(MockView1); @@ -72,7 +67,7 @@ describe('NavController', () => { // Pop 1 await nav.pop({animate: false}, pop1Done); expect(pop1Done).toHaveBeenCalledWith( - hasCompleted, requiresTransition, 'mock-view3', 'mock-view4', DIRECTION_BACK + hasCompleted, requiresTransition, 'mock-view3', 'mock-view4', NavDirection.back ); expect(nav.length()).toEqual(3); expect(nav.getByIndex(0).component).toEqual(MockView1); @@ -82,7 +77,7 @@ describe('NavController', () => { // Pop 2 await nav.pop({animate: false}, pop2Done); expect(pop2Done).toHaveBeenCalledWith( - hasCompleted, requiresTransition, 'mock-view2', 'mock-view3', DIRECTION_BACK + hasCompleted, requiresTransition, 'mock-view2', 'mock-view3', NavDirection.back ); expect(nav.length()).toEqual(2); expect(nav.getByIndex(0).component).toEqual(MockView1); @@ -91,7 +86,7 @@ describe('NavController', () => { // Pop 3 await nav.pop({animate: false}, pop3Done); expect(pop3Done).toHaveBeenCalledWith( - hasCompleted, requiresTransition, 'mock-view1', 'mock-view2', DIRECTION_BACK + hasCompleted, requiresTransition, 'mock-view1', 'mock-view2', NavDirection.back ); expect(nav.length()).toEqual(1); expect(nav.getByIndex(0).component).toEqual(MockView1); @@ -107,7 +102,7 @@ describe('NavController', () => { const hasCompleted = true; const requiresTransition = true; expect(trnsDone).toHaveBeenCalledWith( - hasCompleted, requiresTransition, 'mock-view1', undefined, DIRECTION_FORWARD + hasCompleted, requiresTransition, 'mock-view1', undefined, NavDirection.forward ); expect(nav.length()).toEqual(1); expect(nav.getByIndex(0).component).toEqual(MockView1); @@ -124,7 +119,7 @@ describe('NavController', () => { const hasCompleted = true; const requiresTransition = true; expect(trnsDone).toHaveBeenCalledWith( - hasCompleted, requiresTransition, 'mock-view2', 'mock-view1', DIRECTION_FORWARD + hasCompleted, requiresTransition, 'mock-view2', 'mock-view1', NavDirection.forward ); expect(nav.length()).toEqual(2); expect(nav.getByIndex(0).component).toEqual(MockView1); @@ -165,7 +160,7 @@ describe('NavController', () => { const hasCompleted = true; const requiresTransition = true; expect(trnsDone).toHaveBeenCalledWith( - hasCompleted, requiresTransition, 'mock-view', 'mock-view', DIRECTION_FORWARD + hasCompleted, requiresTransition, 'mock-view', 'mock-view', NavDirection.forward ); expect(nav.length()).toEqual(2); @@ -221,7 +216,7 @@ describe('NavController', () => { const hasCompleted = true; const requiresTransition = true; expect(trnsDone).toHaveBeenCalledWith( - hasCompleted, requiresTransition, 'mock-view2', 'mock-view1', DIRECTION_FORWARD + hasCompleted, requiresTransition, 'mock-view2', 'mock-view1', NavDirection.forward ); expect(nav.length()).toEqual(2); expect(nav._views[nav._views.length - 1].component).toEqual(MockView2); @@ -235,7 +230,7 @@ describe('NavController', () => { const hasCompleted = true; const requiresTransition = true; expect(trnsDone).toHaveBeenCalledWith( - hasCompleted, requiresTransition, 'mock-view2', 'mock-view1', DIRECTION_FORWARD + hasCompleted, requiresTransition, 'mock-view2', 'mock-view1', NavDirection.forward ); expect(nav.length()).toEqual(2); expect(nav._views[nav._views.length - 1].component).toEqual(MockView2); @@ -392,7 +387,7 @@ describe('NavController', () => { const hasCompleted = true; const requiresTransition = true; expect(trnsDone).toHaveBeenCalledWith( - hasCompleted, requiresTransition, 'mock-view1', 'mock-view2', DIRECTION_BACK + hasCompleted, requiresTransition, 'mock-view1', 'mock-view2', NavDirection.back ); expect(nav.length()).toEqual(1); expect(nav.getByIndex(0).component).toEqual(MockView1); @@ -416,7 +411,7 @@ describe('NavController', () => { const hasCompleted = true; const requiresTransition = true; expect(trnsDone).toHaveBeenCalledWith( - hasCompleted, requiresTransition, 'mock-view2', 'mock-view3', DIRECTION_BACK + hasCompleted, requiresTransition, 'mock-view2', 'mock-view3', NavDirection.back ); expect(nav.length()).toEqual(2); expect(nav.getByIndex(0).component).toEqual(MockView1); @@ -437,7 +432,7 @@ describe('NavController', () => { const hasCompleted = true; const requiresTransition = true; expect(trnsDone).toHaveBeenCalledWith( - hasCompleted, requiresTransition, 'mock-view2', 'mock-view4', DIRECTION_BACK + hasCompleted, requiresTransition, 'mock-view2', 'mock-view4', NavDirection.back ); expect(nav.length()).toEqual(2); expect(nav.getByIndex(0).component).toEqual(MockView1); @@ -499,7 +494,7 @@ describe('NavController', () => { const hasCompleted = true; const requiresTransition = true; expect(trnsDone).toHaveBeenCalledWith( - hasCompleted, requiresTransition, 'mock-view1', 'mock-view4', DIRECTION_BACK + hasCompleted, requiresTransition, 'mock-view1', 'mock-view4', NavDirection.back ); expect(nav.length()).toEqual(1); expect(nav.getByIndex(0).component).toEqual(MockView1); @@ -563,7 +558,7 @@ describe('NavController', () => { const hasCompleted = true; const requiresTransition = true; expect(trnsDone).toHaveBeenCalledWith( - hasCompleted, requiresTransition, 'mock-view1', 'mock-view4', DIRECTION_BACK + hasCompleted, requiresTransition, 'mock-view1', 'mock-view4', NavDirection.back ); expect(nav.length()).toEqual(1); expect(nav.getByIndex(0).component).toEqual(MockView1); @@ -779,7 +774,7 @@ describe('NavController', () => { const hasCompleted = true; const requiresTransition = true; expect(trnsDone).toHaveBeenCalledWith( - hasCompleted, requiresTransition, 'mock-view2', 'mock-view4', DIRECTION_BACK + hasCompleted, requiresTransition, 'mock-view2', 'mock-view4', NavDirection.back ); expect(nav.length()).toEqual(2); expect(nav.getByIndex(0).component).toEqual(MockView1); @@ -882,7 +877,7 @@ describe('NavController', () => { const hasCompleted = true; const requiresTransition = true; expect(trnsDone).toHaveBeenCalledWith( - hasCompleted, requiresTransition, 'mock-view2', 'mock-view3', DIRECTION_BACK + hasCompleted, requiresTransition, 'mock-view2', 'mock-view3', NavDirection.back ); expect(nav.length()).toEqual(1); expect(nav.getByIndex(0).component).toEqual(MockView2); @@ -930,7 +925,7 @@ describe('NavController', () => { const hasCompleted = true; const requiresTransition = true; expect(trnsDone).toHaveBeenCalledWith( - hasCompleted, requiresTransition, 'mock-view1', 'mock-view3', DIRECTION_BACK + hasCompleted, requiresTransition, 'mock-view1', 'mock-view3', NavDirection.back ); expect(nav.length()).toEqual(1); expect(nav.getByIndex(0).component).toEqual(MockView1); @@ -957,7 +952,7 @@ describe('NavController', () => { const hasCompleted = true; const requiresTransition = true; expect(trnsDone).toHaveBeenCalledWith( - hasCompleted, requiresTransition, 'mock-view4', 'mock-view3', DIRECTION_BACK + hasCompleted, requiresTransition, 'mock-view4', 'mock-view3', NavDirection.back ); expect(nav.length()).toEqual(1); expect(nav.getByIndex(0).component).toEqual(MockView4); @@ -987,7 +982,7 @@ describe('NavController', () => { const hasCompleted = true; const requiresTransition = true; expect(trnsDone).toHaveBeenCalledWith( - hasCompleted, requiresTransition, 'mock-view5', 'mock-view2', DIRECTION_BACK + hasCompleted, requiresTransition, 'mock-view5', 'mock-view2', NavDirection.back ); expect(nav.length()).toEqual(2); expect(nav.getByIndex(0).component).toEqual(MockView4); @@ -1133,7 +1128,7 @@ function mockNavController(): NavControllerBase { ? mockElement(enteringView.component) as HTMLElement : enteringView.element = enteringView.component as HTMLElement; } - enteringView._state = STATE_INITIALIZED; + enteringView._state = ViewState.Initialized; }; return nav; } diff --git a/core/src/components/router/test/e2e.spec.tsx b/core/src/components/router/test/e2e.spec.tsx index 87004e97fe..42d7b3f4f2 100644 --- a/core/src/components/router/test/e2e.spec.tsx +++ b/core/src/components/router/test/e2e.spec.tsx @@ -73,11 +73,11 @@ function conferenceAppRouting() { -function getRouteIDs(path: string, routes: RouteChain[]): string[] { +export function getRouteIDs(path: string, routes: RouteChain[]): string[] { return routerPathToChain(parsePath(path), routes).map(r => r.id); } -function getRoutePath(ids: RouteID[], routes: RouteChain[]): string { +export function getRoutePath(ids: RouteID[], routes: RouteChain[]): string { return generatePath(chainToPath(routerIDsToChain(ids, routes))); } diff --git a/core/src/components/router/test/matching.spec.tsx b/core/src/components/router/test/matching.spec.tsx index 4dc5ac7e0f..394cf3df3c 100644 --- a/core/src/components/router/test/matching.spec.tsx +++ b/core/src/components/router/test/matching.spec.tsx @@ -140,6 +140,44 @@ describe('routerPathToChain', () => { expect(routerPathToChain(['hola', 'adios'], routes)).toEqual(chain4); }); + it('should match the route with higher priority 2', () => { + + const chain1: RouteChain = [{ id: '1', path: ['categories', ':category_slug'], params: undefined }]; + const chain2: RouteChain = [{ id: '2', path: ['workouts', ':workout_slug'], params: undefined }]; + const chain3: RouteChain = [{ id: '3', path: ['workouts', ':workout_slug', 'time-select'], params: undefined }]; + const chain4: RouteChain = [{ id: '4', path: ['workouts', ':workout_slug', 'end-workout'], params: undefined }]; + const chain5: RouteChain = [{ id: '5', path: ['plans'], params: undefined }]; + const chain6: RouteChain = [{ id: '6', path: ['custom'], params: undefined }]; + const chain7: RouteChain = [{ id: '7', path: ['workouts', 'list'], params: undefined }]; + + const routes: RouteChain[] = [ + chain1, + chain2, + chain3, + chain4, + chain5, + chain6, + chain7 + ]; + // no match + expect(routerPathToChain(['categories'], routes)).toEqual(null); + expect(routerPathToChain(['workouts'], routes)).toEqual(null); + + expect(routerPathToChain(['plans'], routes)).toEqual(chain5); + expect(routerPathToChain(['custom'], routes)).toEqual(chain6); + expect(routerPathToChain(['workouts', 'list'], routes)).toEqual(chain7); + + expect(routerPathToChain(['workouts', 'hola'], routes)).toEqual( + [{ id: '2', path: ['workouts', ':workout_slug'], params: {'workout_slug': 'hola'} }] + ); + expect(routerPathToChain(['workouts', 'hello', 'time-select'], routes)).toEqual( + [{ id: '3', path: ['workouts', ':workout_slug', 'time-select'], params: {'workout_slug': 'hello'} }] + ); + expect(routerPathToChain(['workouts', 'hello2', 'end-workout'], routes)).toEqual( + [{ id: '4', path: ['workouts', ':workout_slug', 'end-workout'], params: {'workout_slug': 'hello2'} }] + ); + }); + it('should match the default route', () => { const chain1: RouteChain = [ { id: 'tabs', path: [''], params: undefined }, diff --git a/core/src/components/router/utils/matching.ts b/core/src/components/router/utils/matching.ts index 1ee5169684..c46864747a 100644 --- a/core/src/components/router/utils/matching.ts +++ b/core/src/components/router/utils/matching.ts @@ -122,8 +122,9 @@ export function routerPathToChain(path: string[], chains: RouteChain[]): RouteCh for (const chain of chains) { const matchedChain = matchesPath(path, chain); if (matchedChain !== null) { - if (matchedChain.length > matches) { - matches = matchedChain.length; + const score = computePriority(matchedChain); + if (score > matches) { + matches = score; match = matchedChain; } } @@ -131,6 +132,22 @@ export function routerPathToChain(path: string[], chains: RouteChain[]): RouteCh return match; } +export function computePriority(chain: RouteChain): number { + let score = 1; + let level = 1; + for (const route of chain) { + for (const path of route.path) { + if (path[0] === ':') { + score += Math.pow(1, level); + } else if (path !== '') { + score += Math.pow(2, level); + } + level++; + } + } + return score; +} + export class RouterSegments { private path: string[]; constructor(path: string[]) {