diff --git a/src/routers/__tests__/Routers-test.js b/src/routers/__tests__/Routers-test.js index 63929c5..38e3445 100644 --- a/src/routers/__tests__/Routers-test.js +++ b/src/routers/__tests__/Routers-test.js @@ -1,4 +1,4 @@ -/* eslint react/no-multi-comp:0 */ +/* eslint react/no-multi-comp:0, react/display-name:0 */ import React from 'react'; @@ -157,6 +157,70 @@ test('Handles deep action', () => { expect(state2 && state2.routes[1].index).toEqual(1); }); +test('Handles the navigate action with params', () => { + const FooTabNavigator = () =>
; + FooTabNavigator.router = TabRouter({ + Baz: { screen: () => }, + Boo: { screen: () => }, + }); + + const TestRouter = StackRouter({ + Foo: { screen: () => }, + Bar: { screen: FooTabNavigator }, + }); + const state = TestRouter.getStateForAction({ type: NavigationActions.INIT }); + const state2 = TestRouter.getStateForAction( + { + type: NavigationActions.NAVIGATE, + immediate: true, + routeName: 'Bar', + params: { foo: '42' }, + }, + state + ); + expect(state2 && state2.routes[1].params).toEqual({ foo: '42' }); + expect(state2 && state2.routes[1].routes).toEqual([ + { + key: 'Baz', + routeName: 'Baz', + params: { foo: '42' }, + }, + { + key: 'Boo', + routeName: 'Boo', + params: { foo: '42' }, + }, + ]); +}); + +test('Handles the setParams action', () => { + const FooTabNavigator = () => ; + FooTabNavigator.router = TabRouter({ + Baz: { screen: () => }, + }); + const TestRouter = StackRouter({ + Foo: { screen: FooTabNavigator }, + Bar: { screen: () => }, + }); + const state = TestRouter.getStateForAction({ type: NavigationActions.INIT }); + const state2 = TestRouter.getStateForAction( + { + type: NavigationActions.SET_PARAMS, + params: { name: 'foobar' }, + key: 'Baz', + }, + state + ); + expect(state2 && state2.index).toEqual(0); + expect(state2 && state2.routes[0].routes).toEqual([ + { + key: 'Baz', + routeName: 'Baz', + params: { name: 'foobar' }, + }, + ]); +}); + test('Supports lazily-evaluated getScreen', () => { const BarView = () => ; const FooTabNavigator = () => ; @@ -249,3 +313,62 @@ test('Does not switch tab index when TabRouter child handles COMPLETE_NAVIGATION expect(stateAfterCompleteTransition.index).toEqual(1); expect(stateAfterSetParams.index).toEqual(1); }); + +test('Inner actions are only unpacked if the current tab matches', () => { + const PlainScreen = () => ; + const ScreenA = () => ; + const ScreenB = () => ; + ScreenB.router = StackRouter({ + Baz: { screen: PlainScreen }, + Zoo: { screen: PlainScreen }, + }); + ScreenA.router = StackRouter({ + Bar: { screen: PlainScreen }, + Boo: { screen: ScreenB }, + }); + const TestRouter = TabRouter({ + Foo: { screen: ScreenA }, + }); + const screenApreState = { + index: 0, + key: 'Init', + isTransitioning: false, + routeName: 'Foo', + routes: [{ key: 'Init', routeName: 'Bar' }], + }; + const preState = { + index: 0, + isTransitioning: false, + routes: [screenApreState], + }; + + const comparable = state => { + let result = {}; + if (typeof state.routeName === 'string') { + result = { ...result, routeName: state.routeName }; + } + if (state.routes instanceof Array) { + result = { + ...result, + routes: state.routes.map(comparable), + }; + } + return result; + }; + + const action = NavigationActions.navigate({ + routeName: 'Boo', + action: NavigationActions.navigate({ routeName: 'Zoo' }), + }); + + const expectedState = ScreenA.router.getStateForAction( + action, + screenApreState + ); + const state = TestRouter.getStateForAction(action, preState); + const innerState = state ? state.routes[0] : state; + + expect(expectedState && comparable(expectedState)).toEqual( + innerState && comparable(innerState) + ); +}); diff --git a/src/routers/__tests__/StackRouter-test.js b/src/routers/__tests__/StackRouter-test.js index 4e3780b..a3c1983 100644 --- a/src/routers/__tests__/StackRouter-test.js +++ b/src/routers/__tests__/StackRouter-test.js @@ -5,7 +5,6 @@ import React from 'react'; import StackRouter from '../StackRouter'; import StackActions from '../StackActions'; import NavigationActions from '../../NavigationActions'; -import TabRouter from '../TabRouter'; import { _TESTING_ONLY_normalize_keys } from '../KeyGenerator'; beforeEach(() => { @@ -484,6 +483,44 @@ describe('StackRouter', () => { expect(state3 && state3.index).toEqual(0); }); + test('pop action works as expected', () => { + const TestRouter = StackRouter({ + foo: { screen: () => }, + bar: { screen: () => }, + }); + + const state = { + index: 3, + isTransitioning: false, + routes: [ + { key: 'A', routeName: 'foo' }, + { key: 'B', routeName: 'bar', params: { bazId: '321' } }, + { key: 'C', routeName: 'foo' }, + { key: 'D', routeName: 'bar' }, + ], + }; + const poppedState = TestRouter.getStateForAction(StackActions.pop(), state); + expect(poppedState.routes.length).toBe(3); + expect(poppedState.index).toBe(2); + expect(poppedState.isTransitioning).toBe(true); + + const poppedState2 = TestRouter.getStateForAction( + StackActions.pop({ n: 2, immediate: true }), + state + ); + expect(poppedState2.routes.length).toBe(2); + expect(poppedState2.index).toBe(1); + expect(poppedState2.isTransitioning).toBe(false); + + const poppedState3 = TestRouter.getStateForAction( + StackActions.pop({ n: 5 }), + state + ); + expect(poppedState3.routes.length).toBe(1); + expect(poppedState3.index).toBe(0); + expect(poppedState3.isTransitioning).toBe(true); + }); + test('popToTop works as expected', () => { const TestRouter = StackRouter({ foo: { screen: () => }, @@ -1081,13 +1118,8 @@ describe('StackRouter', () => { test('Handles the setParams action with nested routers', () => { const ChildNavigator = () => ; - const GrandChildNavigator = () => ; - GrandChildNavigator.router = StackRouter({ - Quux: { screen: () => }, - Corge: { screen: () => }, - }); - ChildNavigator.router = TabRouter({ - Baz: { screen: GrandChildNavigator }, + ChildNavigator.router = StackRouter({ + Baz: { screen: () => }, Qux: { screen: () => }, }); const router = StackRouter({ @@ -1104,10 +1136,10 @@ describe('StackRouter', () => { state ); expect(state2 && state2.index).toEqual(0); - expect(state2 && state2.routes[0].routes[0].routes).toEqual([ + expect(state2 && state2.routes[0].routes).toEqual([ { key: 'id-0', - routeName: 'Quux', + routeName: 'Baz', params: { name: 'foobar' }, }, ]); @@ -1193,7 +1225,7 @@ describe('StackRouter', () => { }); test('Handles the reset action with nested Router', () => { - const ChildRouter = TabRouter({ + const ChildRouter = StackRouter({ baz: { screen: () => , }, @@ -1214,6 +1246,7 @@ describe('StackRouter', () => { const state2 = router.getStateForAction( { type: StackActions.RESET, + key: null, actions: [ { type: NavigationActions.NAVIGATE, @@ -1445,42 +1478,6 @@ describe('StackRouter', () => { }); }); - test('Handles the navigate action with params and nested TabRouter', () => { - const ChildNavigator = () => ; - ChildNavigator.router = TabRouter({ - Baz: { screen: () => }, - Boo: { screen: () => }, - }); - - const router = StackRouter({ - Foo: { screen: () => }, - Bar: { screen: ChildNavigator }, - }); - const state = router.getStateForAction({ type: NavigationActions.INIT }); - const state2 = router.getStateForAction( - { - type: NavigationActions.NAVIGATE, - immediate: true, - routeName: 'Bar', - params: { foo: '42' }, - }, - state - ); - expect(state2 && state2.routes[1].params).toEqual({ foo: '42' }); - expect(state2 && state2.routes[1].routes).toEqual([ - { - key: 'Baz', - routeName: 'Baz', - params: { foo: '42' }, - }, - { - key: 'Boo', - routeName: 'Boo', - params: { foo: '42' }, - }, - ]); - }); - test('Handles empty URIs', () => { const router = StackRouter( { diff --git a/src/routers/__tests__/TabRouter-test.js b/src/routers/__tests__/TabRouter-test.js index 8ca6625..eef6f51 100644 --- a/src/routers/__tests__/TabRouter-test.js +++ b/src/routers/__tests__/TabRouter-test.js @@ -2,7 +2,6 @@ import React from 'react'; import TabRouter from '../TabRouter'; -import StackRouter from '../StackRouter'; import StackActions from '../../routers/StackActions'; import NavigationActions from '../../NavigationActions'; @@ -695,53 +694,15 @@ describe('TabRouter', () => { expect(state2).toEqual(state0); }); - test('pop action works as expected', () => { - const TestRouter = StackRouter({ - foo: { screen: () => }, - bar: { screen: () => }, - }); - - const state = { - index: 3, - isTransitioning: false, - routes: [ - { key: 'A', routeName: 'foo' }, - { key: 'B', routeName: 'bar', params: { bazId: '321' } }, - { key: 'C', routeName: 'foo' }, - { key: 'D', routeName: 'bar' }, - ], - }; - const poppedState = TestRouter.getStateForAction(StackActions.pop(), state); - expect(poppedState.routes.length).toBe(3); - expect(poppedState.index).toBe(2); - expect(poppedState.isTransitioning).toBe(true); - - const poppedState2 = TestRouter.getStateForAction( - StackActions.pop({ n: 2, immediate: true }), - state - ); - expect(poppedState2.routes.length).toBe(2); - expect(poppedState2.index).toBe(1); - expect(poppedState2.isTransitioning).toBe(false); - - const poppedState3 = TestRouter.getStateForAction( - StackActions.pop({ n: 5 }), - state - ); - expect(poppedState3.routes.length).toBe(1); - expect(poppedState3.index).toBe(0); - expect(poppedState3.isTransitioning).toBe(true); - }); - test('Inner actions are only unpacked if the current tab matches', () => { const PlainScreen = () => ; const ScreenA = () => ; const ScreenB = () => ; - ScreenB.router = StackRouter({ + ScreenB.router = TabRouter({ Baz: { screen: PlainScreen }, Zoo: { screen: PlainScreen }, }); - ScreenA.router = StackRouter({ + ScreenA.router = TabRouter({ Bar: { screen: PlainScreen }, Boo: { screen: ScreenB }, }); @@ -750,10 +711,10 @@ describe('TabRouter', () => { }); const screenApreState = { index: 0, - key: 'Init', + key: 'Foo', isTransitioning: false, routeName: 'Foo', - routes: [{ key: 'Init', routeName: 'Bar' }], + routes: [{ key: 'Bar', routeName: 'Bar' }], }; const preState = { index: 0, @@ -779,7 +740,6 @@ describe('TabRouter', () => { routeName: 'Boo', action: NavigationActions.navigate({ routeName: 'Zoo' }), }); - const expectedState = ScreenA.router.getStateForAction( action, screenApreState @@ -787,8 +747,25 @@ describe('TabRouter', () => { const state = router.getStateForAction(action, preState); const innerState = state ? state.routes[0] : state; + expect(innerState.routes[1].index).toEqual(1); expect(expectedState && comparable(expectedState)).toEqual( innerState && comparable(innerState) ); + + const noMatchAction = NavigationActions.navigate({ + routeName: 'Qux', + action: NavigationActions.navigate({ routeName: 'Zoo' }), + }); + const expectedState2 = ScreenA.router.getStateForAction( + noMatchAction, + screenApreState + ); + const state2 = router.getStateForAction(noMatchAction, preState); + const innerState2 = state2 ? state2.routes[0] : state2; + + expect(innerState2.routes[1].index).toEqual(0); + expect(expectedState2 && comparable(expectedState2)).toEqual( + innerState2 && comparable(innerState2) + ); }); });