Skip to content

Commit

Permalink
add source maps, test for scroll restoration
Browse files Browse the repository at this point in the history
  • Loading branch information
kyeotic committed Jun 18, 2021
1 parent c087fd4 commit 79e10a1
Show file tree
Hide file tree
Showing 4 changed files with 46 additions and 7 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [2.3.1] - 2021-06-18
### Added
- Sourcemaps to published package
### Changed
- `useNavigationPrompt` now restores scroll position after undoing navigation

## [2.3.0] - 2021-06-18
### Changed
- `useNavigationPrompt` now intercepts browser back/forward button navigation
Expand Down
4 changes: 3 additions & 1 deletion rollup.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ module.exports = [
globals: {
react: 'React'
},
interop: false
interop: false,
sourcemap: true
},
external: deps,
plugins: [
Expand Down Expand Up @@ -47,6 +48,7 @@ module.exports = [
file: 'dist/module.js',
format: 'esm',
name: 'raviger',
sourcemap: true,
globals: {
react: 'React'
}
Expand Down
6 changes: 5 additions & 1 deletion src/intercept.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,23 @@ let lastScroll = [0, 0]
export function shouldCancelNavigation() {
lastScroll = [window.scrollX, window.scrollY]
if (hasIntercepted) return hasUserCancelled

// confirm if any interceptors return true
return Array.from(interceptors).some(interceptor => {
const prompt = interceptor()
if (!prompt) return false

// cancel navigation if user declines
hasUserCancelled = !window.confirm(prompt) // eslint-disable-line no-alert

// track user response so that multiple interceptors don't prompt
hasIntercepted = true

// reset so that future navigation attempts are prompted
setTimeout(() => {
hasIntercepted = false
hasUserCancelled = false
}, 5)
}, 0)
return hasUserCancelled
})
}
Expand Down
37 changes: 32 additions & 5 deletions test/navigate.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,22 +8,26 @@ import {
} from '../src/main.js'

const originalConfirm = window.confirm
const originalScrollTo = window.scrollTo
const originalReplaceState = window.history.replaceState
const originalPushState = window.history.pushState

beforeEach(() => {
function restoreWindow() {
window.confirm = originalConfirm
window.scrollTo = originalScrollTo
window.history.replaceState = originalReplaceState
window.history.pushState = originalPushState
}

beforeEach(() => {
restoreWindow()
act(() => navigate('/'))
})

afterEach(async () => {
window.confirm = originalConfirm
window.history.replaceState = originalReplaceState
window.history.pushState = originalPushState
restoreWindow()
// We must wait for the intercept reset op
return new Promise(resolve => setTimeout(() => resolve(), 7))
return delay(5)
})

describe('useNavigate', () => {
Expand Down Expand Up @@ -182,6 +186,25 @@ describe('useNavigationPrompt', () => {
expect(document.location.pathname).toEqual('/')
})

test('popstate navigation restores scroll when prompt is declined', async () => {
window.confirm = jest.fn().mockImplementation(() => false)
window.scrollTo = jest.fn()
act(() => navigate('/'))
render(<Route block />)

// Modify scroll to check restoration
window.scrollX = 10
window.scrollY = 12

dispatchEvent(new PopStateEvent('popstate', null))

expect(document.location.pathname).toEqual('/')

// Wait for scroll restoration
await delay(10)
expect(window.scrollTo).toHaveBeenCalledWith(10, 12)
})

test('navigation is confirmed with custom prompt', async () => {
window.confirm = jest.fn().mockImplementation(() => false)
act(() => navigate('/'))
Expand Down Expand Up @@ -235,3 +258,7 @@ describe('navigate', () => {
jest.clearAllMocks()
})
})

function delay(ms) {
return new Promise(resolve => setTimeout(() => resolve(), ms))
}

0 comments on commit 79e10a1

Please sign in to comment.