Skip to content

Commit

Permalink
fix(confirmLeave): update current route's history blocking after "add…
Browse files Browse the repository at this point in the history
…Routes" (#359)

* test(confirmLeave): ensure "addRoutes" updates current route's history blocking

* fix(confirmLeave): update current route's history blocking after "addRoutes"
  • Loading branch information
artkravchenko authored and ScriptedAlchemy committed Jul 29, 2019
1 parent 2da8598 commit a8f3bb3
Show file tree
Hide file tree
Showing 3 changed files with 182 additions and 4 deletions.
155 changes: 154 additions & 1 deletion __tests__/pure-utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import pathToAction from '../src/pure-utils/pathToAction'
import actionToPath from '../src/pure-utils/actionToPath'
import changePageTitle from '../src/pure-utils/changePageTitle'

import { NOT_FOUND } from '../src/index'
import { NOT_FOUND, addRoutes } from '../src/index'

beforeEach(() => {
window.SSRtest = false
Expand Down Expand Up @@ -510,6 +510,159 @@ describe('confirmLeave()', () => {
expect(history.location.pathname).toEqual('/first')
})

it('can block leaving after addRoutes if confirmLeave was missing on init', () => {
const firstRouteName = 'FIRST'

const firstRouteOptions = {
path: '/first'
}

const routesMap = {
[firstRouteName]: firstRouteOptions,
SECOND: '/second'
}

const displayConfirmLeave = jest.fn()
const options = { displayConfirmLeave }
const { store, history } = setupAll('/first', options, { routesMap })
const confirmLeave = jest.fn((state, action) => 'blocked')

store.dispatch(
addRoutes({
[firstRouteName]: {
...firstRouteOptions,
confirmLeave
}
})
)

store.dispatch({ type: 'SECOND' })

const { type } = store.getState().location
expect(type).toEqual(firstRouteName)
expect(displayConfirmLeave).toBeCalled()
expect(history.location.pathname).toEqual('/first')
expect(confirmLeave).toBeCalled()
})

it('can block leaving after addRoutes if confirmLeave was passing on init', () => {
const firstRouteName = 'FIRST'

const firstRouteOptions = {
path: '/first'
}

const prevConfirmLeave = jest.fn((state, action) => undefined)
const nextConfirmLeave = jest.fn((state, action) => 'blocked')

const routesMap = {
[firstRouteName]: {
...firstRouteOptions,
confirmLeave: prevConfirmLeave
},
SECOND: '/second'
}

const displayConfirmLeave = jest.fn()
const options = { displayConfirmLeave }
const { store, history } = setupAll('/first', options, { routesMap })

store.dispatch(
addRoutes({
[firstRouteName]: {
...firstRouteOptions,
confirmLeave: nextConfirmLeave
}
})
)

store.dispatch({ type: 'SECOND' })

const { type } = store.getState().location
expect(type).toEqual(firstRouteName)
expect(displayConfirmLeave).toBeCalled()
expect(history.location.pathname).toEqual('/first')
expect(prevConfirmLeave).not.toBeCalled()
expect(nextConfirmLeave).toBeCalled()
})

it('can unblock leaving after addRoutes removing blocking confirmLeave', () => {
const firstRouteName = 'FIRST'

const firstRouteOptions = {
path: '/first'
}

const confirmLeave = jest.fn((state, action) => 'blocked')

const routesMap = {
[firstRouteName]: {
...firstRouteOptions,
confirmLeave
},
SECOND: '/second'
}

const displayConfirmLeave = jest.fn()
const options = { displayConfirmLeave }
const { store, history } = setupAll('/first', options, { routesMap })

store.dispatch(
addRoutes({
[firstRouteName]: firstRouteOptions
})
)

store.dispatch({ type: 'SECOND' })

const { type } = store.getState().location
expect(type).toEqual('SECOND')
expect(displayConfirmLeave).not.toBeCalled()
expect(history.location.pathname).toEqual('/second')
expect(confirmLeave).not.toBeCalled()
})

it('can unblock leaving after addRoutes if confirmLeave was blocking on init', () => {
const firstRouteName = 'FIRST'

const firstRouteOptions = {
path: '/first'
}

const prevConfirmLeave = jest.fn((state, action) => 'blocked')
const nextConfirmLeave = jest.fn((state, action) => undefined)

const routesMap = {
[firstRouteName]: {
...firstRouteOptions,
confirmLeave: prevConfirmLeave
},
SECOND: '/second'
}

const displayConfirmLeave = jest.fn()
const options = { displayConfirmLeave }
const { store, history } = setupAll('/first', options, { routesMap })

store.dispatch(
addRoutes({
[firstRouteName]: {
...firstRouteOptions,
confirmLeave: nextConfirmLeave
}
})
)

store.dispatch({ type: 'SECOND' })

const { type } = store.getState().location
expect(type).toEqual('SECOND')
expect(displayConfirmLeave).not.toBeCalled()
expect(history.location.pathname).toEqual('/second')
expect(prevConfirmLeave).not.toBeCalled()
expect(nextConfirmLeave).toBeCalled()
})

it('can leave throws (React Native where window.confirm does not exist)', () => {
global.confirm = undefined

Expand Down
29 changes: 27 additions & 2 deletions src/connectRoutes.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import pathnamePlusSearch from './pure-utils/pathnamePlusSearch'
import canUseDom from './pure-utils/canUseDom'

import {
clearBlocking,
createConfirm,
confirmUI,
setDisplayConfirmLeave,
Expand Down Expand Up @@ -230,8 +231,32 @@ export default (routesMap: RoutesMap = {}, options: Options = {}) => {

// code-splitting functionliaty to add routes after store is initially configured
if (action.type === ADD_ROUTES) {
const { type } = selectLocationState(store.getState())
const route = routesMap[type]

routesMap = { ...routesMap, ...action.payload.routes }
return next(action)

const result = next(action)
const nextRoute = routesMap[type]

if (route !== nextRoute) {
if (_confirm !== null) {
clearBlocking()
}

if (typeof nextRoute === 'object' && nextRoute.confirmLeave) {
_confirm = createConfirm(
nextRoute.confirmLeave,
store,
selectLocationState,
history,
querySerializer,
() => (_confirm = null)
)
}
}

return result
}

// navigation transformation specific to React Navigation
Expand Down Expand Up @@ -571,7 +596,7 @@ export default (routesMap: RoutesMap = {}, options: Options = {}) => {
_selectLocationState = selectLocationState

let _initialDispatch
let _confirm
let _confirm = null

_updateScroll = (performedByUser: boolean = true) => {
if (scrollBehavior) {
Expand Down
2 changes: 1 addition & 1 deletion src/pure-utils/confirmLeave.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ let _unblock
let _removeConfirmBlocking
let _displayConfirmLeave

const clearBlocking = () => {
export const clearBlocking = () => {
_unblock && _unblock()
_removeConfirmBlocking && _removeConfirmBlocking()
}
Expand Down

0 comments on commit a8f3bb3

Please sign in to comment.