import { createWebHashHistory } from '../../src/history/hash'
import { createWebHistory } from '../../src/history/html5'
import { createDom } from '../utils'
+import { mockWarn } from 'jest-mock-warn'
jest.mock('../../src/history/html5')
// override the value of isBrowser because the variable is created before JSDOM
beforeAll(() => {
dom = createDom()
})
+ mockWarn()
beforeEach(() => {
;(createWebHistory as jest.Mock).mockClear()
expect(createWebHistory).toHaveBeenCalledWith('/#')
})
- it('does not append a # if the user provides one', () => {
+ it('warns if there is anything but a slash after the # in a provided base', () => {
+ createWebHashHistory('/#/')
+ createWebHashHistory('/#')
+ createWebHashHistory('/base/#')
+ expect('').not.toHaveBeenWarned()
createWebHashHistory('/#/app')
- expect(createWebHistory).toHaveBeenCalledWith('/#/app')
+ expect('should be "/#"').toHaveBeenWarned()
})
it('should be able to provide a base', () => {
.end()
},
+ /** @type {import('nightwatch').NightwatchTest} */
+ 'initial navigation with search': function (browser) {
+ browser
+ .url('http://localhost:8080/hash/?code=auth#')
+ .waitForElementPresent('#app > *', 1000)
+ .assert.urlEquals('http://localhost:8080/hash/?code=auth#/')
+
+ .url('http://localhost:8080/hash/?code=auth#/foo')
+ .assert.urlEquals('http://localhost:8080/hash/?code=auth#/foo')
+ // manually remove the search from the URL
+ .waitForElementPresent('#app > *', 1000)
+ .execute(function () {
+ window.history.replaceState(history.state, '', '/hash/#/foo')
+ })
+ .click('li:nth-child(3) a')
+ .assert.urlEquals(baseURL + '/bar')
+ .back()
+ .assert.urlEquals(baseURL + '/foo')
+
+ // with slash between the pathname and search
+ .url('http://localhost:8080/hash/?code=auth#')
+ .waitForElementPresent('#app > *', 1000)
+ .assert.urlEquals('http://localhost:8080/hash/?code=auth#/')
+
+ .end()
+ },
+
/** @type {import('nightwatch').NightwatchTest} */
'encoding on initial navigation': function (browser) {
browser
function useHistoryListeners(
base: string,
historyState: ValueContainer<StateEntry>,
- location: ValueContainer<HistoryLocation>,
+ currentLocation: ValueContainer<HistoryLocation>,
replace: RouterHistory['replace']
) {
let listeners: NavigationCallback[] = []
}: {
state: StateEntry | null
}) => {
- const to = createCurrentLocation(base, window.location)
- const from: HistoryLocation = location.value
+ const to = createCurrentLocation(base, location)
+ const from: HistoryLocation = currentLocation.value
const fromState: StateEntry = historyState.value
let delta = 0
if (state) {
- location.value = to
+ currentLocation.value = to
historyState.value = state
// ignore the popstate and reset the pauseState
// need to be passed to the listeners so the navigation can be accepted
// call all listeners
listeners.forEach(listener => {
- listener(location.value, from, {
+ listener(currentLocation.value, from, {
delta,
type: NavigationType.pop,
direction: delta
}
function pauseListeners() {
- pauseState = location.value
+ pauseState = currentLocation.value
}
function listen(callback: NavigationCallback) {
}
function useHistoryStateNavigation(base: string) {
- const { history } = window
+ const { history, location } = window
// private variables
- let location: ValueContainer<HistoryLocation> = {
- value: createCurrentLocation(base, window.location),
+ let currentLocation: ValueContainer<HistoryLocation> = {
+ value: createCurrentLocation(base, location),
}
let historyState: ValueContainer<StateEntry> = { value: history.state }
// build current history entry as this is a fresh navigation
if (!historyState.value) {
changeLocation(
- location.value,
+ currentLocation.value,
{
back: null,
- current: location.value,
+ current: currentLocation.value,
forward: null,
// the length is off by one, we need to decrease it
position: history.length - 1,
state: StateEntry,
replace: boolean
): void {
- const url = createBaseLocation() + base + to
+ const url =
+ createBaseLocation() +
+ // preserve any existing query when base has a hash
+ (base.indexOf('#') > -1 && location.search
+ ? location.pathname + location.search + '#'
+ : base) +
+ to
try {
// BROWSER QUIRK
// NOTE: Safari throws a SecurityError when calling this function 100 times in 30 seconds
} catch (err) {
warn('Error with push/replace State', err)
// Force the navigation, this also resets the call count
- window.location[replace ? 'replace' : 'assign'](url)
+ location[replace ? 'replace' : 'assign'](url)
}
}
)
changeLocation(to, state, true)
- location.value = to
+ currentLocation.value = to
}
function push(to: HistoryLocation, data?: HistoryState) {
const state: StateEntry = assign(
{},
- buildState(location.value, to, null),
+ buildState(currentLocation.value, to, null),
{
position: currentState.position + 1,
},
)
changeLocation(to, state, false)
- location.value = to
+ currentLocation.value = to
}
return {
- location,
+ location: currentLocation,
state: historyState,
push,