From 077ec294dd9e034ac3d6d95bd052ad95c4ff7e91 Mon Sep 17 00:00:00 2001 From: Brenley Dueck Date: Sat, 17 Jan 2026 13:04:12 -0600 Subject: [PATCH] fix: useBlocker does not work with memoryHistory --- packages/history/src/index.ts | 7 +++ .../history/tests/createMemoryHistory.test.ts | 57 ++++++++++++++++++- 2 files changed, 63 insertions(+), 1 deletion(-) diff --git a/packages/history/src/index.ts b/packages/history/src/index.ts index 53e4aa1b7fb..8d70c60da55 100644 --- a/packages/history/src/index.ts +++ b/packages/history/src/index.ts @@ -593,6 +593,11 @@ export function createMemoryHistory( const getLocation = () => parseHref(entries[index]!, states[index]) + let blockers: Array = [] + const _getBlockers = () => blockers + const _setBlockers = (newBlockers: Array) => + (blockers = newBlockers) + return createHistory({ getLocation, getLength: () => entries.length, @@ -620,6 +625,8 @@ export function createMemoryHistory( index = Math.min(Math.max(index + n, 0), entries.length - 1) }, createHref: (path) => path, + getBlockers: _getBlockers, + setBlockers: _setBlockers, }) } diff --git a/packages/history/tests/createMemoryHistory.test.ts b/packages/history/tests/createMemoryHistory.test.ts index caddb96ac06..1a27c049198 100644 --- a/packages/history/tests/createMemoryHistory.test.ts +++ b/packages/history/tests/createMemoryHistory.test.ts @@ -1,4 +1,4 @@ -import { describe, expect, test } from 'vitest' +import { describe, expect, test, vi } from 'vitest' import { createMemoryHistory } from '../src' describe('createMemoryHistory', () => { @@ -76,4 +76,59 @@ describe('createMemoryHistory', () => { history.push('/c', { i: 3 }) expect((history.location.state as any).i).toBe(3) }) + + test('block prevents navigation', async () => { + const history = createMemoryHistory({ initialEntries: ['/'] }) + const blockerFn = vi.fn(() => true) // Always block + + const unblock = history.block({ + blockerFn, + enableBeforeUnload: false, + }) + + await history.push('/a') + + // Navigation should be blocked + expect(history.location.pathname).toBe('/') + expect(blockerFn).toHaveBeenCalled() + + unblock() + }) + + test('block allows navigation when blockerFn returns false', async () => { + const history = createMemoryHistory({ initialEntries: ['/'] }) + const blockerFn = vi.fn(() => false) // Never block + + const unblock = history.block({ + blockerFn, + enableBeforeUnload: false, + }) + + await history.push('/a') + + // Navigation should proceed + expect(history.location.pathname).toBe('/a') + expect(blockerFn).toHaveBeenCalled() + + unblock() + }) + + test('unblock removes blocker', async () => { + const history = createMemoryHistory({ initialEntries: ['/'] }) + const blockerFn = vi.fn(() => true) // Always block + + const unblock = history.block({ + blockerFn, + enableBeforeUnload: false, + }) + + // Unblock immediately + unblock() + + await history.push('/a') + + // Navigation should proceed since blocker was removed + expect(history.location.pathname).toBe('/a') + expect(blockerFn).not.toHaveBeenCalled() + }) })